Relay-Version: version B 2.10.3 alpha 4/15/85; site seismo.UUCP Posting-Version: version B 2.10.2 9/3/84; site genrad.UUCP Path: seismo!cbosgd!ulysses!allegra!mit-eddie!genrad!sources-request From: sources-request@genrad.UUCP Newsgroups: mod.sources Subject: Bed version 1.0 (editor for binary files). Message-ID: <877@genrad.UUCP> Date: 5 Jun 85 11:05:53 GMT Sender: john@genrad.UUCP Organization: Department of Computing at Lancaster University. Lines: 876 Approved: john@genrad.UUCP From: "Stephen J. Muir" DARPA: stephen%lancs.comp@ucl-cs UUCP: ...!ukc!icdoc!dcl-cs!stephen ----- cut here ----- #!/bin/sh echo 'Start of pack.out, part 01 of 01:' echo 'x - Makefile' sed 's/^X//' > Makefile << '/' XDESTBIN=/usr/local XDESTMAN=/usr/man/mann/bed.n XCFLAGS=-O XOBJECTS=bed.o getcom.o quest.o X# The type whose width is 1 byte. XW8=char X# The type whose width is 2 bytes. XW16=short X# The type whose width is 4 bytes. XW32=int X# The default editor. XEDITOR=/usr/ucb/vi X Xbed: ${OBJECTS} X cc ${OBJECTS} -o $@ X Xbed.o: bed.c X cc -c ${CFLAGS} -DW8=${W8} -DW16=${W16} -DW32=${W32} \ X -DEDITOR=\"${EDITOR}\" bed.c X Xinstall:bed X install -s bed ${DESTBIN} X cp bed.n ${DESTMAN} X Xclean: X rm -f bed *.o / echo 'x - bed.c' sed 's/^X//' > bed.c << '/' X/* Written by Stephen J. Muir, Computing Dept., Lancaster University */ X X# include X# include X# include X# include X# include X Xextern char *rindex (), *mktemp (), *getenv (), *getcom (), *getpar (); X Xchar *version = "Bed version 1.0\n"; X Xchar *filename, *editor, *ap, abuf [32], X *tempdata = "DbedXXXXXX", *temptext = "TbedXXXXXX"; X Xshort ascii, dirty; X Xint bits, base, width, i, count, reclen, ofd, dfd; X Xint (*outfunc) (), (*infunc) (); X Xunsigned W32 buf [512]; X Xtime_t t_mtime; X XFILE *tfd; X Xstruct stat status; X Xsyserr (name) Xchar *name; X { perror (name); X unlink (tempdata); X exit (1); X } X Xisdigit (c) X char c; X { return ('0' <= c && c <= '9'); X } X Xhexin (c) X char c; X { if ('0' <= c && c <= '9') X return (c - '0'); X c |= 040; X if ('a' <= c && c <= 'f') X return (10 + c - 'a'); X return (-1); X } X Xchar Xhexout (num) X unsigned W32 num; X { if (num <= 9) X return ('0' + num); X return ('a' + num - 10); X } X Xin8 () X { unsigned W8 u, *cp = (unsigned W8 *)(&buf [0]); X char c; X do X { while ((i = fgetc (tfd)) != EOF && X ((c = i & 0377) == ' ' || c == '\n') X ) X if (i != EOF && hexin (c) == -1) X return (1); X u = hexin (c); X while ((i = fgetc (tfd)) != EOF && hexin (c = i & 0377) != -1) X u = u * base + hexin (c); X if (i != EOF) X { if (c != ' ' && c != '\n') X return (1); X *cp++ = u; X } X if (cp == ((unsigned W8 *)(&buf [0])) + reclen) X { if (write (dfd, (char *)buf, reclen) != reclen) X return (-1); X cp = (unsigned W8 *)(&buf [0]); X } X } X while (i != EOF); X if ((i = cp - (unsigned W8 *)(&buf [0])) && X write (dfd, (char *)buf, i) != i X ) X return (-1); X return (0); X } X Xout8 () X { unsigned W8 u = 0377, *cp; X do X ++width; X while (u /= base); X while ((i = count = read (dfd, X (char *)(cp = (unsigned W8 *)buf), X reclen X ) X ) > 0 X ) X { while (i) X { if (i-- != count && fputc (' ', tfd) == EOF) X return (-1); X u = *cp++; X ap = &abuf [width]; X do X { *--ap = hexout ((unsigned W32)(u % base)); X u /= base; X } X while (ap != &abuf [0]); X if (fwrite (abuf, sizeof (W8), width, tfd) == 0) X return (-1); X } X if (fputc ('\n', tfd) == EOF) X return (-1); X } X if (fflush (tfd) == EOF) X return (-1); X return (0); X } X Xin16 () X { unsigned W16 u, *cp = (unsigned W16 *)(&buf [0]); X char c; X do X { while ((i = fgetc (tfd)) != EOF && X ((c = i & 0377) == ' ' || c == '\n') X ) X if (i != EOF && hexin (c) == -1) X return (1); X u = hexin (c); X while ((i = fgetc (tfd)) != EOF && hexin (c = i & 0377) != -1) X u = u * base + hexin (c); X if (i != EOF) X { if (c != ' ' && c != '\n') X return (1); X *cp++ = u; X } X if (cp == ((unsigned W16 *)(&buf [0])) + (reclen >> 1)) X { if (write (dfd, (char *)buf, reclen) != reclen) X return (-1); X cp = (unsigned W16 *)(&buf [0]); X } X } X while (i != EOF); X if ((i = cp - (unsigned W16 *)(&buf [0])) && X write (dfd, (char *)buf, i << 1) != i << 1 X ) X return (-1); X return (0); X } X Xout16 () X { unsigned W16 u = 0177777, *cp; X if (status.st_size & 1) X { fprintf (stderr, "filesize is not multiple of 2\n"); X return (1); X } X do X ++width; X while (u /= base); X while ((count = read (dfd, X (char *)(cp = (unsigned W16 *)buf), X reclen X ) X ) > 0 X ) X { if (count & 1) X { fprintf (stderr, "read error\n"); X return (1); X } X i = (count >>= 1); X while (i) X { if (i-- != count && fputc (' ', tfd) == EOF) X return (-1); X u = *cp++; X ap = &abuf [width]; X do X { *--ap = hexout ((unsigned W32)(u % base)); X u /= base; X } X while (ap != &abuf [0]); X if (fwrite (abuf, sizeof (W8), width, tfd) == 0) X return (-1); X } X if (fputc ('\n', tfd) == EOF) X return (-1); X } X if (fflush (tfd) == EOF) X return (-1); X return (0); X } X Xin32 () X { unsigned W32 u, *cp = &buf [0]; X char c; X do X { while ((i = fgetc (tfd)) != EOF && X ((c = i & 0377) == ' ' || c == '\n') X ) X if (i != EOF && hexin (c) == -1) X return (1); X u = hexin (c); X while ((i = fgetc (tfd)) != EOF && hexin (c = i & 0377) != -1) X u = u * base + hexin (c); X if (i != EOF) X { if (c != ' ' && c != '\n') X return (1); X *cp++ = u; X } X if (cp == &buf [0] + (reclen >> 2)) X { if (write (dfd, (char *)buf, reclen) != reclen) X return (-1); X cp = &buf [0]; X } X } X while (i != EOF); X if ((i = cp - &buf [0]) && write (dfd, (char *)buf, i << 2) != i << 2) X return (-1); X return (0); X } X Xout32 () X { unsigned W32 u = 037777777777, *cp; X if (status.st_size & 3) X { fprintf (stderr, "filesize is not multiple of 4\n"); X return (1); X } X do X ++width; X while (u /= base); X while ((count = read (dfd, X (char *)(cp = (unsigned W32 *)buf), X reclen X ) X ) > 0 X ) X { if (count & 3) X { fprintf (stderr, "read error\n"); X return (1); X } X i = (count >>= 2); X while (i) X { if (i-- != count && fputc (' ', tfd) == EOF) X return (-1); X u = *cp++; X ap = &abuf [width]; X do X { *--ap = hexout (u % base); X u /= base; X } X while (ap != &abuf [0]); X if (fwrite (abuf, sizeof (W8), width, tfd) == 0) X return (-1); X } X if (fputc ('\n', tfd) == EOF) X return (-1); X } X if (fflush (tfd) == EOF) X return (-1); X return (0); X } X Xoutasc () X { char c, *cp; X while ((i = count = read (dfd, cp = (char *)buf, reclen)) > 0) X { while (i--) X { if (' ' <= (c = *cp++) && c <= '~' && c != '\\') X { if (fputc (c, tfd) == EOF) X return (-1); X } X else X { if (fputc ('\\', tfd) == EOF) X return (-1); X switch (c) X { case '\b': X c = 'b'; X break; X case '\t': X c = 't'; X break; X case '\f': X c = 'f'; X break; X case '\n': X c = 'n'; X break; X case '\r': X c = 'r'; X break; X case '\\': X break; X default: X if (fputc ('0' + ((c >> 6) & 3), tfd) == EOF || X fputc ('0' + ((c >> 3) & 7), tfd) == EOF X ) X return (-1); X c = '0' + (c & 7); X break; X } X if (fputc (c, tfd) == EOF) X return (-1); X } X } X if (fputc ('\n', tfd) == EOF) X return (-1); X } X if (fflush (tfd) == EOF) X return (-1); X return (0); X } X Xinasc () X { char c, newc; X int ret = 0; X FILE *mydfd; X if ((mydfd = fdopen (dfd, "r+")) == NULL) X return (-1); X while ((i = fgetc (tfd)) != EOF) X { c = i & 0377; X if (c == '\n') X continue; X if (' ' <= c && c <= '~' && c != '\\') X { if (fputc (c, mydfd) == EOF) X goto sysfail; X continue; X } X if (c != '\\' || (i = fgetc (tfd)) == EOF) X goto fail; X switch (c = i & 0377) X { case 'b': X c = '\b'; X break; X case 't': X c = '\t'; X break; X case 'f': X c = '\f'; X break; X case 'n': X c = '\n'; X break; X case 'r': X c = '\r'; X break; X case '\\': X break; X default: X if (c < '0' || c > '3') X goto fail; X newc = (c - '0') << 6; X if ((i = fgetc (tfd)) == EOF || (c = i & 0377) < '0' || c > '7') X goto fail; X newc |= (c - '0') << 3; X if ((i = fgetc (tfd)) == EOF || (c = i & 0377) < '0' || c > '7') X goto fail; X c = newc | (c - '0'); X break; X } X fputc (c, mydfd); X if (ferror (mydfd)) X goto sysfail; X } X goto out; Xsysfail: --ret; X goto out; Xfail: ++ret; Xout: dfd = dup (dfd); X if (fclose (mydfd) == EOF) X return (-1); X return (ret); X } X Xcopyorig () X { lseek (ofd, 0, 0); X lseek (dfd, 0, 0); X ftruncate (dfd, 0); X while ((count = read (ofd, (char *)buf, sizeof (buf))) > 0) X if (write (dfd, (char *)buf, count) != count) X syserr (tempdata); X if (count < 0) X syserr (filename); X dirty = 0; X } X Xedit () X { int pid; X if (base < 2 || base > 16) X { printf ("Radix must be between 2 and 16 inclusive.\n"); X return; X } X switch (bits) X { case 8: X outfunc = out8; X infunc = in8; X break; X case 16: X outfunc = out16; X infunc = in16; X break; X case 32: X outfunc = out32; X infunc = in32; X break; X default: X printf ("This program can only manage 8, 16 or 32 bit formats\n"); X return; X } X if (ascii) X { outfunc = outasc; X infunc = inasc; X } X else if (reclen % (bits >> 3)) X { printf ("Record length is not a multiple of %d.\n", bits >> 3); X return; X } X if (reclen < 1) X { printf ("Record length is too small.\n"); X return; X } X if ((tfd = fopen (temptext, "w+")) == NULL) X syserr (temptext); X lseek (dfd, 0, 0); X width = 0; X fstat (dfd, &status); X printf ("Preparing for edit.\n"); X if ((i = (*outfunc) ()) < 0) X perror (temptext); X if (i) X goto out; X fstat (fileno (tfd), &status); X t_mtime = status.st_mtime; X while ((pid = fork ()) == -1); X if (pid == 0) X { execlp (editor, editor, temptext, 0); X perror (editor); X exit (1); X } X wait (0); X fstat (fileno (tfd), &status); X if (status.st_mtime != t_mtime) X { fseek (tfd, 0, 0); X lseek (dfd, 0, 0); X ftruncate (dfd, 0); X printf ("Copying back changes.\n"); X if ((i = (*infunc) ()) < 0) X { perror (tempdata); X goto out; X } X if (i) X { printf ("%s: bad format - original file restored\n", temptext); X copyorig (); X } X else X ++dirty; X } Xout: fclose (tfd); X unlink (temptext); X } X X/*ARGSUSED*/ Xmain (argc, argv, envp) X char *argv [], *envp []; X { char *command; X if (!isatty (0)) X { fprintf (stderr, "Standard input is not a tty.\n"); X exit (1); X } X while (--argc && **++argv == '-' && *(*argv + 1)) X { ++*argv; X while (**argv) X { switch (*(*argv)++) X { case 'c': X case 'a': X if (ascii++) X goto usage; X break; X case 'r': X if (base) X goto usage; X while (isdigit (**argv)) X base = base * 10 + *(*argv)++ - '0'; X break; X case 'b': X if (bits) X goto usage; X while (isdigit (**argv)) X bits = bits * 10 + *(*argv)++ - '0'; X break; X case 'l': X if (reclen) X goto usage; X while (isdigit (**argv)) X reclen = reclen * 10 + *(*argv)++ - '0'; X break; X default: Xusage: fprintf (stderr, X "usage: bed [-c] [-r#] [-b#] [-l#] file\n" X ); X exit (1); X } X } X } X if (bits == 0) X bits = 16; X if (reclen == 0) X reclen = 16; X if (base == 0) X base = 8; X if (argc != 1) X goto usage; X if (filename = rindex (*argv, '/')) X { *filename = '\0'; X if (*(ap = *argv) == '\0') X ap = "/"; X if (chdir (ap) == -1) X syserr (ap); X *filename++ = '/'; X } X else X filename = *argv; X if ((ofd = open (filename, O_RDWR, 0)) == -1) X syserr (*argv); X if (flock (ofd, LOCK_EX | LOCK_NB) == -1) X { fprintf (stderr, "%s: waiting for lock to be released\n", *argv); X flock (ofd, LOCK_EX); X } X fstat (ofd, &status); X if ((status.st_mode & S_IFMT) != S_IFREG) X { printf ("%s: not regular file\n", *argv); X exit (1); X } X signal (SIGINT, SIG_IGN); X umask (0); X mktemp (tempdata); X mktemp (temptext); X if ((dfd = open (tempdata, O_RDWR | O_CREAT, status.st_mode)) == -1) X syserr (tempdata); X if ((editor = getenv ("VISUAL")) == 0 && X (editor = getenv ("EDITOR")) == 0 X ) X editor = EDITOR; X copyorig (); X for (;;) X { while ((command = getcom ("command: ")) == 0); X switch (*command) X { case 'w': X if (!dirty && X !quest ("File has not been modified; are you sure? ") X ) X break; X if (rename (tempdata, filename) == -1) X { perror ("rename()"); X fprintf (stderr, "new file is in \"%s\"\n", tempdata); X exit (1); X } X exit (0); X case 'q': X if (dirty && !quest ("File has been modified; are you sure? ")) X break; X unlink (tempdata); X exit (0); X case 'e': X edit (); X break; X case 'c': X case 'a': X printf ("%sow in ascii mode.\n", X (ascii = !ascii) ? "N" : "Not n" X ); X break; X case 'r': X printf ("Radix is now %d.\n", base = atoi (getpar ("radix? "))); X break; X case 'b': X printf ("Word size is now %d bits.\n", X bits = atoi (getpar ("bits? ")) X ); X break; X case 'l': X printf ("Record length is now %d bytes.\n", X reclen = atoi (getpar ("record length? ")) X ); X break; X case 'h': X case '?': X printf ("The following commands are available:\n"); X printf ("h - print out help\n"); X printf ("? - print out help\n"); X printf ("a - ascii toggle\n"); X printf ("c - ascii toggle\n"); X printf ("r - set radix\n"); X printf ("b - set number of bits in word\n"); X printf ("l - set record length\n"); X printf ("e - edit\n"); X printf ("w - write out file and quit\n"); X printf ("q - quit\n"); X printf ("radix = %d, bits = %d,", base, bits); X printf (" length of record = %d bytes%s.\n", X reclen, X ascii ? ", ascii mode" : "" X ); X break; X default: X printf ("Invalid command -- type 'h' for help.\n"); X break; X } X } X } / echo 'x - bed.n' sed 's/^X//' > bed.n << '/' X.TH BED 1 "4 June 1985" X.SH NAME Xbed \- an editor for binary files X.SH SYNOPSIS X.B bed [-c] [-r#] [-b#] [-l#] file X.SH DESCRIPTION X.B Bed Xis an editor for binary files. XIt converts the binary file to a textual format, Xallows the user to edit that textual format, Xthen converts the textual format back into binary format. X.SH OPTIONS X.PP XThe following options are recognised, and may be run together, Xe.g. "bed -l120 -c" and "bed -l120c" are equivalent: X.TP 8 X-c XSet initial mode to ascii. X.TP 8 X-a XSame as above. X.TP 8 X-r# XSet initial radix to #. X.TP 8 X-b# XSet initial word size to # bits. X.TP 8 X-l# XSet initial record length (in bytes) to #. X.SH COMMANDS X.PP XOnce X.B bed Xhas validated everything, Xit takes a copy of the data file and enters command mode. XThe following commands are recognised: X.TP 8 Xh XPrint out help and current modes. X.TP 8 X? XSame as above. X.TP 8 Xc XToggle ascii mode. X.TP 8 Xa XSame as above. X.TP 8 Xr # XSet radix to #. X.TP 8 Xb # XSet word size to # bits. X.TP 8 Xl # XSet record length (in bytes) to #. X.TP 8 Xe XConverts the data file to text format and calls up an editor on the text file. XWhen the editor terminates and, if the file has been modified, X.B bed Xwill convert the text file back into the temporary copy of the binary. X.TP 8 Xw XUpdates the original binary file from the copy and exits. X.TP 8 Xq XExits without updating the original. X.SH NOTES XThe user must have read/write access to the original file X.I and Xits parent directory. XThis is because a "rename" system call is used to update the original X(for atomicity). XSpaces in the text file given to the editor (even at the end of lines) Xare significant. XEach line in the text file format contains the number of characters which Xcorrespond to the X.I record Xsize. X.PP XThe following escape sequences are used in ascii mode: X.nf X X\\b backspace X\\t horizontal tab X\\f form feed X\\n newline X\\r carriage return X\\\\ '\\' character X\\nnn the ascii character whose code is given (in octal) X.fi X.SH ENVIRONMENT X.TP 8 XVISUAL XThe editor to be used. X.TP 8 XEDITOR XThe editor to be used if VISUAL is not defined. X.PP XIf neither of these are defined, a default editor will be used. X.SH BUGS X.PP XThe X.I word size Xcan only have values of 8, 16 or 32. XThe X.I radix Xcan only have values between 2 and 16 inclusive. X.PP XMail bugs to "dcl-cs!stephen". X.SH FILES X.nf XDbed?????? working copy of original data file XTbed?????? as above but in text format X.fi X.SH AUTHOR XStephen J. Muir, University of Lancaster, U.K. / echo 'x - getcom.c' sed 's/^X//' > getcom.c << '/' X# include X X# define LINESIZE 82 X Xchar *parptr, comline [LINESIZE]; X Xcomerr () X { fprintf (stderr, "getcom(): bad input\n"); X } X Xchar * Xgetcom (prompt) X char *prompt; X { register char *old, *new; X register short count; X parptr = (char *)0; X if (prompt != (char *)0) X fprintf (stderr, prompt); X if ((count = read (0, comline, LINESIZE - 1)) < 0) X { perror ("getcom()"); X return ((char *)0); X } X if (count == 0) X return ((char *)0); X if (comline [--count] != '\n') X { comerr (); X return ((char *)0); X } X comline [count] = '\0'; X if (count == 0) X return (comline); X for (old = new = &comline [0]; *old != '\0'; ++old) X { if (*old == '!') X return (old); X if (*old != ' ' && *old != '\t') X break; X } X while (*old != '\0') X { while (*old != '\0' && *old != ' ' && *old != '\t') X *new++ = *old++; X while (*old == ' ' || *old == '\t') X ++old; X *new++ = '\0'; X if (parptr == (char *)0) X parptr = new; X } X *new = '\0'; X if (*parptr == '\0') X parptr = (char *)0; X if (old != &comline [count]) X { comerr (); X return ((char *)0); X } X return (comline); X } X Xchar * Xgetpar (prompt) X char *prompt; X { register char *old; X register short count; X if (parptr != (char *)0) X { old = parptr; X while (*parptr++ != '\0'); X if (*parptr == '\0') X parptr = (char *)0; X return (old); X } X if (prompt != (char *)0) X fprintf (stderr, prompt); X if ((count = read (0, comline, LINESIZE - 1)) < 0) X { perror ("getpar()"); X return ((char *)0); X } X if (count == 0) X return ((char *)0); X if (comline [--count] != '\n') X { fprintf (stderr, "getpar(): bad input\n"); X return ((char *)0); X } X comline [count] = '\0'; X return (comline); X } / echo 'x - quest.c' sed 's/^X//' > quest.c << '/' Xextern char *getpar (); X Xquest (prompt) X char *prompt; X { char *reply; X return ((reply = getpar (prompt)) ? ((*reply | 040) == 'y') : 0); X } / echo 'Part 01 of pack.out complete.' exit -- NAME: Stephen J. Muir Project:Alvey ECLIPSE Distribution JANET: stephen@uk.ac.lancs.comp DARPA: stephen%lancs.comp@ucl-cs UUCP: ...!ukc!icdoc!dcl-cs!stephen PHONE: +44 524 65201 Ext. 4599 POST: Department of Computing, University of Lancaster, Bailrigg, Lancaster. LA1 4YR