home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume40 / bin2asci / part01 < prev    next >
Encoding:
Text File  |  1993-11-01  |  15.6 KB  |  600 lines

  1. Newsgroups: comp.sources.misc
  2. From: joe@montebello.soest.hawaii.edu ("Joe Dellinger")
  3. Subject: v40i067:  bin2ascii - convert binary to ascii and back again, Part01/01
  4. Message-ID: <1993Nov1.220211.8378@sparky.sterling.com>
  5. X-Md4-Signature: a57d88e927fb55b46f6f9149a7eabb6b
  6. Sender: kent@sparky.sterling.com (Kent Landfield)
  7. Organization: Sterling Software
  8. Date: Mon, 1 Nov 1993 22:02:11 GMT
  9. Approved: kent@sparky.sterling.com
  10.  
  11. Submitted-by: joe@montebello.soest.hawaii.edu ("Joe Dellinger")
  12. Posting-number: Volume 40, Issue 67
  13. Archive-name: bin2ascii/part01
  14. Environment: UNIX
  15.  
  16. Here is a "shar" file for bin2ascii, a small C utility for converting
  17. arbitrary binary files into a form where standard UNIX utilities like
  18. vi, grep, sed, diff, etc, can be used on them. bin2ascii can then be
  19. used to convert the modified files back into their original binary
  20. form.
  21.  
  22. #! /bin/sh
  23. # This is a shell archive.  Remove anything before this line, then unpack
  24. # it by saving it into a file and typing "sh file".  To overwrite existing
  25. # files, type "sh file -c".  You can also feed this as standard input via
  26. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  27. # will see the following message at the end:
  28. #        "End of shell archive."
  29. # Contents:  Makefile bin2ascii.c
  30. # Wrapped by joe@montebello.soest.hawaii.edu on Thu Oct 28 22:09:46 1993 HST
  31. PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin:$PATH ; export PATH
  32. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  33.   echo shar: Will not clobber existing file \"'Makefile'\"
  34. else
  35. echo shar: Extracting \"'Makefile'\" \(268 characters\)
  36. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  37. XDEFINES = 
  38. X
  39. X# Your favorite C compiler
  40. X#CC    = gcc
  41. XCC    = cc
  42. X
  43. X# The flags your favorite C compiler requires to work.
  44. X#CFLAGS  = -O -I/usr/X386/include -DSVR4 -DSYSV386 ${DEFINES}
  45. XCFLAGS  = -O ${DEFINES}
  46. X
  47. Xall:    bin2ascii
  48. X
  49. Xbin2ascii:    bin2ascii.o
  50. X    $(CC) -o $@ bin2ascii.o -lm
  51. END_OF_FILE
  52. if test 268 -ne `wc -c <'Makefile'`; then
  53.     echo shar: \"'Makefile'\" unpacked with wrong size!
  54. fi
  55. # end of 'Makefile'
  56. fi
  57. if test -f 'bin2ascii.c' -a "${1}" != "-c" ; then 
  58.   echo shar: Will not clobber existing file \"'bin2ascii.c'\"
  59. else
  60. echo shar: Extracting \"'bin2ascii.c'\" \(13004 characters\)
  61. sed "s/^X//" >'bin2ascii.c' <<'END_OF_FILE'
  62. X/*
  63. X * bin2ascii:
  64. X *    Convert an arbitrary binary file into vi-editable text, and back
  65. X *    again. Tries to do a "human-readable" job: well-known control
  66. X *    characters are by default represented using their standard backslash
  67. X *    sequences. Newlines are by default left as newlines, but they can
  68. X *    also be rendered as \n. (Newlines created by the program are preceded
  69. X *    by a backslash, and thus look like a dangling backslash at the end of
  70. X *    a line like you might find in a Makefile or csh script.) Text can
  71. X *    either be printed free-form to follow the original (with a maximum
  72. X *    line length imposed if desired), or broken into regular columns
  73. X *    separated by spaces. If the latter, _real_ spaces are indicated by
  74. X *    the backslash sequence \w, although "\ " works too. The sequence \E
  75. X *    is used to mark the end of the file, to get around vi's habit of
  76. X *    appending a spurious carriage-return on the end of anything it edits.
  77. X *    You can also use \E to prematurely stop processing before the end of
  78. X *    a long file. See self-doc for a complete list of options.
  79. X *
  80. X *    Joe Dellinger
  81. X *    U. Hawai`i Manoa
  82. X *    Oct 10, 1993
  83. X */
  84. X#include <stdio.h>
  85. X#include <string.h>
  86. X#include <fcntl.h>
  87. X#include <sys/types.h>
  88. X#include <unistd.h>
  89. X
  90. X/* How many bytes to read in at a time */
  91. X#define BUFFERLENGTH    1024
  92. X
  93. X#ifndef lint
  94. Xchar            copyright[] =
  95. X"@(#) Joe Dellinger, Oct 10, 1993, U. Hawaii Manoa\n";
  96. X#endif            /* not lint */
  97. X
  98. X#define YES    1
  99. X#define NO    0
  100. X
  101. Xstatic int      return_ascii = YES;
  102. Xstatic int      columns = 0;
  103. Xstatic int      all_hex = 0;
  104. Xstatic int      spaces = NO;
  105. Xstatic int      label = NO;
  106. Xstatic unsigned int offset = 0;
  107. Xstatic unsigned int endpoint = 0;
  108. Xstatic int      invert = NO;
  109. X
  110. Xstatic int      buffer_len = BUFFERLENGTH;
  111. Xstatic char     inbuf[BUFFERLENGTH];
  112. Xstatic int      fdin;
  113. Xstatic int      alldone = NO;
  114. Xstatic int      newline;
  115. X
  116. Xmain (argc, argv)
  117. X    int             argc;
  118. X    char          **argv;
  119. X{
  120. Xextern char    *optarg;
  121. Xextern int      optind;
  122. Xint             ch;
  123. Xint             nread;
  124. Xint             ii, count;
  125. Xunsigned int    lencount;
  126. Xchar            sp4[5];
  127. Xchar            sp3[4];
  128. Xchar            sp1[2];
  129. Xextern int      getachar ();
  130. Xextern void     putachar ();
  131. Xunsigned int    hexno;
  132. Xchar            hexstring[10];
  133. X
  134. X    if (argc == 1 && isatty (fileno (stdin)))
  135. X    {
  136. X/*
  137. X * SELF DOC
  138. X */
  139. X    printf ("bin2ascii: Convert an arbitrary binary file into a readable ASCII format,\n");
  140. X    printf ("           and back again.\n\n");
  141. X    printf ("Usage: bin2ascii [options] binary_input > ascii_output\n");
  142. X    printf ("       bin2ascii [options] < binary_input > ascii_output\n");
  143. X    printf ("       bin2ascii -i [options] bin2ascii_output > binary_input\n");
  144. X    printf ("       bin2ascii -i [options] < bin2ascii_output > binary_input\n");
  145. X    printf ("              HEX looks like \\xDD where DD is a two-digit\n");
  146. X    printf ("              hexadecimal number. The second digit can be\n");
  147. X    printf ("              a space, but it should be present.\n");
  148. X    printf ("              A \"\\E\" marks the end of the file.\n");
  149. X    printf ("\n");
  150. X    printf ("\tOptions: -c #columns -e #bytes -h -H -i -n -o #bytes -r -s\n");
  151. X    printf ("\t-c  #columns (or merely max line length unless -r).\n");
  152. X    printf ("\t-e  #bytes of the input file to process before exiting.\n");
  153. X    printf ("\t-h  means print ALL nonprintables as hex, even \\0 \\a \\b \\f \\n \\r and \\t.\n");
  154. X    printf ("\t-H  means treat EVERYTHING as hex.\n");
  155. X    printf ("\t-i  means do the reverse: go from ASCII back to BINARY.\n");
  156. X    printf ("\t    (For this to work, options should be same as before.)\n");
  157. X    printf ("\t-n  means label byte offset at start of each line.\n");
  158. X    printf ("\t-o  #bytes to offset into the input file before\n");
  159. X    printf ("\t    beginning. Only works when input is a file!\n");
  160. X    printf ("\t-r  means treat carriage returns like any other nonprintable.\n");
  161. X    printf ("\t-s  put spaces between characters. WARNING!\n");
  162. X    printf ("\t    In this case \"\\w\" is used to identify a legitimate space.\n");
  163. X    exit (0);
  164. X    }
  165. X
  166. X
  167. X    while ((ch = getopt (argc, argv, "c:e:hHino:rs")) != EOF)
  168. X    switch (ch)
  169. X    {
  170. X    case 'c':        /* Number of columns to print.  */
  171. X        sscanf (optarg, "%d", &columns);
  172. X        if (columns <= 0)
  173. X        columns = 0;
  174. X        break;
  175. X    case 'e':        /* number of bytes to process */
  176. X        sscanf (optarg, "%u", &endpoint);
  177. X        break;
  178. X    case 'h':        /* use \xHEX or things like \r, \t, etc? */
  179. X        all_hex = 1;
  180. X        break;
  181. X    case 'H':        /* use \xHEX for EVERYTHING? */
  182. X        all_hex = 2;
  183. X        break;
  184. X    case 'i':        /* The inverse program */
  185. X        invert = YES;
  186. X        break;
  187. X    case 'n':        /* label offset */
  188. X        label = YES;
  189. X        break;
  190. X    case 'o':        /* offset to seek */
  191. X        sscanf (optarg, "%u", &offset);
  192. X        break;
  193. X    case 'r':        /* Should a carriage return be left alone? */
  194. X        return_ascii = NO;
  195. X        break;
  196. X    case 's':        /* Put in spaces to keep columns regular? */
  197. X        spaces = YES;
  198. X        break;
  199. X    default:
  200. X        fprintf (stderr, "Type \"bin2hex\" without arguments to get self-doc!\n");
  201. X        exit (1);
  202. X        break;
  203. X    }
  204. X    argc -= optind;
  205. X    argv += optind;
  206. X
  207. X    if (((offset != 0) || (endpoint != 0)) && invert)
  208. X    {
  209. X    fprintf (stderr, "Warning: offset and endpoint options ignored in inverse mode.\n");
  210. X    offset = 0;
  211. X    endpoint = 0;
  212. X    }
  213. X
  214. X    /* Find input */
  215. X    if (argc > 0)
  216. X    {
  217. X    /* Input file name */
  218. X    fdin = open (argv[0], O_RDONLY);
  219. X    if (fdin < 0)
  220. X    {
  221. X        fprintf (stderr, "Could not open input file \"%s\".\n", argv[1]);
  222. X        exit (1);
  223. X    }
  224. X    if (offset > 0)
  225. X    {
  226. X        if (lseek (fdin, (off_t) offset, SEEK_SET) < 0)
  227. X        {
  228. X        fprintf (stderr, "The lseek didn't work.\n");
  229. X        exit (1);
  230. X        }
  231. X    }
  232. X    else if (offset < 0)
  233. X    {
  234. X        fprintf (stderr, "Negative offset?! It's unsigned; this should NOT be able to happen!\n");
  235. X        exit (1);
  236. X    }
  237. X    }
  238. X    else
  239. X    {
  240. X    fdin = fileno (stdin);
  241. X    if (offset != 0)
  242. X    {
  243. X        fprintf (stderr, "Sorry, can't seek on a stream.\n");
  244. X        exit (1);
  245. X    }
  246. X    }
  247. X
  248. X
  249. X/* Forward direction */
  250. X    if (!invert)
  251. X    {
  252. X    if (spaces)
  253. X    {
  254. X        strcpy (sp4, "    ");
  255. X        strcpy (sp3, "   ");
  256. X        strcpy (sp1, " ");
  257. X    }
  258. X    else
  259. X    {
  260. X        strcpy (sp4, "");
  261. X        strcpy (sp3, "");
  262. X        strcpy (sp1, "");
  263. X    }
  264. X
  265. X    count = 0;
  266. X    lencount = offset;
  267. X
  268. X    while (
  269. X           ((endpoint == 0) || (lencount < offset + endpoint))
  270. X           &&
  271. X           ((nread = read (fdin, inbuf, buffer_len)) > 0)
  272. X     )
  273. X    {
  274. X        for (ii = 0;
  275. X         (ii < nread) && ((endpoint == 0) || (lencount < offset + endpoint));
  276. X         ii++, count++, lencount++)
  277. X        {
  278. X        /* Handle newlines that are inserted automatically */
  279. X        if (columns > 0 && count % columns == 0 && count > 0)
  280. X        {
  281. X            printf ("\\\n");
  282. X            count = 0;
  283. X        }
  284. X
  285. X        /* Handle byte count at start of line */
  286. X        if (label && count == 0)
  287. X        {
  288. X            printf ("%10u: ", lencount);
  289. X        }
  290. X
  291. X        ch = 0xFF & (unsigned int) inbuf[ii];
  292. X
  293. X        if (all_hex < 2)
  294. X        {
  295. X            /*
  296. X             * Have to catch backslashes, because we use it to mark
  297. X             * special characters.
  298. X             */
  299. X            if (ch == '\\')
  300. X            {
  301. X            printf ("\\\\%s", sp3);
  302. X            continue;
  303. X            }
  304. X            else if (ch == ' ')
  305. X            {
  306. X            if (spaces)
  307. X                printf ("\\w%s", sp3);
  308. X            else
  309. X                printf ("%c", (char) ch);
  310. X
  311. X            continue;
  312. X            }
  313. X            else if (isprint (ch))
  314. X            {
  315. X            printf ("%c%s", (char) ch, sp4);
  316. X            continue;
  317. X            }
  318. X            else if (return_ascii && ch == '\n')
  319. X            {
  320. X            printf ("\n");
  321. X            count = -1;
  322. X            continue;
  323. X            }
  324. X            else if (all_hex == 0)
  325. X            {
  326. X            switch (ch)
  327. X            {
  328. X            case '\0':
  329. X                printf ("\\0%s", sp3);
  330. X                continue;
  331. X                break;
  332. X            case '\007':    /* Some compilers don't know '\a' */
  333. X                printf ("\\a%s", sp3);
  334. X                continue;
  335. X                break;
  336. X            case '\b':
  337. X                printf ("\\b%s", sp3);
  338. X                continue;
  339. X                break;
  340. X            case '\f':
  341. X                printf ("\\f%s", sp3);
  342. X                continue;
  343. X                break;
  344. X            case '\n':
  345. X                printf ("\\n%s", sp3);
  346. X                continue;
  347. X                break;
  348. X            case '\r':
  349. X                printf ("\\r%s", sp3);
  350. X                continue;
  351. X                break;
  352. X            case '\t':
  353. X                printf ("\\t%s", sp3);
  354. X                continue;
  355. X                break;
  356. X            case '\v':
  357. X                printf ("\\v%s", sp3);
  358. X                continue;
  359. X                break;
  360. X            default:
  361. X                break;
  362. X            }
  363. X            }
  364. X        }
  365. X        /*
  366. X         * Last case left: it's a random garbage thing we have to do
  367. X         * as hex. Force it to have a leading zero.
  368. X         */
  369. X        sprintf (hexstring, "%2X", (unsigned int) ch);
  370. X        if (hexstring[2] != '\0')
  371. X        {
  372. X            fprintf (stderr, "uh oh! Something is badly wrong with the hex conversion!\n");
  373. X            exit (2);
  374. X        }
  375. X        /* Zero pad, don't blank-pad */
  376. X        if (hexstring[0] == ' ')
  377. X            hexstring[0] = '0';
  378. X        printf ("\\x%s%s", hexstring, sp1);
  379. X        /*
  380. X         * Does nothing, but all the other possibilities ended with
  381. X         * continue, so do it that way here too.
  382. X         */
  383. X        continue;
  384. X        }
  385. X    }
  386. X    /*
  387. X     * vi's going to insert a carriage return at the end anyway!
  388. X     */
  389. X    if (lencount == offset + endpoint)
  390. X        printf ("\\End of dumping after %u bytes.\n", endpoint);
  391. X    else
  392. X        printf ("\\EOF\n");
  393. X    }
  394. X    else
  395. X    {
  396. X/* Go the other direction! */
  397. X
  398. X    newline = YES;
  399. X
  400. X    while (ch = getachar (), !alldone)
  401. X    {
  402. X        /*
  403. X         * If lines are labeled, then skip past the number and ":" and
  404. X         * blank.
  405. X         */
  406. X        if (newline && label)
  407. X        {
  408. X        if (ch != ':')
  409. X            continue;
  410. X
  411. X        /*
  412. X         * We've made it past the initial number and ":"
  413. X         */
  414. X        newline = NO;
  415. X
  416. X        ch = getachar ();
  417. X        if (ch != ' ')
  418. X        {
  419. X            fprintf (stderr, "Warning! Expected to find a number then a : then a space at start of a line.\n");
  420. X            fprintf (stderr, "The space is missing!\n");
  421. X        }
  422. X        else
  423. X            ch = getachar ();
  424. X        }
  425. X
  426. X        /*
  427. X         * If automatic spaces is present, then ignore all spaces.
  428. X         */
  429. X        if (spaces && ch == ' ')
  430. X        continue;
  431. X
  432. X        /*
  433. X         * Check for the start of a backslash sequence.
  434. X         */
  435. X        if (ch == '\\')
  436. X        {
  437. X        /* Backslash what? */
  438. X        ch = getachar ();
  439. X
  440. X        switch (ch)
  441. X        {
  442. X        case 'x':    /* Aha! Hex */
  443. X            ch = getachar ();
  444. X            if (
  445. X            (ch >= '0' && ch <= '9') ||
  446. X            (ch >= 'a' && ch <= 'f') ||
  447. X            (ch >= 'A' && ch <= 'F')
  448. X             )
  449. X            {
  450. X            if (ch >= '0' && ch <= '9')
  451. X                hexno = 0xFF & (unsigned int) (ch - '0');
  452. X            else
  453. X                hexno = 0xFF & (unsigned int) (tolower (ch) - 'a' + 10);
  454. X            }
  455. X            else
  456. X            {
  457. X            fprintf (stderr, "Warning! Unknown backslash sequence \\x%c.\n", (char) ch);
  458. X            putachar ();
  459. X            continue;
  460. X            }
  461. X
  462. X            ch = getachar ();
  463. X            if (
  464. X            (ch >= '0' && ch <= '9') ||
  465. X            (ch >= 'a' && ch <= 'f') ||
  466. X            (ch >= 'A' && ch <= 'F')
  467. X             )
  468. X            {
  469. X            if (ch >= '0' && ch <= '9')
  470. X                hexno = (hexno << 4) | (0xFF & (unsigned int) (ch - '0'));
  471. X            else
  472. X                hexno = (hexno << 4) | (0xFF & ((unsigned int) tolower (ch) - 'a' + 10));
  473. X            }
  474. X            else if (ch != ' ')
  475. X            {
  476. X            fprintf (stderr, "Warning! Prematurely truncated backslash sequence \\x?%c.\n", (char) ch);
  477. X            putachar ();
  478. X            }
  479. X            printf ("%c", (char) (hexno));
  480. X            break;
  481. X        case '\\':    /* Hey, it really *was* a backslash */
  482. X            printf ("%c", (char) ch);
  483. X            break;
  484. X        case '\n':    /* A newline inserted by the program: ignore
  485. X                 * it! */
  486. X            newline = YES;    /* Start ignoring the label for the
  487. X                     * next line */
  488. X            break;
  489. X        case 'E':    /* the END OF THE FILE! */
  490. X            alldone = YES;
  491. X            break;
  492. X        case 'w':    /* A space denoted by \w */
  493. X        case ' ':    /* A space made visible by backslashing it */
  494. X            printf ("%c", (char) ' ');
  495. X            continue;
  496. X            break;
  497. X        case '0':    /* A null */
  498. X            printf ("%c", (char) '\0');
  499. X            continue;
  500. X            break;
  501. X        case 'a':    /* Bell */
  502. X            printf ("%c", (char) '\007');
  503. X            continue;
  504. X            break;
  505. X        case 'b':    /* backspace */
  506. X            printf ("%c", (char) '\b');
  507. X            continue;
  508. X            break;
  509. X        case 'f':    /* form feed */
  510. X            printf ("%c", (char) '\f');
  511. X            continue;
  512. X            break;
  513. X        case 'n':    /* A bona-fide newline made visible */
  514. X            printf ("%c", (char) '\n');
  515. X            continue;
  516. X            break;
  517. X        case 'r':    /* carriage return */
  518. X            printf ("%c", (char) '\r');
  519. X            continue;
  520. X            break;
  521. X        case 't':    /* tab */
  522. X            printf ("%c", (char) '\t');
  523. X            continue;
  524. X            break;
  525. X        case 'v':    /* vertical tab */
  526. X            printf ("%c", (char) '\v');
  527. X            continue;
  528. X            break;
  529. X        default:
  530. X            fprintf (stderr, "Warning! Unknown backslash sequence \\%c.\n", (char) ch);
  531. X            printf ("%c", (char) ch);
  532. X            break;
  533. X        }
  534. X        continue;
  535. X        }
  536. X
  537. X        /*
  538. X         * Otherwise, just pass it on through.
  539. X         */
  540. X        printf ("%c", (char) ch);
  541. X
  542. X        if (ch == '\n')
  543. X        newline = YES;    /* Start ignoring the label for the next line */
  544. X    }
  545. X    }
  546. X
  547. X    return 0;
  548. X}
  549. X
  550. Xstatic int      left_in_queue = 0;
  551. Xvoid
  552. Xputachar ()
  553. X{
  554. X    left_in_queue++;
  555. X}
  556. X
  557. X/*
  558. X * On most UNIX systems reading from input a byte at a time is horribly
  559. X * Slow and inefficient, so buffer the intput reading ourselves.
  560. X */
  561. Xint
  562. Xgetachar ()
  563. X{
  564. Xstatic int      nread = 0;
  565. Xint             output;
  566. X
  567. X    if (left_in_queue == 0)
  568. X    {
  569. X    if (alldone || ((nread = read (fdin, inbuf, buffer_len)) == 0))
  570. X    {
  571. X/* We're done! Let them know. */
  572. X        alldone = YES;
  573. X/*
  574. X * Just in case something is wrong and they try to use this value,
  575. X * go ahead and give them something.
  576. X */
  577. X        output = '\0';
  578. X        return output;
  579. X    }
  580. X    else
  581. X    {
  582. X        left_in_queue = nread;
  583. X    }
  584. X    }
  585. X    output = 0xFF & (unsigned int) inbuf[nread - left_in_queue];
  586. X    left_in_queue--;
  587. X
  588. X    return output;
  589. X}
  590. END_OF_FILE
  591. if test 13004 -ne `wc -c <'bin2ascii.c'`; then
  592.     echo shar: \"'bin2ascii.c'\" unpacked with wrong size!
  593. fi
  594. # end of 'bin2ascii.c'
  595. fi
  596. echo shar: End of shell archive.
  597. exit 0
  598.  
  599. exit 0 # Just in case...
  600.