/**
 * mcvert.c - version 1.05 - 10 January, 1990
 * Written by Doug Moore - Rice University - dougm@rice.edu - April '87

 * Sun bug fixes, assorted stuff - Jim Sasaki, March '89

 * Changed default max_line_size from 2000 to unlimited - Doug Moore, April, '89

 * Sun 3/60 doesn't like odd-sized structs.  Bug fixed - Doug Moore, April, '89
 *                                              - aided by Spencer W. Thomas

 * Didn't handle properly many hqx files combined in one file.  Bug fixed -
 *                                           Doug Moore, June, '89

 * Modified to handle MacBinaryII specification. Jim Van Verth, Sept, '89

 * Fixed a bug when there are blank lines in hqx data, as happens when newline
 * get translated to CRLF and then to \n\n, common for some file transfers.
 * The last hqx line would be lost if the previous line was blank or junk.
 *	Glenn Trewitt, Stanford University, 1990	(1.05)

 * Fixed a bug that occurred when extracting data or resource
 * forks on a Sun 4.  It was a byte alignment problem.
 * Rick Zaccone, zaccone@bucknell.edu.  April 1991.  Version 1.6

 * Fixed:
 *   Sent all "Converting ... " lines to stdout instead of stderr
 *   Changed mactypes.h for HP-UX systems
 *      Alan Danziger, aland@cs.brandeis.edu.  October 1991. Version 1.6.5

 * ----------------------------------------------------------------------------
 * External
 * -----
 * Fixed buffering bug when converting very small MacBinary files to hqx files.
 * Provide helpful usage line.
 * Control "Converting ... " lines separately with -S flag.
 * Make encoding and decoding consistent by ignoring locked and init flags.
 * Clean up some error messages; check for more errors; provide errno on error.
 * Updated the man page.
 * -----
 * Internal
 * -----
 * Reformat source (sorry, local standard used by tools is tab space == 3)
 * Remove compiler warning messages.
 * Rename some variables.
 * Added some comments to code.
 * Added some offsets to struct definitions.
 * Since the makefile has compilation flags,
 *    make the compiles depend on the Makefile.
 * -----
 * Thanks to all who have gone before for creating, maintaining,
 * improving, and providing this program and documentation.
 * -----
 * Joseph Skudlarek  Mentor Graphics  8005 SW Boeckman Rd  Wilsonville OR 97070
 * {Jskud@std.mentorg.com,Joseph_Skudlarek@mentorg.com}
 * ...{uunet,nosun,sequent,attunix,apollo}!mntgfx!Jskud
 * Version 1.70 09Jul92
 * ----------------------------------------------------------------------------

 * ----------------------------------------------------------------------------
 * External
 * -----
 * Added -V (Verbose) option (includes debugging information).
 * Fixed bug converting hqx to MacBinary if last line is ":".
 * Avoided a silent error and quick exit situation.
 * -----
 * Internal
 * -----
 * Got rid of almost all lint (SunOS and HP-UX) error messages.
 * Compiled on SunOs, HP-UX, DomainOS.
 * Incorporated Parag Patel <parag@netcom.com> changes for AU/X.
 *    Here's some diffs for really quick cheap hacks to get mcvert to compile
 *    and run under A/UX.  The main problem was that timeb does not exist, so
 *    I added 2 #ifdef TIMEVAL to use the System-V timeval package instead.
 *    The Makefile just has a -DTIMEVAL and a magic -U_SYSV_SOURCE to get
 *    around a pre-defined type "ulong" in sys/types.h (thanks to Apple).
 * Did more code overhauling:
 *    add lots more comments, rename variables, reformat source.
 * Put code in un_hqx to avoid suspected buffering problem.
 * -----
 * Joseph Skudlarek  Mentor Graphics  8005 SW Boeckman Rd  Wilsonville OR 97070
 * (503) 685-1576 (work)
 * {Jskud@std.MENTORG.Com,Joseph_Skudlarek@MENTORG.Com}
 * ...{uunet,nosun,sequent,attunix,apollo}!mntgfx!Jskud
 * Version 1.80 15Jul92
 * ----------------------------------------------------------------------------

 * ----------------------------------------------------------------------------
 * External
 * -----
 * Made hqx file scan processing much smarter
 *    so, for example, info-mac/comm/qwk-reader.hqx,
 *    complete with extraneous colons in column one, converts correctly
 *    (problem described by Edward John Sabol <es2j+@andrew.cmu.edu>)
 * Avoid silly perror on usage message (prompted by Edward John Sabol)
 * Improve error message regarding improper format
 * Added more caveats to man page
 * -----
 * Internal
 * -----
 * Fixed typo's in printf lines to pass all expected arguments
 *    (pointed out by Bo Holst-Christensen
 *    [holst@diku.dk/dikubhc1@uts.uni-c.dk/holst@login.dkuug.dk])
 * Tweak Makefile to ease shar creation and special case ulong, not A/UX
 * Add yet more comments and debugging code
 * -----
 * Joseph Skudlarek  Mentor Graphics  8005 SW Boeckman Rd  Wilsonville OR 97070
 * (503) 685-1576 (work)
 * {Jskud@std.MENTORG.Com,Joseph_Skudlarek@MENTORG.Com}
 * ...{uunet,nosun,sequent,attunix,apollo}!mntgfx!Jskud
 * Version 1.82 30Jul92
 * ----------------------------------------------------------------------------

 * ----------------------------------------------------------------------------
 * External
 * -----
 * relax exactly 64 characters per incoming hqx file, and
 * handle files without trailing newline, so, eg, 
 *    Telnet2.5docs.sit.hqx now converts correctly
 *       (failure reported by Justin Sullivan <justin@f2.facts.uky.edu>)
 *    now also processes info-mac/app/road-map.hqx correctly
 *       (failure reported by Victor Norton<norton@andy.bgsu.edu>)
 * rework the man page for improved clarity and completeness
 * -----
 * Internal
 * -----
 * avoid warning message from gcc on Sequent Balance mainframe
 *    reported by Justin Sullivan <justin@f2.facts.uky.edu>
 * bump max incoming line length to 2048 from 255
 * add mcvert.ps target to Makefile
 * -----
 * Joseph Skudlarek  Mentor Graphics  8005 SW Boeckman Rd  Wilsonville OR 97070
 * (503) 685-1576 (work)
 * {Jskud@std.MENTORG.Com,Joseph_Skudlarek@MENTORG.Com}
 * ...{uunet,nosun,sequent,attunix,apollo}!mntgfx!Jskud
 * Version 1.83 03Aug92
 * ----------------------------------------------------------------------------

 * ----------------------------------------------------------------------------
 * External
 * -----
 * Found and fixed problem with byte ordering plaguing users of
 *    Sequent's Balance running DYNIX, and DEC computers.
 *    The error message looked something like
 *       hqx_to_bin_fork: writing nnn too many bytes
 * Avoid generating debugging info if not to be printed -- cut runtime in half!
 * Generalize and incorporate -I (info) option processing provided by
 *    Paul Franklin, Computer Enginnering, Univ. of Calif., Davis CA 95616
 *    pdfranklin@ucdavis.edu.
 * Added heuristic to avoid false matches in mail headers.
 *    problem expertly characterized, solution beta tested, and subsequent
 *    improvement suggested by "Jim (J.) Lattanzi" <lattanzi@bnr.ca>
 *    so segmented comp.binaries.mac files (either multi-file or concatenated
 *    single file) should now convert correctly.
 * Added -H switch to disable heuristic.
 * Document heuristic in man page.
 * Fixed (long-standing) bug which precluded -p option from being recognized
 *    and verified decompressing and unpacking of PIT files working.
 *    Thanks to Dave Clemans for providing me with a version of PackIt.
 * Add the version to the extened Usage message emitted by the program.
 * Tune the syntax of the summary in the program and man page.
 * Cleaned up spelling mistakes in the man page.
 * -----
 * Internal
 * -----
 * Close all open streams --
 *    fix for binfile by Paul Franklin <pdfranklin@ucdavis.edu>
 * Incorporate changes suggested by Barry_Wolman@transarc.com
 *    to mactypes.h and Makefile for support of IBM RS/6000 running AIX 3.2
 *    reformat Makefile to avoid long option lines
 * Identify the right Makefile lines for Irix too
 *    suggested by Jack Repenning (jackr@dblues.wpd.sgi.com)
 * Clean up the stream handling and add mopen/mclose
 *    avoid unnecessary /dev/null opens
 *    all file open/close/read/write are checked for success
 *       [still need to check putc/fputs/fprintf]
 * Lower lint content on SunOS and HP-UX.
 *    avoiding all "sometimes ignored" lint messages.
 * Improve modularity with mopen/mclose/converting routines.
 * Tune debugging output information.
 * Verify that passes smoke tests on DomainOS/SunOS/HP-UX/ULTRIX.
 * Reformat these comments to avoid tabs.
 * -----
 * Joseph Skudlarek  Mentor Graphics  8005 SW Boeckman Rd  Wilsonville OR 97070
 * (503) 685-1576 (work)
 * {Jskud@std.MENTORG.Com,Joseph_Skudlarek@MENTORG.Com}
 * ...{uunet,nosun,sequent,attunix,apollo}!mntgfx!Jskud
 * Version 1.87 25Sep92
 * ----------------------------------------------------------------------------

 * ----------------------------------------------------------------------------
 * External
 * -----
 * Add README file which describes how to configure and compile mcvert
 * Handle multiple BinHex4.0 inputs in a single file again (thanks to
 *    <Mark_Larimer@pigeon.cpg.cdc.com> for pointing out this regression)
 * Emit the MacBinary header if verbose (to get create and modify times)
 * -----
 * Internal
 * -----
 * Rename some variables, create mac2unix (time) routine, more comments
 * Keep lint content low
 * Pull unnecessary include of <net/nh.h> -- avoid breaking AIX 3.1
 * Fix = vs == typo dealing with protect bit
 * -----
 * Joseph Skudlarek  Mentor Graphics  8005 SW Boeckman Rd  Wilsonville OR 97070
 * (503) 685-1576 (work)
 * {Jskud@std.MENTORG.Com,Joseph_Skudlarek@MENTORG.Com}
 * ...{uunet,nosun,sequent,attunix,apollo}!mntgfx!Jskud
 * Version 1.88 08Dec92
 * ----------------------------------------------------------------------------

 * ----------------------------------------------------------------------------
 * This program may be freely distributed for non-profit purposes.  It may not
 * be sold, by itself or as part of a collection of software.  It may be freely
 * modified as long as no modified version is distributed.  Modifications of
 * interest to all can be incorporated into the program by sending them to me
 * for distribution.  Parts of the code can be used in other programs.  I am not
 * responsible for any damage caused by this program.  I hope you enjoy it.
 *
 * ----------
 * Things that yet could be done:
 * ----------
 * provide compile time switch to avoid bzero and bcopy, and use memset
 *    and memcpy instead (pointed out by linger@drystone.attmail.com)
 * provide header heuristic tuning option
 *    to set length and/or same sensitivity.
 * check return values from putc/fputs/fprintf
 * From franklin@eecs.ucdavis.edu  Thu Sep 24 16:39:21 1992
 *    ...
 *    In .bin->.hqx, check that the file is as long as you're expecting.  This
 *    could catch an error or a non-MacBinary file.  I ran mcvert on a text
 *    file accidentally, and got a segmentation fault.  (It should at least
 *    exit gracefully.)  I'm guessing the error is from reading past the EOF,
 *    but I'm not sure.
 *
 * [[problem is overwriting *fname, and occurs in mcvert, hqxify, and unpack]]
 * [[ demo with mcvert -UI *.hqx ]]
 *    
 *    Also, in .hqx->.bin, have -v print out input file names as well as output
 *    file names.  Once you're using more than one line, do it right.  (Subject
 *    to arbitrary interpretation, of course.  ;-))  I noticed this because I
 *    typed mcvert -I on a bunch of MacBinary files.  mcvert just kept scanning
 *    them, looking for a reasonable BinHex line and not finding one.  Then, I
 *    got a warning from the new heuristic mechanism.  I had no idea which file
 *    it came from.
 *    ...
 * ----------
 */

