home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume4
/
curly
< prev
next >
Wrap
Internet Message Format
|
1989-02-03
|
23KB
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