#!mkcmd # $Id: glob.m,v 1.8 2012/07/08 21:29:42 ksb Exp $ # I sick of ls telling me the argument list is too long. I want to (ksb) # glob a huge list of files or directories to send to xapply -f, and I # don't want a limit on the size of the list -- thanks. # # Shamelessly copied from my mkcmd exampe-glob.m, and util_fgetln, then # stirred and enhanced a bit. -- ksb # # $Compile: mkcmd -n %F %f && %b %o -m%m %F.c comment "* %kCompile: %k%{cc-cc%} -o %%F %%f %k%k" from '' from '' # must be above machine.h from '' require "util_glob.m" "glob_ieee.m" require "std_help.m" "std_version.m" basename "glob" "" key "glob_options" 1 { "wGlobFlags" } from '"machine.h"' augment action 'V' { user "Version();" } %i static char rcsid[] = "$Id: glob.m,v 1.8 2012/07/08 21:29:42 ksb Exp $"; #ifdef MKCMD_BROKEN_ALT_ENDING static int fBugZZZ; /* mkcmd 8.16 was is broken! 8.17 works */ #endif /* A command-line option to turn on/off bits in this parmeter would * be really nice, but some of the options are not available on all * platforms and I don't know what to do about that. --ksb * If you change this you might need to update Version() below. */ static int wGlobFlags = LOCAL_GLOB_FLAGS, /* flags for IEEE glob */ cSentinal = '\n'; /* or \000 under -z */ %% boolean 'f' { named "fFilter" help "glob names from a filter, rather than from command-line patterns" key "f_filter_file" 2 initialize { "%rfRn" "%n" "%N" } every function { named "Filter" file variable "fpIn" "every" { local } update "%r{fpIn}N = %N;%r{fpIn}Xxu" user "%r{fpIn}XK/ef;" track "fBugZZZ" param "files" help "input files containing glob expressions" } key "f_filter_pipe" 2 initialize { "%rfRn" "stdin" '"-"' } zero { update '%K/ef;' help "process stdin" } } boolean 'r' { named "fVetch" help "report non-matching patterns on stderr, rather than passing them along unmatched" } boolean 's' { named "fSilent" help "unmatched expressions are completely silent, ignore -r" } action 'z' { update "cSentinal = '\\000';" help "output names with terminating NUL characters, like find -print0" } type "mode" 'm' { named "pMCMatch" track "fGaveMode" help "the matched files must match the given mode" } every { named "Matches" track "fGaveLit" param "glob" help "output matches for each expression" } %c /* Explain some internal compile options (ksb) * In this program we try to explain the glob options we set, but if * the customer didn't read glob.3 this won't help a lot. */ static void Version() { register char *pcSep = "", *pcNext = "|"; printf("%s: glob(3) flags ", progname); #if defined(GLOB_NOSORT) if (0 != (wGlobFlags&GLOB_NOSORT)) { printf("%sNOSORT", pcSep); pcSep = pcNext; } #endif #if defined(GLOB_TILDE) if (0 != (wGlobFlags&GLOB_TILDE)) { printf("%sTILDE", pcSep); pcSep = pcNext; } #endif #if defined(GLOB_QUOTE) if (0 != (wGlobFlags&GLOB_QUOTE)) { printf("%sQUOTE", pcSep); pcSep = pcNext; } #endif #if defined(GLOB_MARK) if (0 != (wGlobFlags&GLOB_MARK)) { printf("%sQUOTE", pcSep); pcSep = pcNext; } #endif #if defined(GLOB_NOESCAPE) if (0 != (wGlobFlags&GLOB_NOESCAPE)) { printf("%sNOESCAPE", pcSep); pcSep = pcNext; } #endif #if defined(GLOB_NOESCAPE) if (0 != (wGlobFlags&GLOB_NOESCAPE)) { printf("%sNOESCAPE", pcSep); pcSep = pcNext; } #endif #if defined(GLOB_BRACE) if (0 != (wGlobFlags&GLOB_BRACE)) { printf("%sBRACE", pcSep); pcSep = pcNext; } #endif printf("\n"); } /* The proposed file must have the correct type, (ksb) * all the mode bits set, * and non other than the maditory|optional bits set */ char ** ModeMatch(char **ppcMay, u_MODE_CVT *pMCMatch) { register char **ppcScan; register int iFound; auto char **ppcRet; auto struct stat stLook; static char **ppcHold; static int iMax = 0; /* standard reset logic, free our internal buffer */ if ((char **)0 == ppcMay) { if ((char **)0 != ppcHold) { free((void *)ppcHold); iMax = 0; ppcHold = (char **)0; } return (char **)0; } if (0 == iMax) { iMax = 8192; while (0 != iMax && (char **)0 == (ppcHold = calloc(iMax, sizeof(char *)))) iMax >>= 1; if (0 == iMax) { fprintf(stderr, "%s: calloc: no memory available\n", progname); exit(EX_OSERR); } } iFound = 0; ppcRet = ppcMay; for (ppcScan = ppcMay; (char *)0 != *ppcScan; ++ppcScan) { if (-1 == lstat(*ppcScan, &stLook)) continue; /* raced with an unlink? */ if ('\000' != pMCMatch->cfmt && pMCMatch->iifmt != (S_IFMT&stLook.st_mode)) continue; if (pMCMatch->iset != (pMCMatch->iset & stLook.st_mode)) continue; if (0 != ((07777 & stLook.st_mode) &~ (pMCMatch->iset|pMCMatch->ioptional))) continue; if (iFound == iMax) { register int iAdd = 16384; register char **ppcAlloc; while (0 != iAdd && (char **)0 == (ppcAlloc = realloc(ppcHold, (iMax+iAdd)*sizeof(char *)))) iAdd >>= 1; if (0 == iAdd) { fprintf(stderr, "%s: realloc: out of memory\n", progname); exit(EX_OSERR); } iMax += iAdd; ppcHold = ppcAlloc; } ppcHold[iFound++] = *ppcScan; } ppcHold[iFound] = (char *)0; return 0 == iFound ? (char **)0 : ppcHold; } /* match a single expression (ksb) */ static void Matches(char *pcIt) { register char **ppcFound, **ppcReport; register int i; if ((char **)0 != (ppcReport = ppcFound = util_glob(pcIt)) && fGaveMode) { ppcReport = ModeMatch(ppcFound, pMCMatch); } if ((char **)0 == ppcReport) { if (fSilent) { /* nada */ } else if (fVetch) { fprintf(stderr, "%s: %s: no match\n", progname, pcIt); } else { printf("%s%c", pcIt, cSentinal); } return; } for (i = 0; (char *)0 != ppcReport[i]; ++i) { printf("%s%c", ppcReport[i], cSentinal); } util_glob_free(ppcFound); } /* Read some file for the glob expressions (ksb) */ static void Filter(FILE *fp, char *pcName) { static char *pcFGBuf = (char *)0; static size_t wLen = 0; register int c; register size_t iRead; register char *pc; /* realloc test */ if (0 == wLen) { wLen = 4096; pcFGBuf = calloc(wLen, sizeof(char)); } /* inv. the buffer has room for the next character at least */ for (iRead = 0; EOF != (c = getc(fp)); /* nothing */) { if (cSentinal == c) { pcFGBuf[iRead] = '\000'; Matches(pcFGBuf); iRead = 0; continue; } pcFGBuf[iRead++] = c; if (iRead < wLen) { continue; } wLen += 1024; pc = realloc(pcFGBuf, wLen * sizeof(char)); if ((char *)0 == pc) { fprintf(stderr, "%s: realloc: %lu: %s\n", progname, (unsigned long)wLen, strerror(errno)); exit(EX_OSERR); } pcFGBuf = pc; } if (0 != iRead) { pcFGBuf[iRead] = '\000'; Matches(pcFGBuf); } }