/*
 * Naming
 *		DOWNLOAD
 *			=> converting TO MacBinary
 *			=> direction == FORWARDS
 *			=> use un_* routines (un => UNdo encoding?)
 *		UPLOAD
 *			=> converting FROM MacBinary
 *			=> direction == BACKWARDS
 *			=> use re_* routines (re => Really Encode?)
 */

#include "mactypes.h"

#define HQX 0
#define TEXT 1
#define DATA 2
#define RSRC 3
#define HOST 4
#define FORWARDS 0
#define BACKWARDS 1

FILE *verbose;
FILE *debug;
FILE *convert;
FILE *devnull;
FILE *output;

char **hqxnames, **hqxnames_left;
char *dir, *ext, *text_author;
char *maxlines_str;
int maxlines;

/* used to skip suspect mail header lines */
int suspect_shorter = 12;
int suspect_same = 1;

/* used to avoid writing output files */
int info_only;

char Usage[] = "\
Usage: %s { [option] ... name ...} ...\n\
 version:\t%4.2f\n\
 default:\t-xDqv\n\
\n\
 option:\n\
\t-x\tBinHex      .hqx \t<-> MacBinary\n\
\t-r\tResource    .rsrc\t<-> MacBinary\n\
\t-d\tData        .data\t<-> MacBinary\n\
\t-u\tText(trans) .text\t<-> MacBinary\n\
\t-h\tHost(as is) .text\t<-> MacBinary\n\
\n\
\t-D\tDownload (Other -> MacBinary)\n\
\t-U\tUpload (MacBinary -> Other)\n\
\n\
\t-p\tBinHex -> MacBinary => unpack PIT\n\
\t-q\tdisable unpack PIT\n\
\n\
\t-s\tsilent\n\
\t-S\tSilent about ``Converting ... '' lines too\n\
\t-v\tverbose\n\
\t-V\tVerbose, includes debugging information\n\
\t-H\tdisable skip-legal-but-suspect-lines Heuristic\n\
\t-I\tInformation only (does not write output files)\n\
\n\
Environment:\n\
\tMAC_EDITOR    \tMACA\tMac creator for text files\n\
\tMAC_DLOAD_DIR \t.   \tdirectory for -D files\n\
\tMAC_EXT       \t.bin\textension for -D files\n\
\tMAC_LINE_LIMIT\tnone\tmaximum line length for -Ux files\n\
";

