sources-request@mirror.UUCP (02/20/87)
Submitted by: simon2 <simon2@its63b.ed.ac.uk> Mod.sources: Volume 8, Issue 74 Archive-name: shrink_names [ Blame me for the Makefile. --r$ ] Here is a very useful program for changing filenames from BSD filename form to a more portable form (14 char limit). It is reasonably intelligent as to what the structure of the original filename was, and tries quite hard to maintain this underlying structure by just shortening the subfields. Simon Brown Department of Computer Science, University of Edinburgh, Scotland. ...!{ihnp4,seismo,decvax}!mcvax!ukc!cstvax(!its63b?)!simon ------------------------- CUT HERE ------------------------------- #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # shrink.1 # shrink.c # Makefile export PATH; PATH=/bin:/usr/bin:$PATH echo shar: "extracting 'shrink.1'" '(2814 characters)' if test -f 'shrink.1' then echo shar: "will not over-write existing file 'shrink.1'" else cat << \SHAR_EOF > 'shrink.1' .TH SHRINK 1 "Edinburgh University" "December 1986" .SH NAME shrink \- generate short filenames from extended ones .SH SYNOPSIS .B shrink [ -vnSm ] [ -s\fIseparators\fR ] [ -\fIn\fR ] \fIfilename\fR ... .SH DESCRIPTION .I Shrink converts a filename to a shrunken form, suitable for transportation to another system with less generous filename length limits. It takes each .I filename given, and applies certain rules to shorten it, if necessary. In particular, it tries to leave suffixes unchanged, and, to a less extent, to keep the initial component as close to the original as possible. Of course, very long suffixes do have to be truncated. .PP The following options are recognized: .TP .B -v Verbose mode. Normally .I shrink does its work silently, but under the verbose option it chats about what decisions its making. .TP .B -n Normally the new filename is generated so as to not clash with an existing file, to prevent several long-named files folding into the same shortened form. This behaviour can be revoked by use of the .B -n option. .TP .B -s Normally the new filename is printed on the standard output. The .B -s option causes .I shrink to be silent. This is useful only in conjunction with the .B -m option. .TP .B -m This causes the files to be physically renamed; normally, just the ``suggested'' change is printed but nothing actually done. .TP .B "-s \fIseparators\fB" This can be used to change the set of .I separators that .I shrink recognizes. These are the characters that are used to delimit filename components. .I Shrink operates by shrinking characters out of each component (though it is loath to modify the first or last components unless it has no choice), while leaving the delimiters unchanged. However, if a filename contains a vast number of delimiter characters (such as .I this_file_contains_quite_a_lot_of_stuff_and_useful_stuff_at_that ), then some components (and their associated delimiters) will have to be deleted totally. The default delimiter set is .BR + , .BR - , .BR . , .BR _ , .BR ~ and .BR , . .TP .B "-\fIn\fB" A numerical flag \fIn\fR may be given to specify a maximum length that the resultant filename is allowed to be. The default is 14 (which is the maximum file length under all unix systems without the Berkeley modified filesystem). .SH DIAGNOSTICS Under the .B -v option, lots of diagnostics can be produced. Those preceded by the word .B "``warning:''" can probably be ignored. .PP Under certain circumstances, .I shrink may refuse totally to deal with some filenames, though this is not very likely to occur unless a very small maximum length flag is specified. .SH BUGS If the file begins with a delimiter character, then .I shrink sometimes causes the shortened filename to be shorter than it need be. This is not too serious a bug. .SH AUTHOR Simon Brown. SHAR_EOF fi echo shar: "extracting 'shrink.c'" '(6420 characters)' if test -f 'shrink.c' then echo shar: "will not over-write existing file 'shrink.c'" else cat << \SHAR_EOF > 'shrink.c' /* * Rename a file so's it will be unique under systems without * extended filename size. * The new name is written on the stardard output. * * Example: * To copy lots of files from a 4.?BSD system to a * SystemV, SystemIII, 2.?BSD or V7 system, without * having to worry about overlapping filenames * (eg, so "what_a_long_filename.c" and "what_a_long_filename.h" * don't get squished), just do * for i in * * do * j=`shrink -m $i` * uucp $j othersys!/stuff/$j (or rcp, hhcp, ...) * done * * Bug: It gets overenthusiastic and deletes characters * unnecessarily if the filename begins with a "." * * Author: * Simon Brown * Department of Computer Science, University of Edinburgh. */ #include <stdio.h> /* * maximum no. of "segments" allowed in a file */ #define MAXSEGS 10 /* * silly names for strchr/strrchr under non-usg unices */ #ifndef sysV #define strchr index #define strrchr rindex #endif sysV char *getsegment(); char *strchr(), *strrchr(); struct segment { char seg_string[63]; char seg_sep; } seg[MAXSEGS]; char defaults[] = "._+-,@~="; char usagemsg[] = "Usage: %s [-<maxlength>] [-mnSv] [-s<separators>] filename ...\n"; int max = 14; /* target length */ int nocheck = 0; /* don't check for existance (-n flag) */ int chatty = 0; /* talk a lot (-v flag) */ int silent = 0; /* don't say anything (-s flag) */ int move = 0; /* rename file (-m flag) */ char *file, *prefix; int modified = 0; char realname[512]; char *separators = defaults; main(argc,argv) char **argv; { register int i, j; int nsegs, suflen, remainder, delete; int total; int zap = 0; register char *op; char *progname = argv[0]; if (argv[1] == (char *)0){ fprintf(stderr, usagemsg, progname); exit(1); } while (*++argv) /* process command-line options... */ if (**argv=='-') while (*++*argv) switch(**argv){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': /* change target length */ max = atoi(*argv); if (max<=0){ fprintf(stderr,"%s: illegal length %s\n", argv[0], argv[1]); exit(1); } while (*++*argv); --*argv; break; case 's': /* change separator definition */ separators = ++*argv; while (*++*argv); --*argv; break; case 'n': /* don't create a uniquely named file */ nocheck=1; break; case 'v': /* talk a lot */ chatty=1; break; case 'm': /* move files */ move=1; break; case'S': /* silent */ silent=1; break; default: fprintf(stderr,usagemsg,progname); exit(1); } else break; while (*argv){ strcpy(realname, *argv); if (prefix=strrchr(*argv,'/')){ /* dir/.../file */ file=prefix+1; *prefix = '\0'; prefix = *argv; } else file = *argv; argv++; op=file; modified=0; /* split into logical parts */ for (i=0; i<MAXSEGS && (op=getsegment(op,i)); i++); if (i==MAXSEGS){ fprintf(stderr,"%s: too many segments\n", file); continue; } nsegs = i-1; if ((nsegs*2) >= max){ fprintf(stderr,"%s: too many segments\n", file); continue; } suflen = strlen(seg[nsegs].seg_string); if (suflen>max-nsegs-1){ if (chatty) fprintf(stderr,"warning: %s: suffix truncated\n", file); suflen = max-(2*nsegs)-1; seg[nsegs].seg_string[suflen-1] = '\0'; modified=1; } else if (suflen+nsegs > max-nsegs-1){ zap = nsegs - (max-suflen)/2; if (chatty && zap) fprintf(stderr,"warning: %s: %d segments removed\n", file, zap); } if (nsegs>=1){ /* complicated filename */ for (i=zap+1; i<=nsegs; i++) if (seg[i].seg_sep) suflen++; if (seg[0].seg_sep) suflen++; remainder = max - suflen; delete = remainder/nsegs; total = suflen; for (i=zap+1; i<nsegs; i++){ if (strlen(seg[i].seg_string) > delete) modified=1; seg[i].seg_string[delete] = '\0'; total += delete; } if (strlen(seg[0].seg_string) > max-total) modified=1; seg[0].seg_string[max-total] = '\0'; } unique(zap,nsegs,modified); } } /* * get a segment from a filename. * returns pointer to remainder of filename, or 0 at end of filename */ char * getsegment(cp,i) char *cp; { register char *xp = seg[i].seg_string; while (*cp && strchr(separators,*cp)==0) *xp++ = *cp++; *xp = '\0'; seg[i].seg_sep = *cp; if (*cp) cp++; if (seg[i].seg_string[0] || seg[i].seg_sep) return(cp); else return((char *)0); } /* * print out the current filename in a unique form */ unique(zap,n,mod) { register int i, j; int jmax[MAXSEGS]; int xstart, xstop; if (ok(zap,zap||mod)) return; xstart = (n==0)? 0 : 1; xstop = (n==0)? 1 : n; more: if (xstop <= xstart){ xstart=0; xstop = n+1; } for (i=xstart; i<xstop; i++) jmax[i] = strlen(seg[i].seg_string); for (j=0; j<5; j++){ for (i=xstart; i<xstop; i++){ if (j >= jmax[i]) continue; increment(seg[i].seg_string,j); if (ok(zap,1)) return; } } if (xstart>0 || xstop<n+1){ /* Desparation time: try _any_ segment! */ xstop = -1; goto more; } fprintf(stderr,"Can't generate unique name for %s\n", file); } /* * modify a character in a string (stupid algorithm) */ increment(str,ind) char *str; { char ch = str[ind]; if (ch>='a' && ch<='z') ch += ('A'-'a'); else if (ch>='A' && ch<='Z') ch += ('a'-'A'); str[ind] = ch; } /* * see if a filename is reasonable, and if so print it out * and return 1. * otherwise return 0. */ ok(zap,changed) { char buffer[512]; register char *cp = buffer; register char *xp; register int i; if (prefix){ for (xp=prefix; *xp; ) *cp++ = *xp++; *cp++ = '/'; } for (xp=seg[0].seg_string; *xp; ) /* copy initial segment */ *cp++ = *xp++; if (seg[0].seg_sep){ *cp++ = seg[0].seg_sep; for (i=zap+1; ; i++){ /* copy rest of segments */ for (xp=seg[i].seg_string; *xp; ) *cp++ = *xp++; if (seg[i].seg_sep) *cp++ = seg[i].seg_sep; else if (seg[i].seg_string[0] == '\0') break; } } *cp = '\0'; if (changed && nocheck==0 && access(buffer,0)==0){ if (chatty) fprintf(stderr,"warning: %s already exists - trying again\n",buffer); return(0); } else { if (silent==0) printf("%s\n", buffer); if (move && strcmp(realname,buffer)){ if (link(realname,buffer)==-1 || unlink(realname)==-1) fprintf(stderr,"%s: link/unlink failure\n", realname); } return(1); } } SHAR_EOF fi if test -f 'Makefile' then echo shar: "will not over-write existing file 'Makefile'" else cat << \SHAR_EOF > 'Makefile' CFLAGS=-O shrink: shrink.c $(CC) $(CFLAGS) -o shrink shrink.c install: shrink @echo copy shrink.1 and shrink to appropriate directories SHAR_EOF fi exit 0 # End of shell archive --