/* * 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 #ifdef vms #include #include #define IO_SUCCESS (SS$_NORMAL | STS$M_INHIB_MSG) #define IO_ERROR SS$_ABORT #endif /* * Note: IO_SUCCESS and IO_ERROR are defined in the Decus C stdio.h file */ #ifndef IO_SUCCESS #define IO_SUCCESS 0 #endif #ifndef IO_ERROR #define IO_ERROR 1 #endif #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; #ifdef vms argc = getredirection(argc,argv); #endif 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 */ extern char *cpystr(); 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); strcpy(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'; strcpy(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); strcpy(*insert, fullname); } usage(s) char *s; { bug("E", s, NULL); exit(IO_ERROR); } 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"); } char * cpystr(s1, s2) register char *s1, *s2; /* * Copy string s2 to s1. s1 must be large enough. * return a pointer to the trailing null in s2 */ { while ((*s1 = *s2++) != '\0') s1++; return(s1); }