char *cmdname;

main(argc, argv)
	int argc;
	char **argv;
{
	char *flags, *getenv();
	int direction, mode, unpit_flag;

	cmdname = argv[0];

	/* Early error and clean exit if missing arguments */
	if (argc < 2) {
		usage();
		/*NOTREACHED*/
	}

	devnull = fopen("/dev/null", "w+");

	argv++;
	argc--;
	verbose = stderr;
	debug = devnull;
	output = stdout;
	convert = stdout;
	direction = FORWARDS;
	mode = HQX;
	unpit_flag = 0;

	if ((text_author = getenv("MAC_EDITOR")) == NULL)
		text_author = "MACA";
	if ((ext = getenv("MAC_EXT")) == NULL)
		ext = ".bin";
	if ((dir = getenv("MAC_DLOAD_DIR")) == NULL)
		dir = ".";
	if ((maxlines_str = getenv("MAC_LINE_LIMIT")) == NULL)
		maxlines = 0;
	else {
		maxlines = atoi(maxlines_str);
		if (maxlines < MIN_HQX_LINES) {
			fprintf(stderr, "%s: %s; was %d; reset to %d\n",
				cmdname,
				"warning: MAC_LINE_LIMIT too small",
				maxlines, MIN_HQX_LINES);
			maxlines = MIN_HQX_LINES;
		}
	}

	/* Make command line arguments globally accessible */
	hqxnames = (char **) calloc((unsigned)argc + 1, sizeof(char *));
	hqxnames_left = hqxnames;
	while (argc--)
		*hqxnames_left++ = *argv++;

	/* Flag the end of the list */
	*hqxnames_left = "-";
	hqxnames_left = hqxnames;

	/* While not at the end of the list */
	while (strcmp(*hqxnames_left, "-")) {
		if (hqxnames_left[0][0] == '-') {
			flags = *hqxnames_left++;
			while (*++flags)
				switch (*flags) {
				case 'x':
					mode = HQX;
					break;
				case 'u':
					mode = TEXT;
					break;
				case 'd':
					mode = DATA;
					break;
				case 'r':
					mode = RSRC;
					break;
				case 'h':
					mode = HOST;
					break;
				case 'D':
					direction = FORWARDS;
					break;
				case 'U':
					direction = BACKWARDS;
					break;
				case 'q':
					unpit_flag = 0;
					break;
				case 'p':
					unpit_flag = 1;
					break;
				case 'S':
					convert = devnull;
					/* FALLTHRU */
				case 's':
					verbose = devnull;
					break;
				case 'v':
					verbose = stderr;
					break;
				case 'V':
					debug = stderr;
					break;
				case'H':
					suspect_shorter = suspect_same = 0;
					break;
				case 'I':
					info_only = 1;
					break;
				default:
					usage();
					/*NOTREACHED*/
				}
		}

		if (direction == BACKWARDS)
			if (mode == HQX && unpit_flag)
				re_hqx();      /* no re_pit() yet */
			else if (mode == HQX)
				re_hqx();
			else
				re_other(mode);
		else if (mode == HQX)
			un_hqx(unpit_flag);
		else
			un_other(mode);
	}

	exit(0);
	/*NOTREACHED*/
}

