home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / mac / util / unix / mcvert18.sha / mcvert.c < prev    next >
Encoding:
Text File  |  1992-11-05  |  24.3 KB  |  802 lines

  1. /**
  2.  * mcvert.c - version 1.05 - 10 January, 1990
  3.  * Written by Doug Moore - Rice University - dougm@rice.edu - April '87
  4.  
  5.  * Sun bug fixes, assorted stuff - Jim Sasaki, March '89
  6.  
  7.  * Changed default max_line_size from 2000 to unlimited - Doug Moore, April, '89
  8.  
  9.  * Sun 3/60 doesn't like odd-sized structs.  Bug fixed - Doug Moore, April, '89
  10.  *                                              - aided by Spencer W. Thomas
  11.  
  12.  * Didn't handle properly many hqx files combined in one file.  Bug fixed -
  13.  *                                           Doug Moore, June, '89
  14.  
  15.  * Modified to handle MacBinaryII specification. Jim Van Verth, Sept, '89
  16.  
  17.  * Fixed a bug when there are blank lines in hqx data, as happens when newline
  18.  * get translated to CRLF and then to \n\n, common for some file transfers.
  19.  * The last hqx line would be lost if the previous line was blank or junk.
  20.  *    Glenn Trewitt, Stanford University, 1990    (1.05)
  21.  
  22.  * Fixed a bug that occurred when extracting data or resource
  23.  * forks on a Sun 4.  It was a byte alignment problem.
  24.  * Rick Zaccone, zaccone@bucknell.edu.  April 1991.  Version 1.6
  25.  
  26.  * Fixed:
  27.  *   Sent all "Converting ... " lines to stdout instead of stderr
  28.  *   Changed mactypes.h for HP-UX systems
  29.  *      Alan Danziger, aland@cs.brandeis.edu.  October 1991. Version 1.6.5
  30.  
  31.  * ----------------------------------------------------------------------------
  32.  * External
  33.  * -----
  34.  * Fixed buffering bug when converting very small MacBinary files to hqx files.
  35.  * Provide helpful usage line.
  36.  * Control "Converting ... " lines separately with -S flag.
  37.  * Make encoding and decoding consistent by ignoring locked and init flags.
  38.  * Clean up some error messages; check for more errors; provide errno on error.
  39.  * Updated the man page.
  40.  * -----
  41.  * Internal
  42.  * -----
  43.  * Reformat source (sorry, local standard used by tools is tab space == 3)
  44.  * Remove compiler warning messages.
  45.  * Rename some variables.
  46.  * Added some comments to code.
  47.  * Added some offsets to struct definitions.
  48.  * Since the makefile has compilation flags,
  49.  *    make the compiles depend on the Makefile.
  50.  * -----
  51.  * Thanks to all who have gone before for creating, maintaining,
  52.  * improving, and providing this program and documentation.
  53.  * -----
  54.  * Joseph Skudlarek  Mentor Graphics  8005 SW Boeckman Rd  Wilsonville OR 97070
  55.  * {Jskud@std.mentorg.com,Joseph_Skudlarek@mentorg.com}
  56.  * ...{uunet,nosun,sequent,attunix,apollo}!mntgfx!Jskud
  57.  * Version 1.70 09Jul92
  58.  * ----------------------------------------------------------------------------
  59.  
  60.  * ----------------------------------------------------------------------------
  61.  * External
  62.  * -----
  63.  * Added -V (Verbose) option (includes debugging information).
  64.  * Fixed bug converting hqx to MacBinary if last line is ":".
  65.  * Avoided a silent error and quick exit situation.
  66.  * -----
  67.  * Internal
  68.  * -----
  69.  * Got rid of almost all lint (SunOS and HP-UX) error messages.
  70.  * Compiled on SunOs, HP-UX, DomainOS.
  71.  * Incorporated Parag Patel <parag@netcom.com> changes for AU/X.
  72.  *    Here's some diffs for really quick cheap hacks to get mcvert to compile
  73.  *    and run under A/UX.  The main problem was that timeb does not exist, so
  74.  *    I added 2 #ifdef TIMEVAL to use the System-V timeval package instead.
  75.  *    The Makefile just has a -DTIMEVAL and a magic -U_SYSV_SOURCE to get
  76.  *    around a pre-defined type "ulong" in sys/types.h (thanks to Apple).
  77.  * Did more code overhauling:
  78.  *    add lots more comments, rename variables, reformat source.
  79.  * Put code in un_hqx to avoid suspected buffering problem.
  80.  * -----
  81.  * Joseph Skudlarek  Mentor Graphics  8005 SW Boeckman Rd  Wilsonville OR 97070
  82.  * (503) 685-1576 (work)
  83.  * {Jskud@std.MENTORG.Com,Joseph_Skudlarek@MENTORG.Com}
  84.  * ...{uunet,nosun,sequent,attunix,apollo}!mntgfx!Jskud
  85.  * Version 1.80 15Jul92
  86.  * ----------------------------------------------------------------------------
  87.  
  88.  * ----------------------------------------------------------------------------
  89.  * External
  90.  * -----
  91.  * Made hqx file scan processing much smarter
  92.  *    so, for example, info-mac/comm/qwk-reader.hqx,
  93.  *    complete with extraneous colons in column one, converts correctly
  94.  *    (problem described by Edward John Sabol <es2j+@andrew.cmu.edu>)
  95.  * Avoid silly perror on usage message (prompted by Edward John Sabol)
  96.  * Improve error message regarding improper format
  97.  * Added more caveats to man page
  98.  * -----
  99.  * Internal
  100.  * -----
  101.  * Fixed typo's in printf lines to pass all expected arguments
  102.  *    (pointed out by Bo Holst-Christensen
  103.  *    [holst@diku.dk/dikubhc1@uts.uni-c.dk/holst@login.dkuug.dk])
  104.  * Tweak Makefile to ease shar creation and special case ulong, not A/UX
  105.  * Add yet more comments and debugging code
  106.  * -----
  107.  * Joseph Skudlarek  Mentor Graphics  8005 SW Boeckman Rd  Wilsonville OR 97070
  108.  * (503) 685-1576 (work)
  109.  * {Jskud@std.MENTORG.Com,Joseph_Skudlarek@MENTORG.Com}
  110.  * ...{uunet,nosun,sequent,attunix,apollo}!mntgfx!Jskud
  111.  * Version 1.82 30Jul92
  112.  * ----------------------------------------------------------------------------
  113.  
  114.  * ----------------------------------------------------------------------------
  115.  * External
  116.  * -----
  117.  * relax exactly 64 characters per incoming hqx file, and
  118.  * handle files without trailing newline, so, eg, 
  119.  *    Telnet2.5docs.sit.hqx now converts correctly
  120.  *       (failure reported by Justin Sullivan <justin@f2.facts.uky.edu>)
  121.  *    now also processes info-mac/app/road-map.hqx correctly
  122.  *       (failure reported by Victor Norton<norton@andy.bgsu.edu>)
  123.  * rework the man page for improved clarity and completeness
  124.  * -----
  125.  * Internal
  126.  * -----
  127.  * avoid warning message from gcc on Sequent Balance mainframe
  128.  *    reported by Justin Sullivan <justin@f2.facts.uky.edu>
  129.  * bump max incoming line length to 2048 from 255
  130.  * add mcvert.ps target to Makefile
  131.  * -----
  132.  * Joseph Skudlarek  Mentor Graphics  8005 SW Boeckman Rd  Wilsonville OR 97070
  133.  * (503) 685-1576 (work)
  134.  * {Jskud@std.MENTORG.Com,Joseph_Skudlarek@MENTORG.Com}
  135.  * ...{uunet,nosun,sequent,attunix,apollo}!mntgfx!Jskud
  136.  * Version 1.83 03Aug92
  137.  * ----------------------------------------------------------------------------
  138.  
  139.  * ----------------------------------------------------------------------------
  140.  * External
  141.  * -----
  142.  * Found and fixed problem with byte ordering plaguing users of
  143.  *    Sequent's Balance running DYNIX, and DEC computers.
  144.  *    The error message looked something like
  145.  *       hqx_to_bin_fork: writing nnn too many bytes
  146.  * Avoid generating debugging info if not to be printed -- cut runtime in half!
  147.  * Generalize and incorporate -I (info) option processing provided by
  148.  *    Paul Franklin, Computer Enginnering, Univ. of Calif., Davis CA 95616
  149.  *    pdfranklin@ucdavis.edu.
  150.  * Added heuristic to avoid false matches in mail headers.
  151.  *    problem expertly characterized, solution beta tested, and subsequent
  152.  *    improvement suggested by "Jim (J.) Lattanzi" <lattanzi@bnr.ca>
  153.  *    so segmented comp.binaries.mac files (either multi-file or concatenated
  154.  *    single file) should now convert correctly.
  155.  * Added -H switch to disable heuristic.
  156.  * Document heuristic in man page.
  157.  * Fixed (long-standing) bug which precluded -p option from being recognized
  158.  *    and verified decompressing and unpacking of PIT files working.
  159.  *    Thanks to Dave Clemans for providing me with a version of PackIt.
  160.  * Add the version to the extened Usage message emitted by the program.
  161.  * Tune the syntax of the summary in the program and man page.
  162.  * Cleaned up spelling mistakes in the man page.
  163.  * -----
  164.  * Internal
  165.  * -----
  166.  * Close all open streams --
  167.  *    fix for binfile by Paul Franklin <pdfranklin@ucdavis.edu>
  168.  * Incorporate changes suggested by Barry_Wolman@transarc.com
  169.  *    to mactypes.h and Makefile for support of IBM RS/6000 running AIX 3.2
  170.  *    reformat Makefile to avoid long option lines
  171.  * Identify the right Makefile lines for Irix too
  172.  *    suggested by Jack Repenning (jackr@dblues.wpd.sgi.com)
  173.  * Clean up the stream handling and add mopen/mclose
  174.  *    avoid unnecessary /dev/null opens
  175.  *    all file open/close/read/write are checked for success
  176.  *       [still need to check putc/fputs/fprintf]
  177.  * Lower lint content on SunOS and HP-UX.
  178.  *    avoiding all "sometimes ignored" lint messages.
  179.  * Improve modularity with mopen/mclose/converting routines.
  180.  * Tune debugging output information.
  181.  * Verify that passes smoke tests on DomainOS/SunOS/HP-UX/ULTRIX.
  182.  * Reformat these comments to avoid tabs.
  183.  * -----
  184.  * Joseph Skudlarek  Mentor Graphics  8005 SW Boeckman Rd  Wilsonville OR 97070
  185.  * (503) 685-1576 (work)
  186.  * {Jskud@std.MENTORG.Com,Joseph_Skudlarek@MENTORG.Com}
  187.  * ...{uunet,nosun,sequent,attunix,apollo}!mntgfx!Jskud
  188.  * Version 1.87 25Sep92
  189.  * ----------------------------------------------------------------------------
  190.  
  191.  * ----------------------------------------------------------------------------
  192.  * This program may be freely distributed for non-profit purposes.  It may not
  193.  * be sold, by itself or as part of a collection of software.  It may be freely
  194.  * modified as long as no modified version is distributed.  Modifications of
  195.  * interest to all can be incorporated into the program by sending them to me
  196.  * for distribution.  Parts of the code can be used in other programs.  I am not
  197.  * responsible for any damage caused by this program.  I hope you enjoy it.
  198.  *
  199.  * ----------
  200.  * Things that yet could be done:
  201.  * ----------
  202.  * provide compile time switch to avoid bzero and bcopy, and use memset
  203.  *    and memcpy instead (pointed out by linger@drystone.attmail.com)
  204.  * provide header heuristic tuning option
  205.  *    to set length and/or same sensitivity.
  206.  * check return values from putc/fputs/fprintf
  207.  * From franklin@eecs.ucdavis.edu  Thu Sep 24 16:39:21 1992
  208.  *    ...
  209.  *    In .bin->.hqx, check that the file is as long as you're expecting.  This
  210.  *    could catch an error or a non-MacBinary file.  I ran mcvert on a text
  211.  *    file accidentally, and got a segmentation fault.  (It should at least
  212.  *    exit gracefully.)  I'm guessing the error is from reading past the EOF,
  213.  *    but I'm not sure.
  214.  *    
  215.  *    Also, in .hqx->.bin, have -v print out input file names as well as output
  216.  *    file names.  Once you're using more than one line, do it right.  (Subject
  217.  *    to arbitrary interpretation, of course.  ;-))  I noticed this because I
  218.  *    typed mcvert -I on a bunch of MacBinary files.  mcvert just kept scanning
  219.  *    them, looking for a reasonable BinHex line and not finding one.  Then, I
  220.  *    got a warning from the new heuristic mechanism.  I had no idea which file
  221.  *    it came from.
  222.  *    ...
  223.  * ----------
  224.  */
  225.  
  226. /*
  227.  * Naming
  228.  *        DOWNLOAD
  229.  *            => converting TO MacBinary
  230.  *            => direction == FORWARDS
  231.  *            => use un_* routines (un => UNdo encoding?)
  232.  *        UPLOAD
  233.  *            => converting FROM MacBinary
  234.  *            => direction == BACKWARDS
  235.  *            => use re_* routines (re => Really Encode?)
  236.  */
  237.  
  238. #include "mactypes.h"
  239.  
  240. #define HQX 0
  241. #define TEXT 1
  242. #define DATA 2
  243. #define RSRC 3
  244. #define HOST 4
  245. #define FORWARDS 0
  246. #define BACKWARDS 1
  247.  
  248. FILE *verbose;
  249. FILE *debug;
  250. FILE *convert;
  251. FILE *devnull;
  252. FILE *output;
  253.  
  254. char **hqxnames, **hqxnames_left;
  255. char *dir, *ext, *text_author;
  256. char *maxlines_str;
  257. int maxlines;
  258.  
  259. /* used to skip suspect mail header lines */
  260. int suspect_shorter = 12;
  261. int suspect_same = 1;
  262.  
  263. /* used to avoid writing output files */
  264. int info_only;
  265.  
  266. char Usage[] = "\
  267. Usage: %s { [option] ... name ...} ...\n\
  268.  version:\t%4.2f\n\
  269.  default:\t-xDqv\n\
  270. \n\
  271.  option:\n\
  272. \t-x\tBinHex      .hqx \t<-> MacBinary\n\
  273. \t-r\tResource    .rsrc\t<-> MacBinary\n\
  274. \t-d\tData        .data\t<-> MacBinary\n\
  275. \t-u\tText(trans) .text\t<-> MacBinary\n\
  276. \t-h\tHost(as is) .text\t<-> MacBinary\n\
  277. \n\
  278. \t-D\tDownload (Other -> MacBinary)\n\
  279. \t-U\tUpload (MacBinary -> Other)\n\
  280. \n\
  281. \t-p\tBinHex -> MacBinary => unpack PIT\n\
  282. \t-q\tdisable unpack PIT\n\
  283. \n\
  284. \t-s\tsilent\n\
  285. \t-S\tSilent about ``Converting ... '' lines too\n\
  286. \t-v\tverbose\n\
  287. \t-V\tVerbose, includes debugging information\n\
  288. \t-H\tdisable skip-legal-but-suspect-lines Heuristic\n\
  289. \t-I\tInformation only (does not write output files)\n\
  290. \n\
  291. Environment:\n\
  292. \tMAC_EDITOR    \tMACA\tMac creator for text files\n\
  293. \tMAC_DLOAD_DIR \t.   \tdirectory for -D files\n\
  294. \tMAC_EXT       \t.bin\textension for -D files\n\
  295. \tMAC_LINE_LIMIT\tnone\tmaximum line length for -Ux files\n\
  296. ";
  297.  
  298. char *cmdname;
  299.  
  300. main(argc, argv)
  301.     int argc;
  302.     char **argv;
  303. {
  304.     char *flags, *getenv();
  305.     int direction, mode, unpit_flag;
  306.  
  307.     cmdname = argv[0];
  308.  
  309.     /* Early error and clean exit if missing arguments */
  310.     if (argc < 2) {
  311.         usage();
  312.         /*NOTREACHED*/
  313.     }
  314.  
  315.     devnull = fopen("/dev/null", "w+");
  316.  
  317.     argv++;
  318.     argc--;
  319.     verbose = stderr;
  320.     debug = devnull;
  321.     output = stdout;
  322.     convert = stdout;
  323.     direction = FORWARDS;
  324.     mode = HQX;
  325.     unpit_flag = 0;
  326.  
  327.     if ((text_author = getenv("MAC_EDITOR")) == NULL)
  328.         text_author = "MACA";
  329.     if ((ext = getenv("MAC_EXT")) == NULL)
  330.         ext = ".bin";
  331.     if ((dir = getenv("MAC_DLOAD_DIR")) == NULL)
  332.         dir = ".";
  333.     if ((maxlines_str = getenv("MAC_LINE_LIMIT")) == NULL)
  334.         maxlines = 0;
  335.     else {
  336.         maxlines = atoi(maxlines_str);
  337.         if (maxlines < MIN_HQX_LINES) {
  338.             fprintf(stderr, "%s: %s; was %d; reset to %d\n",
  339.                 cmdname,
  340.                 "warning: MAC_LINE_LIMIT too small",
  341.                 maxlines, MIN_HQX_LINES);
  342.             maxlines = MIN_HQX_LINES;
  343.         }
  344.     }
  345.  
  346.     /* Make command line arguments globally accessible */
  347.     hqxnames = (char **) calloc((unsigned)argc + 1, sizeof(char *));
  348.     hqxnames_left = hqxnames;
  349.     while (argc--)
  350.         *hqxnames_left++ = *argv++;
  351.  
  352.     /* Flag the end of the list */
  353.     *hqxnames_left = "-";
  354.     hqxnames_left = hqxnames;
  355.  
  356.     /* While not at the end of the list */
  357.     while (strcmp(*hqxnames_left, "-")) {
  358.         if (hqxnames_left[0][0] == '-') {
  359.             flags = *hqxnames_left++;
  360.             while (*++flags)
  361.                 switch (*flags) {
  362.                 case 'x':
  363.                     mode = HQX;
  364.                     break;
  365.                 case 'u':
  366.                     mode = TEXT;
  367.                     break;
  368.                 case 'd':
  369.                     mode = DATA;
  370.                     break;
  371.                 case 'r':
  372.                     mode = RSRC;
  373.                     break;
  374.                 case 'h':
  375.                     mode = HOST;
  376.                     break;
  377.                 case 'D':
  378.                     direction = FORWARDS;
  379.                     break;
  380.                 case 'U':
  381.                     direction = BACKWARDS;
  382.                     break;
  383.                 case 'q':
  384.                     unpit_flag = 0;
  385.                     break;
  386.                 case 'p':
  387.                     unpit_flag = 1;
  388.                     break;
  389.                 case 'S':
  390.                     convert = devnull;
  391.                     /* FALLTHRU */
  392.                 case 's':
  393.                     verbose = devnull;
  394.                     break;
  395.                 case 'v':
  396.                     verbose = stderr;
  397.                     break;
  398.                 case 'V':
  399.                     debug = stderr;
  400.                     break;
  401.                 case'H':
  402.                     suspect_shorter = suspect_same = 0;
  403.                     break;
  404.                 case 'I':
  405.                     info_only = 1;
  406.                     break;
  407.                 default:
  408.                     usage();
  409.                     /*NOTREACHED*/
  410.                 }
  411.         }
  412.  
  413.         if (direction == BACKWARDS)
  414.             if (mode == HQX && unpit_flag)
  415.                 re_hqx();      /* no re_pit() yet */
  416.             else if (mode == HQX)
  417.                 re_hqx();
  418.             else
  419.                 re_other(mode);
  420.         else if (mode == HQX)
  421.             un_hqx(unpit_flag);
  422.         else
  423.             un_other(mode);
  424.     }
  425.  
  426.     exit(0);
  427.     /*NOTREACHED*/
  428. }
  429.  
  430. /* An array useful for CRC calculations that use 0x1021 as the "seed" */
  431. word magic[] = {
  432.     0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
  433.     0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
  434.     0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
  435.     0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
  436.     0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
  437.     0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
  438.     0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
  439.     0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
  440.     0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
  441.     0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
  442.     0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
  443.     0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
  444.     0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
  445.     0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
  446.     0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
  447.     0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
  448.     0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
  449.     0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
  450.     0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
  451.     0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
  452.     0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
  453.     0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
  454.     0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
  455.     0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
  456.     0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
  457.     0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
  458.     0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
  459.     0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
  460.     0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
  461.     0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
  462.     0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
  463.     0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
  464. };
  465.  
  466.  
  467. /*
  468.  * calc_crc() --
  469.  *   Compute the MacBinary II-style CRC for the data pointed to by p, with the
  470.  *   crc seeded to seed.
  471.  *
  472.  *   Modified by Jim Van Verth to use the magic array for efficiency.
  473.  */
  474. short
  475. calc_mb_crc(p, len, seed)
  476.     unsigned char *p;
  477.     long len;
  478.     short seed;
  479. {
  480.     short hold;        /* crc computed so far */
  481.     long i;            /* index into data */
  482.  
  483.     extern unsigned short magic[];    /* the magic array */
  484.  
  485.     hold = seed;                   /* start with seed */
  486.     for (i = 0; i < len; i++, p++) {
  487.         hold ^= (*p << 8);
  488.         hold = (hold << 8) ^ magic[(unsigned char) (hold >> 8)];
  489.     }
  490.  
  491.     return (hold);
  492. }                /* calc_crc() */
  493.  
  494.  
  495. /* Report a fatal error */
  496. error(msg, name)
  497.     char msg[], name[];
  498.  
  499. {
  500.     fprintf(stderr, msg, name);
  501.     putc('\n', stderr);
  502.     perror("\nlast perror (may not be relevant)");
  503.     fprintf(stderr, "%s: exiting\n", cmdname);
  504.     if (debug == stderr)
  505.         abort();
  506.     exit(2);
  507.     /*NOTREACHED*/
  508. }
  509.  
  510. /* replace illegal Unix characters in file name */
  511. /* make sure host file name doesn't get truncated beyond recognition */
  512. unixify(np)
  513.     register char *np;
  514. {
  515.     register ulong c;
  516.  
  517.     c = strlen(np);
  518.     if (c > SYSNAMELEN - 4)
  519.         c = SYSNAMELEN - 4;
  520.     np[c] = '\0';
  521.     np--;
  522.     while (c = *++np)
  523.         if (c <= ' ' || c == '/' || c > '~')
  524.             *np = '_';
  525. }
  526.  
  527. /* Convert Unix time (GMT since 1-1-1970) to Mac time (local since 1-1-1904) */
  528. #define MACTIMEDIFF 0x7c25b080    /* Mac time of 00:00:00 GMT, Jan 1, 1970 */
  529.  
  530.  
  531. ulong
  532. time2mac(xtime)
  533.     ulong xtime;
  534. {
  535. #ifdef TIMEVAL
  536.     struct timeval t;
  537.     struct timezone tz;
  538.  
  539.     gettimeofday(&t, &tz);
  540.     return long2mac(xtime + MACTIMEDIFF
  541.        - 60 * (tz.tz_minuteswest - 60 * tz.tz_dsttime));
  542. #else
  543.     struct timeb tp;
  544.  
  545.     ftime(&tp);
  546.     return long2mac(xtime + MACTIMEDIFF
  547.         - 60 * (tp.timezone - 60 * tp.dstflag));
  548. #endif
  549. }
  550.  
  551. /* This procedure copies the input file to the output file, basically, although
  552.     in TEXT mode it changes LF's to CR's and in any mode it forges a Mac info
  553.     header.  Author type for TEXT mode can come from the MAC_EDITOR environ-
  554.     ment variable if it is defined. */
  555.  
  556. un_other(mode)
  557.     int mode;
  558. {
  559.     register ulong b;
  560.     register ulong nchars;
  561.     char txtfname[BINNAMELEN], binfname[BINNAMELEN];
  562.     FILE *txtfile, *binfile;
  563.     char *suffix;
  564.     struct stat stbuf;
  565.     info_header info;
  566.     int extra_chars;
  567.     ulong dlen, rlen, mtim, ctim;
  568.     short crc, calc_mb_crc();
  569.  
  570.     if (mode == DATA)
  571.         suffix = ".data";
  572.     else if (mode == RSRC)
  573.         suffix = ".rsrc";
  574.     else
  575.         suffix = ".text";
  576.  
  577.     while (hqxnames_left[0][0] != '-') {
  578.  
  579.         strcpy(txtfname, *hqxnames_left++);
  580.         txtfile = mopen(txtfname, suffix, "r");
  581.         if (stat(txtfname, &stbuf))
  582.             error("Cannot stat %s", txtfname);
  583.  
  584.         /* stuff header data into the info header */
  585.         bzero((char*)&info, sizeof(info_header));
  586.         info.nlen = strlen(txtfname);
  587.         info.nlen = (info.nlen > NAMELEN) ? NAMELEN : info.nlen;
  588.         info.name[info.nlen] = '\0';
  589.         strcpy((char*)info.name, txtfname);   /* name */
  590.         mtim = time2mac((ulong)stbuf.st_mtime);
  591.         ctim = time2mac((ulong)stbuf.st_ctime);
  592.         bcopy((char*)&mtim, (char*)info.mtim, 4);
  593.         bcopy((char*)&ctim, (char*)info.ctim, 4);
  594.         info.uploadvers = '\201';
  595.         info.readvers = '\201';
  596.  
  597.         if (mode == RSRC) {
  598.             /* dlen is already zero */
  599.             rlen = long2mac(stbuf.st_size);
  600.             bcopy((char*)&rlen, (char*)info.rlen, 4);
  601.             bcopy("APPL", (char*)info.type, 4);
  602.             bcopy("CCOM", (char*)info.auth, 4);
  603.         } else {
  604.             dlen = long2mac(stbuf.st_size);
  605.             bcopy((char*)&dlen, (char*)info.dlen, 4);
  606.             /* rlen is already zero */
  607.             bcopy("TEXT", (char*)info.type, 4);
  608.             if (mode == DATA)
  609.                 bcopy("????", (char*)info.auth, 4);
  610.             else
  611.                 bcopy(text_author, (char*)info.auth, 4);
  612.         }
  613.  
  614.         /* calculate CRC */
  615.         crc = calc_mb_crc((unsigned char*)&info, 124L, 0);
  616.         info.crc[0] = (char) (crc >> 8);
  617.         info.crc[1] = (char) crc;
  618.  
  619.         /* Create the .bin file and write the info to it */
  620.         sprintf(binfname, "%s/%s%s", dir, txtfname, ext);
  621.         binfile = mopen(binfname, "", "w");
  622.         converting(txtfname, info.type, info.auth);
  623.         if (1 != fwrite((char*)&info, sizeof(info), 1, binfile))
  624.             error("fwrite failed on binfile", "");
  625.  
  626.         nchars = stbuf.st_size;
  627.         extra_chars = 127 - (nchars + 127) % 128;
  628.         if (mode == TEXT)
  629.             while (nchars--) {
  630.                 b = getc(txtfile);
  631.                 if (b == LF)
  632.                     b = CR;
  633.                 putc((char)b, binfile);
  634.             }
  635.         else
  636.             while (nchars--)
  637.                 putc(getc(txtfile), binfile);
  638.  
  639.         while (extra_chars--)
  640.             putc(0, binfile);
  641.         mclose(&binfile, "binfile");
  642.         mclose(&txtfile, "txtfile");
  643.     }
  644. }
  645.  
  646. /* This procedure copies the input file to the output file, basically, although
  647.     in TEXT mode it changes CR's to LF's and in any mode it skips over the Mac
  648.     info header. */
  649.  
  650. re_other(mode)
  651.     int mode;
  652. {
  653.     register ulong b;
  654.     register ulong nchars;
  655.     ulong temp;
  656.     char txtfname[BINNAMELEN], binfname[BINNAMELEN];
  657.     FILE *txtfile, *binfile;
  658.     char *suffix;
  659.     info_header info;
  660.  
  661.     if (mode == DATA)
  662.         suffix = ".data";
  663.     else if (mode == RSRC)
  664.         suffix = ".rsrc";
  665.     else
  666.         suffix = ".text";
  667.  
  668.     while (hqxnames_left[0][0] != '-') {
  669.  
  670.         strcpy(binfname, *hqxnames_left++);
  671.         binfile = mopen(binfname, ext, "r");
  672.         /* Read the info from the .bin file, create the output file */
  673.         if (1 != fread((char*)&info, sizeof(info), 1, binfile))
  674.             error("fread failed on binfile", "");
  675.         strncpy(txtfname, (char*)info.name, (int)info.nlen);
  676.         txtfname[info.nlen] = '\0';
  677.         converting(txtfname, info.type, info.auth);
  678.  
  679.         /*
  680.          * It appears that we use the unadorned name if possible,
  681.          * and only add the suffix to avoid collisions.
  682.          * This seemed silly and still seems silly to me today, but
  683.          * it looks deliberate, and we're avoiding gratuitous changes,
  684.          * so we leave it as it is.
  685.          */
  686.         if ((txtfile = fopen(txtfname, "r")) == NULL) {
  687.             txtfile = mopen(txtfname, "", "w");
  688.         } else {
  689.             mclose(&txtfile, "txtfile");
  690.             strcat(txtfname, suffix);
  691.             txtfile = mopen(txtfname, "", "w");
  692.         }
  693.  
  694.         bcopy((char*)info.dlen, (char *) &temp, 4);
  695.         nchars = temp;
  696.         if (mode == TEXT)
  697.             while (nchars--) {
  698.                 b = getc(binfile);
  699.                 if (b == CR)
  700.                     b = LF;
  701.                 putc((char)b, txtfile);
  702.             }
  703.         else if (mode == DATA)
  704.             while (nchars--)
  705.                 putc(getc(binfile), txtfile);
  706.         else {
  707.             while (nchars--)
  708.                 (void)getc(binfile);
  709.             bcopy((char*)info.rlen, (char *) &temp, 4);
  710.             nchars = temp;
  711.             while (nchars--)
  712.                 putc(getc(binfile), txtfile);
  713.         }
  714.  
  715.         mclose(&binfile, "binfile");
  716.         mclose(&txtfile, "txtfile");
  717.     }
  718. }
  719.  
  720. usage()
  721. {
  722.     fprintf(stderr, Usage, cmdname, VERSION/100.);
  723.     exit(1);
  724.     /*NOTREACHED*/
  725. }
  726.  
  727.  
  728. /* My FileIO routines, to enable clean implementation of info_only */
  729. /* If info_only and open for write, inform user and use devnull instead */
  730. /* If trying to close devnull, don't */
  731.  
  732. FILE *
  733. mopen(name, exten, type)
  734.     char *name;
  735.     char *exten;
  736.     char *type;
  737. {
  738.     FILE *result;
  739.  
  740.     switch (*type) {
  741.     case 'r':
  742.         result = fopen(name, type);
  743.         if (result == NULL && *exten) {
  744.             /* see if adding the extension would help */
  745.             int len_root = strlen(name);
  746.             int len_ext = strlen(exten);
  747.             char *dotspot = name + len_root - len_ext;
  748.             if (strcmp(exten, dotspot)) {
  749.                 strcat(name, exten);
  750.                 result = fopen(name, "r");
  751.             }
  752.         }
  753.         if (result == NULL)
  754.             error("Cannot open %s for read", name);
  755.         break;
  756.  
  757.     case 'w':
  758.         if (info_only) {
  759.             fprintf(verbose, " %-14s%-27s -I specified\n",
  760.                 " No output to", name);
  761.             result = devnull;
  762.         } else {
  763.             result = fopen(name, type);
  764.             if (result == NULL)
  765.                 error("Cannot open %s for write", name);
  766.         }
  767.         break;
  768.  
  769.     default:
  770.         fprintf(stderr, "%s: internal error in mopen -- exiting\n", cmdname);
  771.         exit(2);
  772.  
  773.     }
  774.  
  775.     return result;
  776. }
  777.  
  778. mclose(stream_p, name)
  779.     FILE **stream_p;
  780.     char *name;
  781. {
  782.     if (*stream_p && *stream_p != devnull) {
  783.         if (fclose(*stream_p) == EOF)
  784.             error("Error closing %s", name);
  785.     }
  786.  
  787.     *stream_p = (FILE *)0;
  788. }
  789.  
  790. converting(name, type, auth)
  791.     char *name;
  792.     byte *type;
  793.     byte *auth;
  794. {
  795.  
  796.     fprintf(convert,
  797.         "%-15s%-30s type = \"%4.4s\", author = \"%4.4s\"\n",
  798.          info_only ? "Processing" : "Converting",
  799.          name, type, auth);
  800. }
  801.  
  802.