home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume8 / shrink_names / shrink.c < prev   
Encoding:
C/C++ Source or Header  |  1987-02-18  |  6.3 KB  |  278 lines

  1. /*
  2.  *    Rename a file so's it will be unique under systems without
  3.  *    extended filename size.
  4.  *    The new name is written on the stardard output.
  5.  *
  6.  *    Example:
  7.  *        To copy lots of files from a 4.?BSD system to a
  8.  *        SystemV, SystemIII, 2.?BSD or V7 system, without
  9.  *        having to worry about overlapping filenames
  10.  *        (eg, so "what_a_long_filename.c" and "what_a_long_filename.h"
  11.  *        don't get squished), just do
  12.  *            for i in *
  13.  *            do
  14.  *                j=`shrink -m $i`
  15.  *                uucp $j othersys!/stuff/$j  (or rcp, hhcp, ...)
  16.  *            done
  17.  *
  18.  *    Bug:    It gets overenthusiastic and deletes characters
  19.  *            unnecessarily if the filename begins with a "."
  20.  *
  21.  *    Author:
  22.  *        Simon Brown
  23.  *        Department of Computer Science, University of Edinburgh.
  24.  */
  25.  
  26. #include <stdio.h>
  27.  
  28. /*
  29.  *    maximum no. of "segments" allowed in a file 
  30.  */
  31. #define MAXSEGS 10
  32.  
  33. /*
  34.  *    silly names for strchr/strrchr under non-usg unices
  35.  */
  36. #ifndef sysV
  37. #define strchr    index
  38. #define strrchr    rindex
  39. #endif sysV
  40.  
  41. char *getsegment();
  42. char *strchr(), *strrchr();
  43.  
  44. struct segment {
  45.     char seg_string[63];
  46.     char seg_sep;
  47. } seg[MAXSEGS];
  48.  
  49. char defaults[] = "._+-,@~=";
  50. char usagemsg[] = "Usage: %s [-<maxlength>] [-mnSv] [-s<separators>] filename ...\n";
  51.  
  52. int max = 14;            /* target length */
  53. int nocheck = 0;        /* don't check for existance (-n flag) */
  54. int chatty = 0;            /* talk a lot (-v flag) */
  55. int silent = 0;            /* don't say anything (-s flag) */
  56. int move = 0;            /* rename file (-m flag) */
  57. char *file, *prefix;
  58. int modified = 0;
  59. char realname[512];
  60. char *separators = defaults;
  61.  
  62. main(argc,argv)
  63. char **argv;
  64. {
  65.     register int i, j;
  66.     int nsegs, suflen, remainder, delete;
  67.     int total;
  68.     int zap = 0;
  69.     register char *op;
  70.     char *progname = argv[0];
  71.  
  72.     if (argv[1] == (char *)0){
  73.         fprintf(stderr, usagemsg, progname);
  74.         exit(1);
  75.     }
  76.     while (*++argv)        /* process command-line options... */
  77.         if (**argv=='-')
  78.             while (*++*argv)
  79.                 switch(**argv){
  80.                    case '0': case '1': case '2':
  81.                    case '3': case '4': case '5':
  82.                    case '6': case '7': case '8':
  83.                    case '9':    /* change target length */
  84.                     max = atoi(*argv);
  85.                     if (max<=0){
  86.                         fprintf(stderr,"%s: illegal length %s\n", argv[0], argv[1]);
  87.                         exit(1);
  88.                     }
  89.                     while (*++*argv);
  90.                     --*argv;
  91.                     break;
  92.                    case 's':    /* change separator definition */
  93.                     separators = ++*argv;
  94.                     while (*++*argv);
  95.                     --*argv;
  96.                     break;
  97.                    case 'n':    /* don't create a uniquely named file */
  98.                     nocheck=1;
  99.                     break;
  100.                    case 'v':    /* talk a lot */
  101.                     chatty=1;
  102.                     break;
  103.                    case 'm':     /* move files */
  104.                     move=1;
  105.                     break;
  106.                    case'S':    /* silent */
  107.                     silent=1;
  108.                     break;
  109.                    default:
  110.                     fprintf(stderr,usagemsg,progname);
  111.                     exit(1);
  112.                 }
  113.         else break;
  114.     while (*argv){
  115.         strcpy(realname, *argv);
  116.         if (prefix=strrchr(*argv,'/')){        /* dir/.../file */
  117.             file=prefix+1;
  118.             *prefix = '\0';
  119.             prefix = *argv;
  120.         } else file = *argv;
  121.         argv++;
  122.         op=file;
  123.         modified=0;
  124.         /* split into logical parts */
  125.         for (i=0; i<MAXSEGS && (op=getsegment(op,i)); i++);
  126.         if (i==MAXSEGS){
  127.             fprintf(stderr,"%s: too many segments\n", file);
  128.             continue;
  129.         }
  130.         nsegs = i-1;
  131.         if ((nsegs*2) >= max){
  132.             fprintf(stderr,"%s: too many segments\n", file);
  133.             continue;
  134.         }
  135.         suflen = strlen(seg[nsegs].seg_string);
  136.         if (suflen>max-nsegs-1){
  137.             if (chatty)
  138.                 fprintf(stderr,"warning: %s: suffix truncated\n", file);
  139.             suflen = max-(2*nsegs)-1;
  140.             seg[nsegs].seg_string[suflen-1] = '\0';
  141.             modified=1;
  142.         } else if (suflen+nsegs > max-nsegs-1){
  143.             zap = nsegs - (max-suflen)/2;
  144.             if (chatty && zap)
  145.                 fprintf(stderr,"warning: %s: %d segments removed\n", file, zap);
  146.         }
  147.         if (nsegs>=1){        /* complicated filename */
  148.             for (i=zap+1; i<=nsegs; i++)
  149.                 if (seg[i].seg_sep) suflen++;
  150.             if (seg[0].seg_sep) suflen++;
  151.             remainder = max - suflen;
  152.             delete = remainder/nsegs;
  153.             total = suflen;
  154.             for (i=zap+1; i<nsegs; i++){
  155.                 if (strlen(seg[i].seg_string) > delete)
  156.                     modified=1;
  157.                 seg[i].seg_string[delete] = '\0';
  158.                 total += delete;
  159.             }
  160.             if (strlen(seg[0].seg_string) > max-total)
  161.                 modified=1;
  162.             seg[0].seg_string[max-total] = '\0';
  163.         }
  164.         unique(zap,nsegs,modified);
  165.     }
  166. }
  167.  
  168. /*
  169.  *    get a segment from a filename.
  170.  *    returns pointer to remainder of filename, or 0 at end of filename
  171.  */
  172. char *
  173. getsegment(cp,i)
  174. char *cp;
  175. {
  176.     register char *xp = seg[i].seg_string;
  177.     while (*cp && strchr(separators,*cp)==0)
  178.         *xp++ = *cp++;
  179.     *xp = '\0';
  180.     seg[i].seg_sep = *cp;
  181.     if (*cp) cp++;
  182.     if (seg[i].seg_string[0] || seg[i].seg_sep) return(cp);
  183.     else return((char *)0);
  184. }
  185.  
  186.     
  187. /*
  188.  *    print out the current filename in a unique form
  189.  */
  190. unique(zap,n,mod)
  191. {
  192.     register int i, j;
  193.     int jmax[MAXSEGS];
  194.     int xstart, xstop;
  195.  
  196.     if (ok(zap,zap||mod)) return;
  197.     xstart = (n==0)? 0 : 1;
  198.     xstop = (n==0)? 1 : n;
  199.     more:
  200.     if (xstop <= xstart){
  201.         xstart=0;
  202.         xstop = n+1;
  203.     }
  204.     for (i=xstart; i<xstop; i++)
  205.         jmax[i] = strlen(seg[i].seg_string);
  206.     for (j=0; j<5; j++){
  207.         for (i=xstart; i<xstop; i++){
  208.             if (j >= jmax[i]) continue;
  209.             increment(seg[i].seg_string,j);
  210.             if (ok(zap,1)) return;
  211.         }
  212.     }
  213.     if (xstart>0 || xstop<n+1){    /* Desparation time: try _any_ segment! */
  214.         xstop = -1;
  215.         goto more;
  216.     }
  217.     fprintf(stderr,"Can't generate unique name for %s\n", file);
  218. }
  219.  
  220. /*
  221.  *    modify a character in a string (stupid algorithm)
  222.  */
  223. increment(str,ind)
  224. char *str;
  225. {
  226.     char ch = str[ind];
  227.  
  228.     if (ch>='a' && ch<='z') ch += ('A'-'a');
  229.     else if (ch>='A' && ch<='Z') ch += ('a'-'A');
  230.     str[ind] = ch;
  231. }
  232.  
  233.  
  234. /*
  235.  *    see if a filename is reasonable, and if so print it out
  236.  *    and return 1.
  237.  *    otherwise return 0.
  238.  */
  239. ok(zap,changed)
  240. {
  241.     char buffer[512];
  242.     register char *cp = buffer;
  243.     register char *xp;
  244.     register int i;
  245.  
  246.     if (prefix){
  247.         for (xp=prefix; *xp; )
  248.             *cp++ = *xp++;
  249.         *cp++ = '/';
  250.     }
  251.     for (xp=seg[0].seg_string; *xp; )    /* copy initial segment */
  252.         *cp++ = *xp++;
  253.     if (seg[0].seg_sep){
  254.         *cp++ = seg[0].seg_sep;
  255.         for (i=zap+1; ; i++){        /* copy rest of segments */
  256.             for (xp=seg[i].seg_string; *xp; )
  257.                 *cp++ = *xp++;
  258.             if (seg[i].seg_sep) *cp++ = seg[i].seg_sep;
  259.             else if (seg[i].seg_string[0] == '\0') break;
  260.         }
  261.     }
  262.     *cp = '\0';
  263.     if (changed && nocheck==0 && access(buffer,0)==0){
  264.         if (chatty)
  265.             fprintf(stderr,"warning: %s already exists - trying again\n",buffer);
  266.         return(0);
  267.     } else {
  268.         if (silent==0) printf("%s\n", buffer);
  269.         if (move && strcmp(realname,buffer)){
  270.             if (link(realname,buffer)==-1 || unlink(realname)==-1)
  271.                 fprintf(stderr,"%s: link/unlink failure\n", realname);
  272.         }
  273.         return(1);
  274.     }
  275. }
  276.  
  277.  
  278.