/* An array useful for CRC calculations that use 0x1021 as the "seed" */
word magic[] = {
    0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
    0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
    0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
    0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
    0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
    0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
    0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
    0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
    0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
    0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
    0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
    0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
    0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
    0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
    0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
    0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
    0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
    0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
    0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
    0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
    0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
    0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
    0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
    0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
    0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
    0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
    0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
    0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
    0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
    0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
    0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
    0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
};


/*
 * calc_crc() --
 *   Compute the MacBinary II-style CRC for the data pointed to by p, with the
 *   crc seeded to seed.
 *
 *   Modified by Jim Van Verth to use the magic array for efficiency.
 */
short
calc_mb_crc(p, len, seed)
	unsigned char *p;
	long len;
	short seed;
{
	short hold;		/* crc computed so far */
	long i;			/* index into data */

	extern unsigned short magic[];	/* the magic array */

	hold = seed;			       /* start with seed */
	for (i = 0; i < len; i++, p++) {
		hold ^= (*p << 8);
		hold = (hold << 8) ^ magic[(unsigned char) (hold >> 8)];
	}

	return (hold);
}				/* calc_crc() */


/* Report a fatal error, and exit, never return */
error(msg, name)
	char msg[], name[];

{
	fprintf(stderr, msg, name);
	putc('\n', stderr);
	perror("\nlast perror (may not be relevant)");
	fprintf(stderr, "%s: exiting\n", cmdname);
	if (debug == stderr)
		abort();
	exit(2);
	/*NOTREACHED*/
}

