/* * scopy * * Replace the named files with identical copies such that the * replacement file has "vanilla RMS" file attributes. * No option preserves 8-bit data, but strips NUL bytes. * The -b option transfers the file as read (not recommended as * attributes get messed up). * The -a option cleans up random ascii. * The -p option strips "parity", NUL, and DEL codes * */ /*)BUILD */ #ifdef DOCUMENTATION title scopy Make file standard RMS index Make file standard RMS synopsis scopy [options] file_list description Scopy creates an identical copy of the named input files (the file_list may contain wild cards), creating output files with standard file attributes (record type = variable length, record format = implied carriage control). If there are no arguments, scopy prompts for the option and then for each file. Options: .lm +8 .p -8 -a Cleanup random ASCII, removing NUL, DEL, and other junk. -b Binary, don't remove anything (not even NUL bytes). This option is not recommended as scopy doesn't preserve attributes. -p Remove the 8'th "parity" bit. .lm -8 If no option is given, data is 8-bit, but NUL bytes are removed. Also, is mapped to . diagnostics Scopy does not run on RSTS, RT11, or Unix as these operating systems do not support multiple versions of the same file. author Martin Minow bugs #endif #include #define FALSE 0 #define TRUE 1 #define EOS 0 #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 static int verbose = TRUE; static char filename[81]; /* Just file name */ static char text[81]; /* Work buffer for interactive */ static char record[2048 + 1]; /* Work buffer for file copy */ static FILE *infd; static FILE *outfd; char aflag = FALSE; /* Clean up ASCII if TRUE */ char bflag = FALSE; /* Binary if TRUE */ char pflag = FALSE; /* Strip 8'th bit if TRUE */ main(argc, argv) int argc; char *argv[]; { register int c; register int i; int j; register char *ap; /* * scopy will overwrite files if there are no version numbers */ #ifdef unix fprintf(stderr, "This program must not be used on Unix\n"); exit(IO_ERROR); #endif #ifdef rt11 fprintf(stderr, "This program must not be used on RT11\n"); exit(IO_ERROR); #endif #ifdef rsx extern int $$rsts; if ($$rsts) { fprintf(stderr, "This program must not be used on RSTS/E\n"); exit(IO_ERROR); } #endif #ifdef vms argc = getredirection(argc, argv); #endif for (i = j = 1; i < argc; i++) { ap = argv[i]; if (*ap != '-') argv[j++] = ap; else { for (++ap; (c = *ap++) != EOS; ) { c = tolower(c); switch (c) { case 'a': aflag = TRUE; break; case 'b': bflag = TRUE; break; case 'p': pflag = TRUE; break; default: fprintf(stderr, "Unknown option '%c', ignored\n", *ap); break; } } /* For all options */ } /* If -arg */ } /* For all arg's */ argc = j; /* New end of table */ if (bflag && (aflag | pflag)) { fprintf(stderr, "Illegal option combination, -b stands alone\n"); exit(IO_ERROR); } if (argc <= 1) interactive(); else { for (i = 1; i < argc; i++) dofiles(argv[i]); } } interactive() /* * Prompt for files to do */ { register char *tp; fprintf(stderr, "Replace file by an identical copy, changing output\n"); fprintf(stderr, "file attributes to variable-length, implied carriage control\n"); fprintf(stderr, "File names may contain wild-cards\n"); if (!aflag) { for (;;) { fprintf(stderr, "Clear out extraneous junk characters (Yes/No) ? "); fflush(stderr); if (gets(text) == NULL) return; if (match(text, "yes")) { aflag = TRUE; break; } else if (text[0] == EOS || match(text, "no")) { aflag = FALSE; break; } else { fprintf(stderr, "Can't understand \"%s\", please answer Yes or No\n", text); } } } while (!feof(stdin)) { fprintf(stderr, "File: "); fflush(stderr); gets(text); if (feof(stdin)) break; if (text[0] != EOS) dofiles(text); } } dofiles(wildname) char *wildname; /* * Do all files for this wild_card argument */ { register int nfiles; register long nrecords; int count; #ifdef decus if ((infd = fwild(wildname, (bflag) ? "rn" : "r")) == NULL) { fprintf(stderr, "Illegal (wild-card) file name: \"%s\"\n", wildname); return; } #else if ((infd = fwild(wildname, "r")) == NULL) { fprintf(stderr, "Illegal (wild-card) file name: \"%s\"\n", wildname); return; } #endif for (nfiles = 0; fnext(infd) != NULL; nfiles++) { setname(infd); #ifdef decus outfd = fopen(filename, (bflag) ? "wn" : "w"); #else #ifdef vms if (bflag) outfd = fopen(filename, "w"); else { int unit; if ((unit = creat(filename, 0, "rat=cr", "rfm=var")) == -1) outfd = NULL; else outfd = fdopen(unit, "w"); } #else outfd = fopen(filename, "w"); /* Unix */ #endif #endif if (outfd == NULL) { perror(filename); continue; } nrecords = 0; while ((count = readrecord(infd)) >= 0) { nrecords++; if (bflag) fwrite(record, count, 1, outfd); else fputs(record, outfd); } if (ferror(infd) || ferror(outfd)) perror(filename); fclose(outfd); if (verbose) { printf("%8ld records: %s\n", nrecords, filename); } } if (nfiles == 0) { fprintf(stderr, "No files matching \"%s\"\n", wildname); } } int readrecord(fd) register FILE *fd; /* * Read a line, watch out for garbage. Returns size or -1 on eof/error */ { register char *rp; register int c; if (feof(fd)) return (-1); for (rp = record; rp < &record[(sizeof record)] - 1;) { if ((c = getc(fd)) == EOF) break; if (pflag) c &= 0x7F; if (!bflag) { switch (c) { case 0: /* Always toss NUL */ case 0x7F: /* Always toss DEL */ continue; case '\f': case '\b': case '\t': case '\n': case ('K' - '@'): /* VT */ case '\007': /* BELL */ break; /* Always accept these */ case '\r': if ((c = getc(fd)) != '\n') { ungetc(c, fd); /* Save next char */ c = '\r'; /* Keeping the */ } break; /* Accept if naked */ default: if (aflag && c < ' ') continue; /* Toss random controls */ break; } } *rp++ = c; /* Got a character */ if (!bflag && c == '\n') break; /* End of line */ } *rp = EOS; /* For debugging */ return (rp - record); /* Number gotten */ } setname(fd) FILE *fd; /* * Put output file name into filename buffer */ { register char *ptr; fgetname(fd, filename); if ((ptr = strchr(filename, ';')) != NULL) *ptr = EOS; /* Remove version number */ } int match(arg, value) register char *arg; register char *value; /* * Return TRUE if arg matches leftmost part of value. * Value must be in lowercase. */ { register char c; while ((c = tolower(*arg++)) != EOS) { if (c != *value++) return (FALSE); } return (TRUE); } 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"); } dumptext(buffer, count, fd) register char *buffer; int count; FILE *fd; { extern char *dumpchar(); putc('"', fd); while (--count >= 0) fputs(dumpchar((int) *buffer++), fd); fputs("\"\n", fd); } char * dumpchar(c) register int c; /* * Make a character printable. Returns a static pointer. */ { static char dump_buffer[8]; c &= 0xFF; if (isascii(c) && isprint(c)) { dump_buffer[0] = c; dump_buffer[1] = EOS; } else { switch (c) { case '\n': return ("\\n"); case '\t': return ("\\t"); case '\b': return ("\\b"); case '\f': return ("\\f"); case '\r': return ("\\r"); } sprintf(dump_buffer, "", c); } return (dump_buffer); }