/* * scat file... * * Copy files to stdout. Note: the program first looks for all * files, sorting the file names in ascending alphabetic order * The files are then output in that order. * * In sorting the files, the information is ordered: * * file_name disk[directory] * */ /*)BUILD $(TKBOPTIONS) = { TASK = ...CAT } */ #ifdef DOCUMENTATION title scat Concatenate Files index Concatenate Files synopsis scat file_list description Scat performs a wild-card lookup on all files in the argument list. It sorts these on ascending file name, copying them, in that order, to stdout. Scat removes trailing blanks, tabs, and other control characters from the end of each line. diagnostics .lm +8 .s.i -8;Unknown switch - ... .s.i -8;Illegal file name ... .s.i -8;Can't reopen file ... .s.i -8;Bad file name ... .s.i -8;Duplicate file name ... .s.i -8;Too many files ... .s After wild-card expansion, the file name buffer filled. .s.i -8;No room .s The program ran out of memory for the file name strings. .lm -8 author Martin Minow bugs All files must be on the current network node. #endif #include #define FALSE 0 #define TRUE 1 #define EOS 0 #define MAX_NAMES 500 /* Max. file names */ static int debug; static char filename[81]; /* Just file name */ static char fullname[81]; /* dev:[...] + filename */ static char dirname[81]; /* Just dev:[...] */ static char work[81]; /* Work buffer for file names */ static char record[512]; /* Work buffer for file copy */ static char *wild_spec; /* Current wild card spec */ static char *text[MAX_NAMES]; /* store file names here */ static char **ttop = text; /* Top of text pointer */ static FILE *infd; static int isarg = FALSE; main(argc, argv) int argc; char *argv[]; { register int c; register int i; register char *ap; for (i = 1; i < argc; i++) { if (*(ap = argv[i]) == '-') { while ((c = tolower(*++ap)) != 0) { switch (c) { case 'd': debug++; break; default: bug("W", "Unknown switch", ap); break; } } } else { wild_spec = argv[i]; ttop = text; isarg = TRUE; getnames(); } } if (isarg) { copyall(); } else { copyfile(stdin); } } getnames() /* * Find all files for wild_spec */ { register int count; /* Count files */ register char *wp; /* -> wild_spec */ register char *dp; /* -> dirname[] */ wp = wild_spec; dp = dirname; do { *dp++ = (count = *wp++); } while (count != 0 && count != ':' && count != '[' && count != '('); if (count == 0) { dp = dirname; } else if (count == '[' || count == '(') { do { *dp++ = (count = *wp++); } while (count != 0 && count != ']' && count != ')'); } *dp = 0; if (debug) fprintf(stderr, "wild spec = \"%s\", dirname = \"%s\"\n", wild_spec, dirname); if ((infd = fwild(wild_spec, "r")) == NULL) { bug("W", "Can't open", wild_spec); return(0); } for (count = 0; fnext(infd) != NULL; count++) { setname(infd); save(); if (debug) fprintf(stderr, "Saved file = \"%s\"\n", fullname); } if (debug) fprintf(stderr, "%d files processed\n\n", count); if (count == 0) bug("W", "No files matched", wild_spec); return(count); } copyall() /* * Copy all files */ { char **textp; /* Pointer to names */ register char *tp; /* Pointer to a name */ register char *np; /* Filename pointer */ register int c; /* Current character */ for (textp = text; textp < ttop; textp++) { /* * Get directory part */ for (tp = *textp; (c = *tp++) != 0 && c != '\t';); if (c == 0) error("Illegal file name \"%s\"\n", filename); np = cpystr(fullname, tp); /* * Copy in name part */ for (tp = *textp; (c = *tp++) != 0 && c != '\t';) *np++ = c; *np = 0; if ((infd = fopen(fullname, "r")) == NULL) bug("W", "Can't reopen", np); else { copyfile(infd); fclose(infd); } } } copyfile(fd) register FILE *fd; /* * Copy loop */ { register char *rp; /* * Note -- scat cleans up the end of the logical record */ while (fgets(record, sizeof record, fd) != NULL) { rp = &record[strlen(record) - 1]; while (rp >= record && *rp <= ' ') rp--; rp[1] = EOS; fputss(record, stdout); } } setname(fd) FILE *fd; /* * Build file name */ { register char *wp; register char *np; register int c; fgetname(fd, work); /* * Skip over device name, if any */ for (wp = work; (c = *wp++) && c != ':';); if (c == 0) wp = work; /* * Skip over [UIC] or [PPN] if present */ if (*wp == '[' || *wp == '(') { while ((c = *wp++) && c != ']' && c != ')') if (c == 0) error("Bad file name \"%s\"\n", work); } /* * Wp now points to the first byte of the file name. */ if (debug) fprintf(stderr, "Setname, file name = \"%s\"\n", wp); cpystr(fullname, wp); /* * Don't include version in sort argument, then append * directory name. Result is: * foo.bardb0:[10,20] */ for (wp = fullname; (c = *wp) && c != ';'; wp++); *wp++ = '\t'; cpystr(wp, dirname); } save() /* * Save fullname, add it to the text area (in sorted order) */ { register char **textp; register char **insert; register int i; for (textp = text; textp < ttop; textp++) { if ((i = strcmp(*textp, fullname)) == 0) { fprintf("?SCAT-E-Duplicate file name \"%s\"\n", fullname); return; } else if (i > 0) break; } insert = textp; textp = ttop; if (++ttop >= &text[MAX_NAMES]) error("?SCAT-F-Too many file names, %d max.\n", MAX_NAMES); while (textp >= insert) { textp[1] = *textp; textp--; } if ((*insert = malloc(strlen(fullname) + 1)) == NULL) error("?SCAT-F-No room for \"%s\"\n", fullname); cpystr(*insert, fullname); } usage(s) char *s; { bug("E", s, NULL); exit(1); } bug(severity, mess, arg) char *severity; char *mess; char *arg; /* * Error messages */ { fprintf(stderr, "?SCAT-%s-%s", severity, mess); if (arg != NULL) fprintf(stderr, ": \"%s\"", arg); fprintf(stderr, "\n"); if (*severity != 'W') error("?SCAT-F-Can't continue"); }