/* replace illegal Unix characters in file name */
/* make sure host file name doesn't get truncated beyond recognition */
unixify(np)
	register char *np;
{
	register ulong c;

	c = strlen(np);
	if (c > SYSNAMELEN - 4)
		c = SYSNAMELEN - 4;
	np[c] = '\0';
	np--;
	while (c = *++np)
		if (c <= ' ' || c == '/' || c > '~')
			*np = '_';
}

/*
 * Unix time (GMT since 1-1-1970)
 * Mac time (local since 1-1-1904)
 */
#define MACTIMEDIFF 0x7c25b080	/* Mac time of 00:00:00 GMT, Jan 1, 1970 */

/* Convert Unix time to Mac time */
ulong
unix2mac(xtime)
	ulong xtime;
{
#ifdef TIMEVAL
	struct timeval t;
	struct timezone tz;

	gettimeofday(&t, &tz);
	return long2mac(xtime + MACTIMEDIFF
	   - 60 * (tz.tz_minuteswest - 60 * tz.tz_dsttime));
#else
	struct timeb tp;

	ftime(&tp);
	return long2mac(xtime + MACTIMEDIFF
	    - 60 * (tp.timezone - 60 * tp.dstflag));
#endif
}

/* Convert Mac time to Unix time */
ulong
mac2unix(xtime)
	ulong xtime;
{
#ifdef TIMEVAL
	struct timeval t;
	struct timezone tz;

	gettimeofday(&t, &tz);
	return (mac2long(xtime) - MACTIMEDIFF
	   + 60 * (tz.tz_minuteswest - 60 * tz.tz_dsttime));
#else
	struct timeb tp;

	ftime(&tp);
	return (mac2long(xtime) - MACTIMEDIFF
	    + 60 * (tp.timezone - 60 * tp.dstflag));
#endif
}

/* This procedure copies the input file to the output file, basically, although
    in TEXT mode it changes LF's to CR's and in any mode it forges a Mac info
    header.  Author type for TEXT mode can come from the MAC_EDITOR environ-
    ment variable if it is defined. */

