[BACK]Return to backupfile.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / patch

Annotation of src/usr.bin/patch/backupfile.c, Revision 1.1.1.1

1.1       deraadt     1: /* backupfile.c -- make Emacs style backup file names
                      2:    Copyright (C) 1990 Free Software Foundation, Inc.
                      3:
                      4:    This program is free software; you can redistribute it and/or modify
                      5:    it without restriction.
                      6:
                      7:    This program is distributed in the hope that it will be useful,
                      8:    but WITHOUT ANY WARRANTY; without even the implied warranty of
                      9:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  */
                     10:
                     11: /* David MacKenzie <djm@ai.mit.edu>.
                     12:    Some algorithms adapted from GNU Emacs. */
                     13:
                     14: #ifndef lint
                     15: static char rcsid[] = "$Id: backupfile.c,v 1.3 1994/12/24 17:30:13 cgd Exp $";
                     16: #endif /* not lint */
                     17:
                     18: #include <stdio.h>
                     19: #include <stdlib.h>
                     20: #include <string.h>
                     21: #include <ctype.h>
                     22: #include <sys/types.h>
                     23: #include "backupfile.h"
                     24: #include "config.h"
                     25:
                     26: #ifdef DIRENT
                     27: #include <dirent.h>
                     28: #ifdef direct
                     29: #undef direct
                     30: #endif
                     31: #define direct dirent
                     32: #define NLENGTH(direct) (strlen((direct)->d_name))
                     33: #else /* !DIRENT */
                     34: #define NLENGTH(direct) ((direct)->d_namlen)
                     35: #ifdef USG
                     36: #ifdef SYSNDIR
                     37: #include <sys/ndir.h>
                     38: #else /* !SYSNDIR */
                     39: #include <ndir.h>
                     40: #endif /* !SYSNDIR */
                     41: #else /* !USG */
                     42: #ifdef SYSDIR
                     43: #include <sys/dir.h>
                     44: #endif /* SYSDIR */
                     45: #endif /* !USG */
                     46: #endif /* !DIRENT */
                     47:
                     48: #ifndef isascii
                     49: #define ISDIGIT(c) (isdigit ((unsigned char) (c)))
                     50: #else
                     51: #define ISDIGIT(c) (isascii (c) && isdigit (c))
                     52: #endif
                     53:
                     54: #if defined (HAVE_UNISTD_H)
                     55: #include <unistd.h>
                     56: #endif
                     57:
                     58: #if defined (_POSIX_VERSION)
                     59: /* POSIX does not require that the d_ino field be present, and some
                     60:    systems do not provide it. */
                     61: #define REAL_DIR_ENTRY(dp) 1
                     62: #else
                     63: #define REAL_DIR_ENTRY(dp) ((dp)->d_ino != 0)
                     64: #endif
                     65:
                     66: /* Which type of backup file names are generated. */
                     67: enum backup_type backup_type = none;
                     68:
                     69: /* The extension added to file names to produce a simple (as opposed
                     70:    to numbered) backup file name. */
                     71: char *simple_backup_suffix = "~";
                     72:
                     73: char *basename ();
                     74: char *dirname ();
                     75: static char *concat ();
                     76: char *find_backup_file_name ();
                     77: static char *make_version_name ();
                     78: static int max_backup_version ();
                     79: static int version_number ();
                     80:
                     81: #ifndef NODIR
                     82: /* Return the name of the new backup file for file FILE,
                     83:    allocated with malloc.  Return 0 if out of memory.
                     84:    FILE must not end with a '/' unless it is the root directory.
                     85:    Do not call this function if backup_type == none. */
                     86:
                     87: char *
                     88: find_backup_file_name (file)
                     89:      char *file;
                     90: {
                     91:   char *dir;
                     92:   char *base_versions;
                     93:   int highest_backup;
                     94:
                     95:   if (backup_type == simple)
                     96:     return concat (file, simple_backup_suffix);
                     97:   base_versions = concat (basename (file), ".~");
                     98:   if (base_versions == 0)
                     99:     return 0;
                    100:   dir = dirname (file);
                    101:   if (dir == 0)
                    102:     {
                    103:       free (base_versions);
                    104:       return 0;
                    105:     }
                    106:   highest_backup = max_backup_version (base_versions, dir);
                    107:   free (base_versions);
                    108:   free (dir);
                    109:   if (backup_type == numbered_existing && highest_backup == 0)
                    110:     return concat (file, simple_backup_suffix);
                    111:   return make_version_name (file, highest_backup + 1);
                    112: }
                    113:
                    114: /* Return the number of the highest-numbered backup file for file
                    115:    FILE in directory DIR.  If there are no numbered backups
                    116:    of FILE in DIR, or an error occurs reading DIR, return 0.
                    117:    FILE should already have ".~" appended to it. */
                    118:
                    119: static int
                    120: max_backup_version (file, dir)
                    121:      char *file, *dir;
                    122: {
                    123:   DIR *dirp;
                    124:   struct direct *dp;
                    125:   int highest_version;
                    126:   int this_version;
                    127:   int file_name_length;
                    128:
                    129:   dirp = opendir (dir);
                    130:   if (!dirp)
                    131:     return 0;
                    132:
                    133:   highest_version = 0;
                    134:   file_name_length = strlen (file);
                    135:
                    136:   while ((dp = readdir (dirp)) != 0)
                    137:     {
                    138:       if (!REAL_DIR_ENTRY (dp) || NLENGTH (dp) <= file_name_length)
                    139:        continue;
                    140:
                    141:       this_version = version_number (file, dp->d_name, file_name_length);
                    142:       if (this_version > highest_version)
                    143:        highest_version = this_version;
                    144:     }
                    145:   closedir (dirp);
                    146:   return highest_version;
                    147: }
                    148:
                    149: /* Return a string, allocated with malloc, containing
                    150:    "FILE.~VERSION~".  Return 0 if out of memory. */
                    151:
                    152: static char *
                    153: make_version_name (file, version)
                    154:      char *file;
                    155:      int version;
                    156: {
                    157:   char *backup_name;
                    158:
                    159:   backup_name = malloc (strlen (file) + 16);
                    160:   if (backup_name == 0)
                    161:     return 0;
                    162:   sprintf (backup_name, "%s.~%d~", file, version);
                    163:   return backup_name;
                    164: }
                    165:
                    166: /* If BACKUP is a numbered backup of BASE, return its version number;
                    167:    otherwise return 0.  BASE_LENGTH is the length of BASE.
                    168:    BASE should already have ".~" appended to it. */
                    169:
                    170: static int
                    171: version_number (base, backup, base_length)
                    172:      char *base;
                    173:      char *backup;
                    174:      int base_length;
                    175: {
                    176:   int version;
                    177:   char *p;
                    178:
                    179:   version = 0;
                    180:   if (!strncmp (base, backup, base_length) && ISDIGIT (backup[base_length]))
                    181:     {
                    182:       for (p = &backup[base_length]; ISDIGIT (*p); ++p)
                    183:        version = version * 10 + *p - '0';
                    184:       if (p[0] != '~' || p[1])
                    185:        version = 0;
                    186:     }
                    187:   return version;
                    188: }
                    189:
                    190: /* Return the newly-allocated concatenation of STR1 and STR2.
                    191:    If out of memory, return 0. */
                    192:
                    193: static char *
                    194: concat (str1, str2)
                    195:      char *str1, *str2;
                    196: {
                    197:   char *newstr;
                    198:   char str1_length = strlen (str1);
                    199:
                    200:   newstr = malloc (str1_length + strlen (str2) + 1);
                    201:   if (newstr == 0)
                    202:     return 0;
                    203:   strcpy (newstr, str1);
                    204:   strcpy (newstr + str1_length, str2);
                    205:   return newstr;
                    206: }
                    207:
                    208: /* Return NAME with any leading path stripped off.  */
                    209:
                    210: char *
                    211: basename (name)
                    212:      char *name;
                    213: {
                    214:   char *base;
                    215:
                    216:   base = rindex (name, '/');
                    217:   return base ? base + 1 : name;
                    218: }
                    219:
                    220: /* Return the leading directories part of PATH,
                    221:    allocated with malloc.  If out of memory, return 0.
                    222:    Assumes that trailing slashes have already been
                    223:    removed.  */
                    224:
                    225: char *
                    226: dirname (path)
                    227:      char *path;
                    228: {
                    229:   char *newpath;
                    230:   char *slash;
                    231:   int length;    /* Length of result, not including NUL. */
                    232:
                    233:   slash = rindex (path, '/');
                    234:   if (slash == 0)
                    235:        {
                    236:          /* File is in the current directory.  */
                    237:          path = ".";
                    238:          length = 1;
                    239:        }
                    240:   else
                    241:        {
                    242:          /* Remove any trailing slashes from result. */
                    243:          while (slash > path && *slash == '/')
                    244:                --slash;
                    245:
                    246:          length = slash - path + 1;
                    247:        }
                    248:   newpath = malloc (length + 1);
                    249:   if (newpath == 0)
                    250:     return 0;
                    251:   strncpy (newpath, path, length);
                    252:   newpath[length] = 0;
                    253:   return newpath;
                    254: }
                    255:
                    256: /* If ARG is an unambiguous match for an element of the
                    257:    null-terminated array OPTLIST, return the index in OPTLIST
                    258:    of the matched element, else -1 if it does not match any element
                    259:    or -2 if it is ambiguous (is a prefix of more than one element). */
                    260:
                    261: int
                    262: argmatch (arg, optlist)
                    263:      char *arg;
                    264:      char **optlist;
                    265: {
                    266:   int i;                       /* Temporary index in OPTLIST. */
                    267:   int arglen;                  /* Length of ARG. */
                    268:   int matchind = -1;           /* Index of first nonexact match. */
                    269:   int ambiguous = 0;           /* If nonzero, multiple nonexact match(es). */
                    270:
                    271:   arglen = strlen (arg);
                    272:
                    273:   /* Test all elements for either exact match or abbreviated matches.  */
                    274:   for (i = 0; optlist[i]; i++)
                    275:     {
                    276:       if (!strncmp (optlist[i], arg, arglen))
                    277:        {
                    278:          if (strlen (optlist[i]) == arglen)
                    279:            /* Exact match found.  */
                    280:            return i;
                    281:          else if (matchind == -1)
                    282:            /* First nonexact match found.  */
                    283:            matchind = i;
                    284:          else
                    285:            /* Second nonexact match found.  */
                    286:            ambiguous = 1;
                    287:        }
                    288:     }
                    289:   if (ambiguous)
                    290:     return -2;
                    291:   else
                    292:     return matchind;
                    293: }
                    294:
                    295: /* Error reporting for argmatch.
                    296:    KIND is a description of the type of entity that was being matched.
                    297:    VALUE is the invalid value that was given.
                    298:    PROBLEM is the return value from argmatch. */
                    299:
                    300: void
                    301: invalid_arg (kind, value, problem)
                    302:      char *kind;
                    303:      char *value;
                    304:      int problem;
                    305: {
                    306:   fprintf (stderr, "patch: ");
                    307:   if (problem == -1)
                    308:     fprintf (stderr, "invalid");
                    309:   else                         /* Assume -2. */
                    310:     fprintf (stderr, "ambiguous");
                    311:   fprintf (stderr, " %s `%s'\n", kind, value);
                    312: }
                    313:
                    314: static char *backup_args[] =
                    315: {
                    316:   "never", "simple", "nil", "existing", "t", "numbered", 0
                    317: };
                    318:
                    319: static enum backup_type backup_types[] =
                    320: {
                    321:   simple, simple, numbered_existing, numbered_existing, numbered, numbered
                    322: };
                    323:
                    324: /* Return the type of backup indicated by VERSION.
                    325:    Unique abbreviations are accepted. */
                    326:
                    327: enum backup_type
                    328: get_version (version)
                    329:      char *version;
                    330: {
                    331:   int i;
                    332:
                    333:   if (version == 0 || *version == 0)
                    334:     return numbered_existing;
                    335:   i = argmatch (version, backup_args);
                    336:   if (i >= 0)
                    337:     return backup_types[i];
                    338:   invalid_arg ("version control type", version, i);
                    339:   exit (1);
                    340: }
                    341: #endif /* NODIR */