[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     ! 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 */