un_other(mode)
	int mode;
{
	register ulong b;
	register ulong nchars;
	char txtfname[BINNAMELEN], binfname[BINNAMELEN];
	FILE *txtfile, *binfile;
	char *suffix;
	struct stat stbuf;
	info_header info;
	int extra_chars;
	ulong dlen, rlen, mtim, ctim;
	short crc, calc_mb_crc();

	if (mode == DATA)
		suffix = ".data";
	else if (mode == RSRC)
		suffix = ".rsrc";
	else
		suffix = ".text";

	while (hqxnames_left[0][0] != '-') {

		strcpy(txtfname, *hqxnames_left++);
		txtfile = mopen(txtfname, suffix, "r");
		if (stat(txtfname, &stbuf))
			error("Cannot stat %s", txtfname);

		/* stuff header data into the info header */
		bzero((char*)&info, sizeof(info_header));
		info.nlen = strlen(txtfname);
		info.nlen = (info.nlen > NAMELEN) ? NAMELEN : info.nlen;
		info.name[info.nlen] = '\0';
		strcpy((char*)info.name, txtfname);   /* name */
		mtim = unix2mac((ulong)stbuf.st_mtime);
		ctim = unix2mac((ulong)stbuf.st_ctime);
		bcopy((char*)&mtim, (char*)info.mtim, 4);
		bcopy((char*)&ctim, (char*)info.ctim, 4);
		info.uploadvers = '\201';
		info.readvers = '\201';

		if (mode == RSRC) {
			/* dlen is already zero */
			rlen = long2mac(stbuf.st_size);
			bcopy((char*)&rlen, (char*)info.rlen, 4);
			bcopy("APPL", (char*)info.type, 4);
			bcopy("CCOM", (char*)info.auth, 4);
		} else {
			dlen = long2mac(stbuf.st_size);
			bcopy((char*)&dlen, (char*)info.dlen, 4);
			/* rlen is already zero */
			bcopy("TEXT", (char*)info.type, 4);
			if (mode == DATA)
				bcopy("????", (char*)info.auth, 4);
			else
				bcopy(text_author, (char*)info.auth, 4);
		}

		/* calculate CRC */
		crc = calc_mb_crc((unsigned char*)&info, 124L, 0);
		info.crc[0] = (char) (crc >> 8);
		info.crc[1] = (char) crc;

		/* Create the .bin file and write the info to it */
		sprintf(binfname, "%s/%s%s", dir, txtfname, ext);
		binfile = mopen(binfname, "", "w");
		converting(txtfname, info.type, info.auth);
		print_bin_hdr("Creating", &info);
		if (1 != fwrite((char*)&info, sizeof(info), 1, binfile))
			error("fwrite failed on binfile", "");

		nchars = stbuf.st_size;
		extra_chars = 127 - (nchars + 127) % 128;
		if (mode == TEXT)
			while (nchars--) {
				b = getc(txtfile);
				if (b == LF)
					b = CR;
				putc((char)b, binfile);
			}
		else
			while (nchars--)
				putc(getc(txtfile), binfile);

		while (extra_chars--)
			putc(0, binfile);
		mclose(&binfile, "binfile");
		mclose(&txtfile, "txtfile");
	}
}

/* This procedure copies the input file to the output file, basically, although
    in TEXT mode it changes CR's to LF's and in any mode it skips over the Mac
    info header. */

