#ifdef ournix #include "ournix.h" #endif char sccsID[] = "@(#) tab.c V0.4 Copyright Vector Systems Ltd(pjc+jhs) 1988\n"; /* tab - entab + detab, convert spaces to tabs, or inverse. BUG: tab.c does not recognise epson or hp pcl escape sequences are invisible. thus spacing of tab stops becomes miscalculated. mktemp & verbose added by jhs. jhs did: reformatted with `indent', then manually added typedefs & more meaningfull names I think jhs did signal handling */ #include #include #ifdef unix #include #include #else #include #include #endif #ifdef i386 /* { */ #include #endif /* } */ #ifndef O_BINARY #define O_BINARY 0 #endif typedef int FD ; typedef char FLAG; FLAG verbose = 0; char **ARGV; #ifdef scs /* { */ extern char * mktemp(); #define TMP_NAME "taXXXXXX" #else /* }{ */ #include #ifdef MSDOS /* { */ #define TMP_NAME "taXXXXXX" #else /* }{ */ #define TMP_NAME "tab.XXXXXX" #endif /* } */ #endif /* } */ #include /* for MAXPATHLEN */ char tmp_name[MAXPATHLEN]; /* temporary file name */ main(argc, argv) char **argv; { FD fd; void clean_on_error(); int dir = 0; ARGV = argv; #ifdef VSL /* { */ #include "../../include/vsl.h" #endif /* } */ if (argc < 3) { fprintf(stderr, "Usage: tab -d/-e [files]\n"); exit(1); } strcpy(tmp_name, TMP_NAME); signal(SIGINT, clean_on_error); #ifdef scs (void) mktemp(tmp_name); #else if (mktemp(tmp_name) != tmp_name) fprintf(stderr, "%s: mktemp failed\n", *ARGV); /* else fprintf(stderr,"%s: mktemp ok\n",*ARGV); */ #endif for (argv++; *argv; argv++) { if (**argv == '-') { if (dir != 0) { fprintf(stderr, "En/detab selected - ignored\n"); continue; } switch ((*argv)[1]) { case 'd': /* detabulate */ case 'D': dir = -1; break; case 'e': /* entabulate */ case 'E': dir = 1; break; case 'v': verbose = 1; break; default: fprintf(stderr, "Unknown option - ignored\n"); break; } continue; } if (dir == 0) { fprintf(stderr, "en/detab not set - cannot continue\n"); exit(2); } fd = open(*argv, O_BINARY | O_RDONLY); if (fd < 0) { fprintf(stderr, "Cannot open '%s'\n", *argv); continue; } if (verbose) printf("%s\n", *argv); if (dir > 0) entab(fd); else detab(fd); close(fd); fls_tmp(); signal(SIGINT, SIG_IGN); fd = open(*argv, O_BINARY | O_WRONLY | O_CREAT | O_TRUNC, 0200); if (fd < 0) { signal(SIGINT, clean_on_error); fprintf(stderr, "Cannot recreate '%s'\n", *argv); clean_unlink((FLAG)1); continue; } copyback(*argv,fd); signal(SIGINT, clean_on_error); clean_unlink((FLAG)1); } exit(0); } #ifdef MSDOS #define MAXBUF 25000 #else #define MAXBUF 250000 #endif /* output/tmpfile variables */ char out_buf[MAXBUF]; int tmp_fd; char *out_p = out_buf; /* input file variables */ unsigned char in_buf[MAXBUF]; unsigned char *in_end; unsigned char *in_p; clean_unlink(unlink_f) FLAG unlink_f ; { if (tmp_fd > 0) { close(tmp_fd); tmp_fd = 0; if (unlink_f) unlink(tmp_name); } out_p = out_buf; } void clean_on_error() { clean_unlink((FLAG)1); exit(2); } fls_tmp() { int diff, res; if (tmp_fd == 0) return; diff = out_p - out_buf; if (diff != 0) res = write(tmp_fd, out_buf, diff); out_p = out_buf; if (diff != res) { fprintf(stderr, "Write error on temporary file\n"); close(tmp_fd); unlink(tmp_name); exit(1); } lseek(tmp_fd, (off_t) 0, 0); /* go back to beginning */ } copyback(name,fd) char *name ; FD fd; { unsigned diff; int res = 1; if (tmp_fd == 0) { /* no temporary file */ diff = out_p - out_buf; out_p = out_buf; if (diff && write(fd, out_buf, diff) != diff) res = -1; } else { while ((diff = read(tmp_fd, out_buf, MAXBUF)) > 0) if (write(fd, out_buf, diff) != diff) { res = -1; break; } } if (res < 0) { fprintf(stderr, "Write failure on source file\n"); clean_unlink((FLAG)0); fprintf(stderr, "Suggest you manually rescue data from %s for %s\n", tmp_name,name); exit(2); } close(fd); } out_c(c) { int diff; if (tmp_fd == 0) { /* no temporary file yet */ tmp_fd = open(tmp_name, O_BINARY | O_CREAT | O_TRUNC | O_RDWR, 0200); if (tmp_fd < 0) { fprintf(stderr, "Cannot create temporary file '%s'\n", tmp_name); exit(3); } } diff = out_p - out_buf; out_p = out_buf; if (write(tmp_fd, out_buf, diff) != diff) { fprintf(stderr, "Write failure on temporary file\n"); clean_unlink((FLAG)1); exit(4); } *out_p++ = c; } in_c(fd) FD fd; { int diff; diff = read(fd, in_buf, MAXBUF); if (diff <= 0) return (EOF); in_end = in_buf + diff; in_p = in_buf; return (*in_p++); } #define IN_C(fd) ((in_p < in_end) ? *in_p++ : in_c(fd)) #define OUTC(ch) ((out_p < &out_buf[MAXBUF] )? *out_p++ = ch : out_c(ch)) /* actually do the entabing */ entab(fd) FD fd; { register int c; register int col, newcol; FLAG quoted = 0; /*- 1 if a quote character is seen in line, if you entabulate a quoted string in a program, it will change the binary, so once double quote is detected on a line, no more tabbing occurs, lines such as printf("very_long_line\ spaces end"); are not protected from change Also to be set to 1 if an escape character is encountered in the line, to preserve tab spacing in text with printer control escape sequences */ col = 0; for (;;) { newcol = col; while ((c = IN_C(fd)) == ' ' || c == '\t') { if (c == '\t') { newcol = (newcol + 8) & ~07; OUTC('\t'); col = newcol; continue; } newcol++; if ((newcol % 8) == 0) { if (newcol - col > 1) OUTC('\t'); else OUTC(' '); col = newcol; } } while (col < newcol) { OUTC(' '); col++; } if (c == EOF) return; OUTC(c); #ifdef MSDOS if (c == '\r') continue; #endif if (c == '\n') col = 0; else col++; } } /* detab the file */ detab(fd) FD fd; { register int c; register int column = 0; /* left most char on page is column no. 0 tab positions are normally 0,8,16 etc */ while ((c = IN_C(fd)) != EOF) { switch (c) { default: if (c >= ' ' && c <= '~') column++; break; case '\r': case '\n': case '\f': /* assume FF puts cursor to left margin */ column = 0; break; case '\t': do { OUTC(' '); } while ((++column % 8) != 0); continue; case '\b': if (column > 0) column--; break; } OUTC(c); } }