home *** CD-ROM | disk | FTP | other *** search
- Path: xanth!mcnc!gatech!bloom-beacon!husc6!m2c!necntc!ncoast!allbery
- From: ksb@s.cc.purdue.edu (Kevin Braunsdorf)
- Newsgroups: comp.sources.misc
- Subject: v04i011: curly/uncurly: fold and unfold file names into csh {} form
- Message-ID: <8807310008.AA16489@s.cc.purdue.edu>
- Date: 31 Jul 88 00:08:08 GMT
- Sender: allbery@ncoast.UUCP
- Reply-To: ksb@s.cc.purdue.edu (Kevin Braunsdorf)
- Lines: 896
- Approved: allbery@ncoast.UUCP
-
- Posting-number: Volume 4, Issue 11
- Submitted-by: "Kevin Braunsdorf" <ksb@s.cc.purdue.edu>
- Archive-name: curly
-
- # This is a shell archive.
- # Remove everything above and including the cut line.
- # Then run the rest of the file through sh.
- #----cut here-----cut here-----cut here-----cut here----#
- #!/bin/sh
- # shar: Shell Archiver
- # Run the following text with /bin/sh to create:
- # README
- # curly.c
- # uncurly.c
- # This archive created: Sat Jul 30 18:57:01 1988
- # By: Kevin Braunsdorf (Purdue UNIX Group)
- sed 's/^K//' << \SHAR_EOF > README
- KHere are two programs I have found (recently) to be quite useful.
- KOne of them expands the C-Shell curly braces notation for file name
- Kbuilding, the other compresses a list of file names into one of
- Kthese expressions. I called these programs `curly' and `uncurly'.
- K
- KThere is am example usage of {un,}curly in the comments in the code,
- Kcopied below. I have used them to compress a dictionary (one initial
- Kletter at a time BTW), and to compress lists of files on tape.
- K
- KOne might pipe the output of a find to uncurly and compress to store
- Ka list of filenames as:
- K
- K $ find . -type f -print | uncurly | compress > /tmp/files.u.Z
- K
- Kthen (later on) we need that list of files again...
- K
- K $ zcat /tmp/files.u.Z | curly | xargs do_something
- K
- Kthis yields substantial compression over just compress alone, which it
- Kshouldn't. (We know something quite special about the output of find
- Kon a `normal' find output that gives us an advantage here.)
- K
- KI always name the output from uncurly as files.u. Here is some sample
- Kcompression data (for 567 handy filenames in my src directory):
- K
- K 15 -rw-r----- 1 ksb 14435 Jul 30 17:27 files # 100%
- K 5 -rw-r----- 1 ksb 4754 Jul 30 17:27 files.Z # 32.9%
- K 5 -rw-r----- 1 ksb 5074 Jul 30 17:26 files.u # 35.2%
- K 3 -rw-r----- 1 ksb 2810 Jul 30 17:27 files.u.Z # 17.3%
- K
- KI would like to be mailed any bug reports so I can fix my own copy.
- K
- KKnown bugs: doesn't handle files with `{' or `}' in them well.
- K
- KEnjoy.
- Kkayessbee (Kevin S Braunsdorf, ksb@j.cc.purdue.edu, pur-ee!ksb)
- SHAR_EOF
- sed 's/^K//' << \SHAR_EOF > curly.c
- K/*
- K * curly -- expand {...} as csh(1) (ksb)
- K *
- K * Copyright 1988, All Rights Reserved
- K * Kevin S Braunsdorf
- K * ksb@j.cc.purdue.edu, pur-ee!ksb
- K * Math/Sci Building, Purdue Univ
- K * West Lafayette, IN
- K *
- K * `You may redistibute this code as long as you don't claim to have
- K * written it. -- ksb'
- K *
- K * We are limited to not eating backslash escapes because that would be
- K * very confusing to the user. If you need a file name {a}.c don't call
- K * this routine. Simple. (If we did use \ as special, then \.c would
- K * need to be quoted from us... it never ends, so we let the shells worry
- K * about \ quoting for us.)
- K *
- K * We don't expand other globbing characters, because ksh will expand
- K * those for us when it reads our output in `quotes`.
- K *
- K * The command
- K * $ curly c{1,2,3,4,5}.c
- K * outputs
- K * c1.c c2.c c3.c c4.c c5.c
- K *
- K * So use you might use
- K * $ tar xv `curly c{1,2,3,4,5}.c`
- K * to extract them from tape.
- K *
- K * If we are given no arguments we can read stdin for strings to glob.
- K * The READSTDIN switch controls this feature.
- K *
- K * Improvments:
- K *
- K * This code could be mixed with other globbing code to fully emulate
- K * csh(1) globbing in a few minutes, I have no need of this (yet).
- K *
- K * We can avoid the malloc/strcpy/strcat in DoExpr if we build right
- K * context right to left in a large buffer; this buffer could limit the
- K * size of the glob expression, but other factors limit it already.
- K *
- K * $Compile: ${CC-cc} ${DEBUG--O} ${SYS--Dbsd} -DREADSTDIN %f -o %F
- K * $Compile: ${CC-cc} ${DEBUG--O} ${SYS--Dbsd} %f -o %F
- K * $Lint: lint -abhxp ${SYS--Dbsd} -DREADSTDIN %f
- K * $Lint: lint -abhxp ${SYS--Dbsd} %f
- K */
- K#include <stdio.h>
- K#include <sys/param.h>
- K#include <sys/types.h>
- K
- Kstatic char *progname =
- K "$Id: curly.c,v 2.0 88/07/30 17:10:38 ksb Exp $";
- K
- K/*
- K * If your compiler doesn't allow `register' as a parameter storage class
- K * define PREG as empty, and don't worry about it.
- K */
- K#define PREG register /* make arguments faster access */
- K/* #define PREG /* no register arguments */
- K
- K#if defined(bsd)
- K#define strrchr rindex /* I must be on bsd, us rindex */
- K#endif
- K
- K#if !defined(MAXPATHLEN)
- K#define MAXPATHLEN 1024
- K#endif
- K
- Kextern char *malloc(), *realloc(), *strcpy();
- K
- K/* static int iMatch = 0; */
- Kstatic char acName[MAXPATHLEN];
- Kextern void DoExpr(), DoList();
- K
- K#if defined(READSTDIN)
- K#define FIRST_GUESS 8 /* be get on MAXPATHLEN * this */
- K#define NEXT_GUESS 2 /* we hedge with MAXPATHLEN * this */
- K#define GRAB 2 /* size chunk to read (<= NEXT_GUESS) */
- K
- Kstatic char acNoMem[] = "%s: out of memory\n";
- K
- K/*
- K * Here we call gets() to read a glob expression to do. (ksb)
- K * Repeat until end of file.
- K */
- Kvoid
- KDoStdin(pcAccum)
- KPREG char *pcAccum;
- K{
- K extern char *strrchr();
- K auto char acLine[MAXPATHLEN*GRAB];
- K static char *pcLine = (char *)0;
- K static unsigned uBufLen = 0;
- K register unsigned uPos;
- K register char *pcNewLine;
- K
- K acLine[MAXPATHLEN*GRAB-1] = '\000';
- K if ((char *)0 == pcLine) {
- K uBufLen = MAXPATHLEN*FIRST_GUESS;
- K pcLine = malloc(uBufLen);
- K if ((char *)0 == pcLine) {
- K fprintf(stderr, acNoMem, progname);
- K exit(1);
- K }
- K }
- K uPos = 0;
- K while (NULL != fgets(acLine, MAXPATHLEN*GRAB-1, stdin)) {
- K pcNewLine = strrchr(acLine, '\n');
- K if (0 == uPos && (char *)0 != pcNewLine) {
- K *pcNewLine = '\000';
- K DoExpr(pcAccum, acLine, "\n");
- K continue;
- K }
- K if ((char *)0 != pcNewLine) {
- K *pcNewLine = '\000';
- K }
- K if (uPos + MAXPATHLEN*GRAB-1 > uBufLen) {
- K uBufLen += MAXPATHLEN*NEXT_GUESS;
- K pcLine = realloc(pcLine, uBufLen);
- K }
- K strcpy(pcLine+uPos, acLine);
- K if ((char *)0 == pcNewLine) { /* we got chars, no end yet */
- K uPos += MAXPATHLEN*GRAB-2;
- K continue;
- K }
- K /* we have a line */
- K DoExpr(pcAccum, pcLine, "\n");
- K uPos = 0;
- K }
- K}
- K#endif /* we can read stdin for a list of patterns */
- K
- K/*
- K * find a matching close char for the open we just ate, or (char *)0 (ksb)
- K * pc = FindMatch("test(a,b))+f(d)", '(', ')', 1);
- K * ^ pc points here
- K */
- Kchar *
- KFindMatch(pcBuf, cOpen, cClose, iLevel)
- Kchar *pcBuf;
- Kchar cOpen, cClose;
- Kint iLevel;
- K{
- K while ('\000' != *pcBuf) {
- K if (cClose == *pcBuf) {
- K --iLevel;
- K } else if (cOpen == *pcBuf) {
- K ++iLevel;
- K }
- K if (0 == iLevel)
- K return pcBuf;
- K ++pcBuf;
- K }
- K return (char *)0;
- K}
- K
- K/*
- K * if we can locate a curly expression in our expression if the form: (ksb)
- K * left { list } right
- K * 1) copy left side to pcAccum,
- K * 2) add right to our right context (malloc a new buffer if needed)
- K * 3) call DoList(pcAccum, list, right)
- K * or if we find no such curly expression
- K * 1) copy all nonspecial chars to pcAccum
- K * 2) recurse with DoExpr(pcAccum, pcRight, "")
- K */
- Kvoid
- KDoExpr(pcAccum, pcExpr, pcRight)
- KPREG char *pcAccum;
- Kchar *pcExpr, *pcRight;
- K{
- K extern void DoList();
- K extern char *malloc(), *strcat(), *strcpy();
- K register char *pcClose;
- K register char *pcComma;
- K register char *pcTemp;
- K register unsigned int uLen;
- K
- K while ('{' != *pcExpr && '\000' != *pcExpr) { /*}*/
- K *pcAccum++ = *pcExpr++;
- K }
- K
- K switch (*pcExpr) {
- K case '\000':
- K if (*pcRight == '\000') { /* no right context */
- K if (pcAccum != acName) {
- K *pcAccum = '\000';
- K fputs(acName, stdout);
- K /* ++iMatch; */
- K }
- K } else {
- K DoExpr(pcAccum, pcRight, "");
- K }
- K break;
- K case '{':
- K pcClose = FindMatch(pcExpr, '{', '}', 0);
- K /*
- K * if an open is unbalanced we ignore it.
- K */
- K if ((char *)0 == pcClose) {
- K *pcAccum++ = *pcExpr++;
- K DoExpr(pcAccum, pcExpr, pcRight);
- K break;
- K }
- K *pcClose++ = '\000';
- K pcComma = pcExpr+1;
- K
- K /*
- K * Now that the expr is cracked we can optimize if the
- K * additional right context is empty. If it is not we
- K * have to compute a new right context.
- K */
- K uLen = strlen(pcClose);
- K if (0 == uLen) {
- K DoList(pcAccum, pcComma, pcRight);
- K } else {
- K uLen += strlen(pcRight);
- K pcTemp = malloc(uLen+1);
- K (void) strcpy(pcTemp, pcClose);
- K (void) strcat(pcTemp, pcRight);
- K DoList(pcAccum, pcComma, pcTemp);
- K free(pcTemp);
- K }
- K *--pcClose = '}';
- K break;
- K }
- K}
- K
- K/*
- K * do a comma separated list of terms with known right context (ksb)
- K * 1) loop through exprs at this level
- K * 2) call DoExpr(pcAccum, SubExpr, Right)
- K */
- Kvoid
- KDoList(pcAccum, pcList, pcRight)
- KPREG char *pcAccum;
- Kchar *pcList, *pcRight;
- K{
- K extern void DoExpr();
- K register char *pcThis;
- K register int iLevel;
- K
- K iLevel = 0;
- K
- K for (pcThis = pcList; '\000' != *pcList; ++pcList) {
- K switch (*pcList) {
- K case '{':
- K ++iLevel;
- K break;
- K case '}':
- K --iLevel;
- K break;
- K default:
- K break;
- K case ',':
- K if (0 == iLevel) {
- K *pcList = '\000';
- K DoExpr(pcAccum, pcThis, pcRight);
- K *pcList = ',';
- K pcThis = pcList+1;
- K }
- K break;
- K }
- K }
- K DoExpr(pcAccum, pcThis, pcRight);
- K}
- K
- K/*
- K * Special case "{}" as csh(1) does for find (YUCK!) (ksb)
- K * We take no options so that they won't conflict with anything.
- K * Count option exprs so we can output a blank line if we come up empty
- K * (I've forgotten why we do this...)
- K */
- Kint
- Kmain(argc, argv)
- Kint argc;
- Kchar **argv;
- K{
- K register char *pcPat;
- K
- K progname = *argv++;
- K --argc;
- K
- K#if defined(READSTDIN)
- K if (0 == argc) {
- K DoStdin(acName);
- K }
- K#endif
- K while (argc > 0) {
- K pcPat = *argv++;
- K --argc;
- K /*
- K * this kludge keeps us more csh(1) compatible
- K */
- K if ('{' == pcPat[0] && '}' == pcPat[1] && '\000' == pcPat[2]) {
- K fputs("{}\n", stdout);
- K /* ++iMatch; */
- K continue;
- K }
- K DoExpr(acName, pcPat, "\n");
- K }
- K
- K exit(0);
- K}
- SHAR_EOF
- sed 's/^K//' << \SHAR_EOF > uncurly.c
- K/*
- K * unculry -- uncurly expand a list of parameters (ksb)
- K *
- K * Copyright 1988, All Rights Reserved
- K * Kevin S Braunsdorf
- K * ksb@j.cc.purdue.edu, pur-ee!ksb
- K * Math/Sci Building, Purdue Univ
- K * West Lafayette, IN
- K *
- K * `You may redistibute this code as long as you don't claim to have
- K * written it. -- ksb'
- K *
- K * The command
- K * $ uncurly c1.c c2.c c3.c c4.c c5.c
- K * outputs
- K * c{1,2,3,4,5}.c
- K *
- K * So one might pipe the ouptut of a find to uncurly to compress the filenames
- K * like:
- K * $ find . -type f -print | uncurly | compress > /tmp/${USER}files.Z
- K * # later on we need the list again...
- K * $ zcat /tmp/${USER}files.Z | curly | xargs do_something
- K *
- K * Improvments:
- K *
- K * This code could be mixed with other globbing code to fully emulate
- K * an `arcglob' function, however this assumes the files exist in there
- K * present form and is therefore less useful (to me).
- K *
- K * We could free more memory, if we were more carefull with our bookkeeping.
- K *
- K * The READSTDIN flag could be stired with the code for main to get something
- K * that allocate less memory before UnCulry was called, free'd it and went
- K * back to reading... if you run out of memory you can try it and send me
- K * a patch :-).
- K *
- K * $Compile: ${CC-cc} ${DEBUG--O} ${SYS--Dbsd} -DREADSTDIN %f -o %F
- K * $Compile: ${CC-cc} ${DEBUG--O} ${SYS--Dbsd} %f -o %F
- K * $Lint: lint -abhxp ${SYS--Dbsd} -DREADSTDIN %f
- K * $Lint: lint -abhxp ${SYS--Dbsd} %f
- K */
- K#include <stdio.h>
- K#include <sys/param.h>
- K#include <sys/types.h>
- K
- Kstatic char *progname =
- K "$Id: uncurly.c,v 2.0 88/07/30 17:10:50 ksb Exp $";
- K
- K/*
- K * If your compiler doesn't allow `register' as a parameter storage class
- K * define PREG as empty, and don't worry about it.
- K */
- K#define PREG register /* make arguments faster access */
- K/* #define PREG /* no register arguments */
- K
- K#if defined(bsd)
- K#define strrchr rindex /* I must be on bsd, us rindex */
- K#endif
- K
- K#if !defined(MAXPATHLEN)
- K#define MAXPATHLEN 1024
- K#endif
- K
- Kextern char *malloc(), *calloc(), *strrchr(), *strcat();
- Kstatic char acNoMem[] = "%s: out of memory\n";
- K
- K/*
- K * find a matching close char for the open we just ate, or (char *)0 (ksb)
- K * pc = FindMatch("test(a,b))+f(d)", '(', ')', 1);
- K * ^ pc points here
- K */
- Kchar *
- KFindMatch(pcBuf, cOpen, cClose, iLevel)
- KPREG char *pcBuf;
- Kchar cOpen, cClose;
- Kint iLevel;
- K{
- K while ('\000' != *pcBuf) {
- K if (cClose == *pcBuf) {
- K --iLevel;
- K } else if (cOpen == *pcBuf) {
- K ++iLevel;
- K }
- K if (0 == iLevel)
- K return pcBuf;
- K ++pcBuf;
- K }
- K return (char *)0;
- K}
- K
- K/*
- K * save a string in malloc space (ksb)
- K */
- Kchar *
- Kstrsave(pc)
- Kchar *pc;
- K{
- K extern char *strcpy();
- K extern int strlen();
- K register char *pcMem;
- K
- K pcMem = malloc((unsigned int) strlen(pc)+1);
- K if ((char *)0 == pcMem) {
- K fprintf(stderr, acNoMem, progname);
- K exit(1);
- K }
- K return strcpy(pcMem, pc);
- K}
- K
- K#if defined(READSTDIN)
- K#define FIRST_GUESS 8192 /* initial number of input files */
- K#define NEXT_GUESS 2048 /* add this many if too few */
- K
- K/*
- K * Joe wants us to turn a piped list of files into a big glob list (ksb)
- K * we return the number of files (he gave us) and a vector of them.
- K */
- Kunsigned int
- KGetFiles(pppcArgv)
- Kchar ***pppcArgv;
- K{
- K extern char *realloc();
- K register unsigned int uCount, uLeft;
- K register char **ppcVector;
- K auto char acFile[MAXPATHLEN];
- K
- K ppcVector = (char **) calloc(FIRST_GUESS, sizeof(char *));
- K uCount = 0;
- K uLeft = FIRST_GUESS;
- K while (NULL != gets(acFile)) {
- K if (0 == uLeft) {
- K uLeft = (uCount+NEXT_GUESS) * sizeof(char *);
- K ppcVector = (char **) realloc((char *)ppcVector, uLeft);
- K uLeft = NEXT_GUESS;
- K }
- K ppcVector[uCount] = strsave(acFile);
- K ++uCount;
- K --uLeft;
- K }
- K
- K *pppcArgv = ppcVector;
- K return uCount;
- K}
- K#endif /* find files from stdin */
- K
- K/*
- K * longest common prefix of more than one string (ksb)
- K * Note that the prefix must have balanced '{'..'}' in it.
- K */
- Kint
- KPrefix(n, ppcList, puiLen)
- Kunsigned int n;
- Kchar **ppcList;
- Kunsigned *puiLen;
- K{
- K register int cCmp, cCur, iBal;
- K auto unsigned int j, i, uArea, uLen, uSpan, uCurlen;
- K
- K *puiLen = 0;
- K
- K iBal = 0;
- K for (j = 0; j < n; ++j) {
- K if ('\000' == ppcList[j][0]) {
- K break;
- K }
- K }
- K
- K /* trivial case either first or second sring is empty
- K */
- K if (j < 2) {
- K return 0;
- K }
- K
- K uCurlen = uArea = uLen = uSpan = 0;
- K while ('\000' != (cCur = ppcList[0][uCurlen])) {
- K if ('{' == cCur)
- K ++iBal;
- K else if ('}' == cCur)
- K --iBal;
- K for (i = 1; i < j; ++i) {
- K cCmp = ppcList[i][uCurlen];
- K if ('\000' == cCmp || cCur != cCmp) {
- K j = i;
- K break;
- K }
- K }
- K ++uCurlen;
- K if (0 == iBal && uCurlen * j > uArea) {
- K uArea = uCurlen*j;
- K uLen = uCurlen;
- K uSpan = j;
- K }
- K }
- K *puiLen = uLen;
- K return uSpan;
- K}
- K
- K/*
- K * longest common suffix of more than one string (ksb)
- K * 1) find the ends of all the strings
- K * 2) back off until we find a non-match, but keep looking
- K * 3) return the one with most characters in it
- K * Note that the suffix must have balanced '{'..'}' in it.
- K */
- Kint
- KSuffix(n, ppcList, puiLen)
- Kunsigned int n;
- Kchar **ppcList;
- Kunsigned *puiLen;
- K{
- K register char **ppcLast, *pcTemp;
- K register unsigned int j, i, uCurlen;
- K auto unsigned uArea, uLen, uSpan, iStopAt;
- K auto int cCur, iBal;
- K
- K *puiLen = 0;
- K
- K ppcLast = (char **)calloc(n, sizeof(char *));
- K if ((char **)0 == ppcLast) {
- K fprintf(stderr, acNoMem, progname);
- K exit(1);
- K }
- K for (j = 0; j < n; ++j) {
- K ppcLast[j] = strrchr(ppcList[j], '\000');
- K if (ppcLast[j] == ppcList[j]) {
- K break;
- K }
- K }
- K
- K iBal = uCurlen = uArea = uLen = uSpan = 0;
- K while (ppcLast[0] != ppcList[0]) {
- K cCur = ppcLast[0][-1];
- K if ('{' == cCur)
- K ++iBal;
- K else if ('}' == cCur)
- K --iBal;
- K iStopAt = -1;
- K for (i = 0; i < j; ++i) {
- K pcTemp = --ppcLast[i];
- K if (cCur != pcTemp[0]) {
- K j = i;
- K break;
- K }
- K if (ppcList[i] == pcTemp && -1 == iStopAt) {
- K iStopAt = i;
- K }
- K }
- K ++uCurlen;
- K if (0 == iBal && uCurlen * j > uArea) {
- K uArea = uCurlen*j;
- K uLen = uCurlen;
- K uSpan = j;
- K }
- K if (-1 != iStopAt) {
- K j = iStopAt;
- K }
- K }
- K *puiLen = uLen;
- K free((char *)ppcLast);
- K return uSpan;
- K}
- K
- K/*
- K * determine context for a list ppcList[0..n-1] (ksb)
- K * left { ... } right
- K *
- K * If the longest common prefix will eat more character then
- K * we should use that, else try the longest common suffix.
- K * If both are 0 chars just return the list (0).
- K */
- Kunsigned int
- KSplit(n, ppcList, ppcLeft, ppcRight)
- Kunsigned int n;
- Kchar **ppcList, **ppcLeft, **ppcRight;
- K{
- K register unsigned int i, iLcs, iLcp;
- K register char *pcEnd;
- K auto unsigned int iLcsLen, iLcpLen;
- K auto int cKeep;
- K
- K *ppcLeft = (char *)0;
- K *ppcRight = (char *)0;
- K if (n == 1) {
- K return 1 ;
- K }
- K
- K iLcp = Prefix(n, ppcList, & iLcpLen);
- K if (iLcp * iLcpLen < 2 + iLcpLen) {
- K iLcp = 0;
- K }
- K
- K iLcs = Suffix(n, ppcList, & iLcsLen);
- K if (iLcs * iLcsLen < 2 + iLcsLen) {
- K iLcs = 0;
- K }
- K
- K if (iLcp * iLcpLen < iLcs * iLcsLen) {
- K pcEnd = strrchr(ppcList[0], '\000') - iLcsLen;
- K *ppcRight = strsave(pcEnd);
- K for (i = 0; i < iLcs; ++i) {
- K pcEnd = strrchr(ppcList[i], '\000') - iLcsLen;
- K *pcEnd = '\000';
- K }
- K iLcp = Prefix(iLcs, ppcList, & iLcpLen);
- K if (iLcp == iLcs) {
- K pcEnd = ppcList[0] + iLcpLen;
- K cKeep = *pcEnd;
- K *pcEnd = '\000';
- K *ppcLeft = strsave(ppcList[0]);
- K *pcEnd = cKeep;
- K for (i = 0; i < iLcp; ++i) {
- K ppcList[i] += iLcpLen;
- K }
- K }
- K return iLcs;
- K } else if (0 != iLcpLen && 0 != iLcp) {
- K pcEnd = ppcList[0] + iLcpLen;
- K cKeep = *pcEnd;
- K *pcEnd = '\000';
- K *ppcLeft = strsave(ppcList[0]);
- K *pcEnd = cKeep;
- K for (i = 0; i < iLcp; ++i) {
- K ppcList[i] += iLcpLen;
- K }
- K iLcs = Suffix(iLcp, ppcList, & iLcsLen);
- K if (iLcs == iLcp) {
- K pcEnd = strrchr(ppcList[0], '\000') - iLcsLen;
- K *ppcRight = strsave(pcEnd);
- K for (i = 0; i < iLcs; ++i) {
- K pcEnd = strrchr(ppcList[i], '\000') - iLcsLen;
- K *pcEnd = '\000';
- K }
- K }
- K return iLcp;
- K }
- K return 0;
- K}
- K/* If there are matched curlies around a
- K * member of the list we can remove them.
- K * uLen may be (a few chars) too big, who cares?
- K */
- Kvoid
- Kmcat(pcAccum, pcElement)
- KPREG char *pcAccum, *pcElement;
- K{
- K extern int strlen();
- K register char *pcMatch;
- K register unsigned int uLen;
- K
- K if ('{' == pcElement[0]) {
- K uLen = strlen(pcElement)-1;
- K pcMatch = FindMatch(pcElement, '{', '}', 0);
- K if (pcMatch == & pcElement[uLen]) {
- K *pcMatch = '\000';
- K strcat(pcAccum, pcElement+1);
- K *pcMatch = '}';
- K } else {
- K strcat(pcAccum, pcElement);
- K }
- K } else {
- K strcat(pcAccum, pcElement);
- K }
- K}
- K
- K/*
- K * undo what a {...} does in csh (ksb)
- K * We make passes over the list until we can make no more reductions.
- K * I think this works -- that is it does as good a job as I would.
- K */
- Kunsigned int
- KUnCurly(n, ppcWhole)
- Kunsigned int n;
- Kchar **ppcWhole;
- K{
- K register unsigned int m, i;
- K register char **ppcList;
- K auto unsigned int uInside, uLen, uEnd, uSquish;
- K auto char *pcLeft, *pcRight;
- K auto char *pcTemp, *pcSep;
- K
- K ppcList = ppcWhole;
- K m = n;
- K while (m > 0) {
- K uInside = Split(m, ppcList, & pcLeft, & pcRight);
- K switch (uInside) {
- K case 0:
- K case 1:
- K /* skip boring files for next pass
- K */
- K --m;
- K ++ppcList;
- K break;
- K default:
- K /* Left "{" List[0] "," List[uInside-1] "}" Right
- K */
- K n -= m;
- K uSquish = UnCurly(uInside, ppcList);
- K uLen = 2; /* close curly and "\000" */
- K if ((char *)0 != pcLeft) {
- K uLen += strlen(pcLeft);
- K }
- K for (i = 0; i < uSquish; ++i) {
- K uLen += 1 + strlen(ppcList[i]);
- K }
- K if ((char *)0 != pcRight) {
- K uLen += strlen(pcRight);
- K }
- K pcTemp = malloc(uLen);
- K if ((char *)0 == pcTemp) {
- K fprintf(stderr, acNoMem, progname);
- K exit(1);
- K }
- K
- K pcTemp[0] = '\000';
- K if ((char *)0 != pcLeft) {
- K (void) strcat(pcTemp, pcLeft);
- K free(pcLeft);
- K }
- K if (1 == uSquish) {
- K mcat(pcTemp, ppcList[0]);
- K } else {
- K pcSep = "{";
- K for (i = 0; i < uSquish; ++i) {
- K register char *pcMatch;
- K
- K strcat(pcTemp, pcSep);
- K
- K mcat(pcTemp, ppcList[i]);
- K pcSep = ",";
- K }
- K strcat(pcTemp, "}");
- K }
- K if ((char *)0 != pcRight) {
- K (void) strcat(pcTemp, pcRight);
- K free(pcRight);
- K }
- K
- K uEnd = UnCurly(m-uInside, ppcList+uInside);
- K n += 1 + uEnd;
- K ppcList[0] = pcTemp;
- K for (i = 0 ; i < uEnd; /* update below */) {
- K ppcList[++i] = ppcList[uInside++];
- K }
- K ppcList = ppcWhole;
- K m = n;
- K break;
- K }
- K }
- K return n;
- K}
- K
- K/*
- K * do the opposite of csh(1) {...} (ksb)
- K * we cannot process files with a comma in them, but as a special
- K * case we will remove ",EXT" from the end of a list of files...
- K * and process those if it is the only comma in each of the files.
- K * 1) output UnCulry of files with no commas
- K * 2) output UnCulry of files with `,EXT' (only) on the end
- K * 3) output files with random commas in them (bletch)
- K * 4) loop until all files have been done
- K */
- Kint
- Kmain(argc, argv)
- Kunsigned int argc;
- Kchar **argv;
- K{
- K register unsigned int i, uReplace, uCommon;
- K register char *pcExt;
- K
- K progname = *argv++;
- K --argc;
- K
- K#if defined(READSTDIN)
- K if (argc == 0) {
- K argc = GetFiles(& argv);
- K }
- K#endif
- K while (0 < argc) {
- K for (uCommon = 0; uCommon < argc; ++uCommon) {
- K if ((char *)0 != strrchr(argv[uCommon], ',')) {
- K break;
- K }
- K }
- K if (0 != uCommon) {
- K uReplace = UnCurly(uCommon, argv);
- K argc -= uCommon;
- K for (i = 0; i < uReplace; ++i) {
- K puts(argv[i]);
- K }
- K argv += uCommon;
- K }
- K do {
- K pcExt = (char *)0;
- K for (uCommon = 0; uCommon < argc; ++uCommon) {
- K register char *pcComma;
- K if ((char *)0 == (pcComma = strrchr(argv[uCommon], ','))) {
- K break;
- K }
- K if ((char *)0 == pcExt) {
- K *pcComma ='\000';
- K pcExt = pcComma+1;
- K } else if (0 != strcmp(pcExt, pcComma+1)) {
- K break;
- K } else {
- K *pcComma = '\000';
- K }
- K if ((char *)0 != strrchr(argv[uCommon], ',')) {
- K *pcComma = ',';
- K break;
- K }
- K }
- K if (0 != uCommon) {
- K uReplace = UnCurly(uCommon, argv);
- K argc -= uCommon;
- K for (i = 0; i < uReplace; ++i) {
- K fputs(argv[i], stdout);
- K putchar(',');
- K puts(pcExt);
- K }
- K argv += uCommon;
- K }
- K if ((char *)0 != strrchr(argv[0], ',')) {
- K puts(argv[0]);
- K argc -= 1;
- K argv += 1;
- K uCommon = 1;
- K }
- K } while (0 != uCommon);
- K }
- K exit(0);
- K}
- SHAR_EOF
- # End of shell archive
- exit 0
-