re_other(mode)
	int mode;
{
	register ulong b;
	register ulong nchars;
	ulong temp;
	char txtfname[BINNAMELEN], binfname[BINNAMELEN];
	FILE *txtfile, *binfile;
	char *suffix;
	info_header info;

	if (mode == DATA)
		suffix = ".data";
	else if (mode == RSRC)
		suffix = ".rsrc";
	else
		suffix = ".text";

	while (hqxnames_left[0][0] != '-') {

		strcpy(binfname, *hqxnames_left++);
		binfile = mopen(binfname, ext, "r");
		/* Read the info from the .bin file, create the output file */
		if (1 != fread((char*)&info, sizeof(info), 1, binfile))
			error("fread failed on binfile", "");

		strncpy(txtfname, (char*)info.name, (int)info.nlen);
		txtfname[info.nlen] = '\0';
		converting(txtfname, info.type, info.auth);
		print_bin_hdr("Reading", &info);

		/*
		 * It appears that we use the unadorned name if possible,
		 * and only add the suffix to avoid collisions.
		 * This seemed silly and still seems silly to me today, but
		 * it looks deliberate, and we're avoiding gratuitous changes,
		 * so we leave it as it is.
		 */
		if ((txtfile = fopen(txtfname, "r")) == NULL) {
			txtfile = mopen(txtfname, "", "w");
		} else {
			mclose(&txtfile, "txtfile");
			strcat(txtfname, suffix);
			txtfile = mopen(txtfname, "", "w");
		}

		bcopy((char*)info.dlen, (char *) &temp, 4);
		nchars = temp;
		if (mode == TEXT)
			while (nchars--) {
				b = getc(binfile);
				if (b == CR)
					b = LF;
				putc((char)b, txtfile);
			}
		else if (mode == DATA)
			while (nchars--)
				putc(getc(binfile), txtfile);
		else {
			while (nchars--)
				(void)getc(binfile);
			bcopy((char*)info.rlen, (char *) &temp, 4);
			nchars = temp;
			while (nchars--)
				putc(getc(binfile), txtfile);
		}

		mclose(&binfile, "binfile");
		mclose(&txtfile, "txtfile");
	}
}

usage()
{
	fprintf(stderr, Usage, cmdname, VERSION/100.);
	exit(1);
	/*NOTREACHED*/
}


/* My FileIO routines, to enable clean implementation of info_only */
/* If info_only and open for write, inform user and use devnull instead */
/* If trying to close devnull, don't */

FILE *
mopen(name, exten, type)
	char *name;
	char *exten;
	char *type;
{
	FILE *result;

	switch (*type) {
	case 'r':
		result = fopen(name, type);
		if (result == NULL && *exten) {
			/* see if adding the extension would help */
			int len_root = strlen(name);
			int len_ext = strlen(exten);
			char *dotspot = name + len_root - len_ext;
			if (strcmp(exten, dotspot)) {
				strcat(name, exten);
				result = fopen(name, "r");
			}
		}
		if (result == NULL)
			error("Cannot open %s for read", name);
		break;

	case 'w':
		if (info_only) {
			fprintf(verbose, " %-14s%-27s -I specified\n",
				" No output to", name);
			result = devnull;
		} else {
			result = fopen(name, type);
			if (result == NULL)
				error("Cannot open %s for write", name);
		}
		break;

	default:
		fprintf(stderr, "%s: internal error in mopen -- exiting\n", cmdname);
		exit(2);

	}

	return result;
}

mclose(stream_p, name)
	FILE **stream_p;
	char *name;
{
	if (*stream_p && *stream_p != devnull) {
		if (fclose(*stream_p) == EOF)
			error("Error closing %s", name);
	}

	*stream_p = (FILE *)0;
}

converting(name, type, auth)
	char *name;
	byte *type;
	byte *auth;
{

	fprintf(convert,
	    "%-15s%-30s type = \"%4.4s\", author = \"%4.4s\"\n",
 	    info_only ? "Processing" : "Converting",
		 name, type, auth);
}

print_bin_hdr(msg, hdr)
	char *msg;
	info_header *hdr;
{
	ulong otime, xtime;

	bcopy((char*)hdr->ctim, (char*)&otime, 4);
	fprintf(debug, "DEBUG: verifying mac2unix/unix2mac: 0x%8lx, 0x%8lx\n",
		otime, unix2mac(mac2unix(otime)));

	fprintf(debug, "\
%s\n\
\tName     %.*s\n\
\tType     %.4s\n\
\tCreator  %.4s\n\
",
		msg,
		hdr->nlen, hdr->name,
		hdr->type,
		hdr->auth);

	bcopy((char*)hdr->ctim, (char*)&otime, 4);
	xtime = mac2unix(otime);
	fprintf(debug, "raw ctim: 0x%8lx, mac2unix: 0x%8lx\n",
		otime, xtime);
	fprintf(verbose, "\tCreated  %s", ctime((time_t *)&xtime));

	bcopy((char*)hdr->mtim, (char*)&otime, 4);
	xtime = mac2unix(otime);
	fprintf(debug, "raw mtim: 0x%8lx, mac2unix: 0x%8lx\n",
		otime, xtime);
	fprintf(verbose, "\tModified %s", ctime((time_t *)&xtime));

}
