[net.sources] Unix tools for the Macintosh

chuqui@nsc.UUCP (Chuqui Q. Koala) (01/05/85)

This is a shar file of useful programs for the Macintosh. I wrote none of 
them, but there have been requests for them. See the article in
net.micro.mac for more details.

chuq
--- cut here --- (ouch!)
#! /bin/sh
# The rest of this file is a shell script which will extract:
# BinHex.hex README README.xbin fromhexu.c macget.c macput.c tohexu.c xbin.c
echo x - BinHex.hex
cat >BinHex.hex <<'!!ChuquiCo!!Software!!'
#APPLBNHX$2000
***COMPRESSED
***RESOURCE FORK
(    0   !2!   3@0   3+M_,Y"J  ,0^P "B%) !(Q
(&P !@ 6$6P "0 :3G5AX!%  !LA2@ <H  P*  8/B@ 
(!!.=6'*$4  &R%* !R@"C H !@^*  03G5![?S.0J@ 
( PQ0  8H $^*  09@ ! $*H !(Q;  & !:@$SXH !!F
(   [$YU88B@"#XH !!F  #>3G5A /]Z0F@ '* ,/B@ 
(!!G"@Q'_]5G'&   ,(^//_3""@ !P H9@  M* )/B@ 
(!!F  "J3G5A /]&0F@ '* ,/B@ $&8  )9.=4'M_,Y"
(*@ ##%M_=8 %C%\  ( +$*H "Z@1#XH !!F  !R3G5*
(    !@70FEN2&5X(%8R+C @+2T@,3 O,CDO.#0   $ 
( ___@ (  , "  "@ @ 0D ( &(@"'_R$ A_^_@(?_ (
( AP8 @(<$ ("'  " AP  @(<  ("'  " AP/P@)_$"(
( CX@$@(<3 H""'(& @.?P\$ C ' @$ !P$ @ < @& '
( ! '^< ( (? ! $!P ("   !!    (@   !0    (  
( ___@ /__\ #___@ ___\ /___@#___\ ____@/___X
( ____@/___X#___^ ____@/___X#___^ ____@/___X
( ____@/___X#___^ ____\'____ ____P'___\ ____
( !___\ /_X? !_\!P /^   !_    /@   !P    (  
(     =!4%!,        '$).2%@    !24-.(P      
((!&4D5&      "     *0 !          #____[ 10-
($%B;W5T($)I;DAE>,D      2T          )8  @  
(        /___M<$1FEL915!<'!L:6-A=&EO;B M/B!5
('!L;V%D     !55<&QO860@+3X@07!P;&EC871I;VX 
(     $M      M415A4(&9I;'1E<@  $@ !+0     *
($-O;7!R97-S960  !( #U-E;F0@;&EN92!F965D<P  
(    2T     !%%U:70 40       !4 9  R ,@!S  !
(             $    ! @ $      !& 50 6@&0! )/
($L       H "@ : 9"(.$)I;DAE>" R+C L("!W<FET
('1E;B!B>2!9=F5S($QE;7!E<F5U<B![0TE3(#<T,#$V
("PQ-S0Q?2       !H "@ J 9"(-'=I=&@@36%C05--
(*HL(&%N($5D:71O<B]!<W-E;6)L97(@9F]R('1H92!-
(&%C:6YT;W-H+@      .@ * $H!+(@J1F]R(&9U<G1H
(&5R(&EN9F]R;6%T:6]N(&-O;G1A8W0@36%I;G-T87DL
("       $H "@!: 2R((GM#25,@-S W-C4L-S,T?2!O
('(@*#@Q."D@.3DQ+38U-# N    %0!D &0 O@&0  $ 
(            @     J  $      #P Y@!0 2($ D]+
(       %  4 #L!&(@*7C @97)R;W(N(    !4 9 !D
( "^ 9   0            ,     =  !       \ .8 
(% !(@0"3TL       H "@ Z 2*(5$-O;G9E<G-I;VX@
(&]F($%P<&QI8V%T:6]N(&1O8W5M96YT('1O(&%N(%5P
(&QO860@9F]R;6%T(&1O8W5M96YT(&AA<R!B965N(&-O
(&UP;&5T960A(    !4 9 !D +@!F@ !            
( 0     D  #       V /  2@$L! )/2P      "@ *
(  J 2R(4$-O;G9E<G-I;VX@;V8@57!L;V%D(&9O<FUA
('0@9&]C=6UE;G0@=&\@07!P;&EC871I;VX@9&]C=6UE
(&YT(&AA<R!B965N(&-O;7!L971E9"$      "H "@ Z
( #FB )>,       .@ * $H YH@"7C$    3 &0 9 #8
( &5  $!              Z4     4AM__RH;JC^J1*I
(#!"IZE[80 , B \  #__Z R/SP  JGI/SP  ZEY/SP 
( 2I>6$ # H;?  !_?P;?  !_?^H4"M/_<*IM$(G/SS_
(/](;?VRJ7 0'V?N,"W]LM! ,#L !D[[  +_X  R_^  
(!C_X/_@_^ !8/_@_^#_X/_@,"W]P @   AGOD*G("W]
(+0_ *D^(!]@   R0F<O+?V\2&W]QJDL,!_00# [  9.
(/L  O^6  X!"/^6_Y;_EO^60J<O+?V\J3T@'RM _<HP
("W]RM! ,#L !D[[  ( !@ . &9"9ZDX8 #_8# M_<P,
($   68P0J<_/  !0J<O//____^I?"M7_<ZI%4*G2&W]
(-*ID3 M_=(,0  !9NXO+?W.J8-@OD*G/SP  :E)/RW]
(,Q(;?O.J49"9TAM^\ZIMC ?8* P+?W,T$ P.P &3OL 
( +_D@": ^3_D@ 4_Y( , !,_Y( : HM  ']_$*G/SP 
( *I23\\  0?+?W\J45@ /]D"BT  ?W_0J<_/  "J4D_
(#P !A\M_?^I16  _T@*+0 !_?U"IS\\  *I23\\  <?
("W]_:E%8 #_+*GT2&W]LB\M_<:ILV  _H(P+?VT9P#^
('I"9S\\ &0_/ !D+RW]M#\\  "IZ3 ?8 #^8#\\ $8_
(#P 1DAZ"F!"IS\\__]"IT*G2&W]'C\\  *IZDHM_1YG
( #^TC\\ $8_/ !&2'H, TAZ"C1"ITAM_6@_/  !J>I*
("W]:&< _JY)[?UH80 (AF$ "'1A  BR(7Q415A4 " A
('P@(" @ "2@#3XH !!F  D^< ))[?UH1>WYQ&$ !_ [
($#]UAM\  ']^TI'9@ )(&$ !DA)[?T>80 (;BMH "#]
(. K:  D_>0P*  H D#P #M _>@K: ! _=@K:  V_=QA
(  !\$HM_?]G"$'Z"<UA  &X80 '*$)M_?)"+?WT/SP 
( H_/ !&J)-*K?W89RA"K?W82&W]<JB$2'H*;JB$0?H)
(*=A  &$< %)[?T>1?@  &$ !W)@+$JM_=QG8D*M_=Q(
(&W]<JB$2'H*,ZB$0?H)BF$  59P 4GM_1Y%^   80 '
("X[0/W4&WP  ?WZ2D=F  A>80 !M$HM^\YG!F$  )A@
(/!!^@EA80 !($GM_1XP+?W480 ')D(M_?I@ /]B2BW]
(/]F$D'Z"59A  $6$"W]]&$  61@$$'Z"3QA  $$,"W]
(/)A  %(80  Y&$ !/A)[?UH,"W]UF$ !N)"+?W[+RW]
(,:I%$*G/SP  T*G+SS_____J7PK5_W.J15"ITAM_=*I
()$P+?W2#$   6;N+RW]SJF#8 #] $'M^\Y"01(82BW]
(/]G+D('$ %A   X8"1"0! 8T2W]]#0M_?+40.=:.T+]
(/)*+?W_9@9A  #,8 1A   24<G_VDHM_?]G!&$  "I@
($IT!PP'  9F$@(& #\&!@ @P49A  0TP49"!^,0XQ92
( =1RO_@3G5*!V<:# < !F<&XPY2!V#T @8 /P8& " 0
( 9A  0&3G5A   6< UA  /Z2BW]_6<&< IA  /N3G5"
($$2&& &$!AA  /@4<G_^$YU0?H'LV'0<"-A  /.("W]
(.!A   :("W]Y&$  !)P)&$  [@P+?WH80  $F"N<@/A
()AA  .F4<G_^$YU/P#@2&$   0P'Q\ Z AA   $$!]A
(  $.&   X1![?S.0J@ ##%M_=0 &$/M^\\A20 @(7P 
(   (  D0F@ +$*H "Z@ CXH !!G" Q'_]EF  9R&V@ 
("O[SDYU/SP 1C\\ $9(>@<60J=*+?W\9@@_//__0J=@
( @_/  !2'H&^D*G2&W]'C\\  *IZDHM_1YG /MX/SP 
($8_/ !&2'H(J4AZ!MI"ITAM_6@_/  !J>I*+?UH9P#[
(%1)[?T>80 %8' !1?@  &$ !+P[0/W4&WP  ?WZ2D=F
(  %[$(M_?XK?%1%6%3]X"M\(" @(/WD0FW]Z$)M_?)"
("W]]&$ !8A"04'M^\X2&&<  ?Y@!@P8 "-G!E')__A@
(.(,00 (929A  +>*T#]X&$  M8K0/WD#$$ !640#!@ 
("1F"F$  M!E!#M _>AA  -Z2>W]:&$ !)QA  2*80 $
(,@A;?W@ " A;?WD "0P+?WH@6@ ** -/B@ $&8 !5!A
(  %#$/Z!C-A  +X9@H;?  !_?YA  3X/SP "C\\ $:H
()-(;?URJ(1#^@8N80 "U&8,2'H&QZB$80 $U& D0_H&
( =A  *^9AI(>@:^J(1A  2^< ))[?UH1>WYQ&$  \9@
( YP DGM_6A%[?G$80 #H#M _=8;?  !_?M*1V8 !-!A
(  $.F$  ?1@!&$ !()*+?O.9QY#^@6?80 ":&<&80 !
( 1@YD/Z!;]A  )89@1A  1>80 !D$GM_6@P+?W680 #
('I"+?W[0_H%D&$  C9G /](0_H%<V$  BIG /\\2>W]
(!XP+?W480 #4D(M_?HO+?W&J11"IS\\  1"IR\\____
(/^I?"M?_<Y#^@5R80 !]&8.0_H&%Q-8 !,36  48#1#
(/H%4F$  =QF)D/Z!>T36  .$U@ #Q-8 ! 36  11?H&
(!U'Z@ 1,"W]\F$  7A@%$/Z!>Y%^@8<1^H %A M_?1A
(  !:B\)+PI"IT*GJ8LO+?W.J15"ITAM_=*ID3 M_=(,
($   6;N+RW]SJF#8 #Y!DGM_1XP+?W480 "H$(M_?I@
( #X\F$  49*+?W^9B0, 0 "94A"0&$  .)E0-$M_?0T
("W]\M1 YUH[0OWR80  7&#<0@=A   H92(R & :80  
(!YE&-$M_?0T+?WRU$#G6CM"_?)A   T4<G_Y$YU= =*
( =F%AP8! 8 ( P& $!E!@ \  %.=>4.?@;C%N,04P=1
(,K_W@(\ /Y.=2)M_>H2P"M)_>I2K?WN#*T  "  _>YD
( ).=4CGPX!![?S.0J@ ##%M_=8 &$/MV<0A20 @(6W]
(.X )$)H "Q"J  NH ,^*  09@ "VDS? <-#[=G$*TG]
(.I"K?WN3G5T ^&($!A305'*__A.=6$   )A   "%!A3
($$* @ P# ( "F4*!@( B0P" /IE# ("  _I2( " CP 
(/Y.=3\ X$AA C ?'P#H"&$"$!]A!!; 3G4"   /    
(# ,   Z90)> $YU0>W[SA(89PP,$  *9@92B%,!9O1.
('5AZ$)"%!FR F4,8 2S"&8&4<K_^D) 3G5"IS\\  %"
(*<O//____^IO2M7_<:H<S\\  "HAS\\  RHBC\\  "H
((@_/   J(E.=6'./SP "C\\ !:HDTAZ S&HA!M\  3]
(/4K;?W@_?9(;?WUJ(0_/  */SP )JB32'H#-:B$*VW]
(.3]]DAM_?6HA#\\  H_/ !FJ)-(>@,\J(1.=6$ _WP_
(#P "C\\ !:HDTAZ ]ZHA!M\  3]]2MM_>#]]DAM_?6H
((0_/  */SP )JB32'H#WJB$*VW]Y/WV2&W]]:B$/SP 
( H_/ !FJ)-(>@+HJ(1.=4'M_,Y"J  ,0^P "B%) !(Q
(&P !@ 6$6P "0 :3G5AX!%  !LA2@ <H  P*  8/B@ 
(!!.=6'*$4  &R%* !R@"C H !@^*  03G5![?S.0J@ 
( PQ0  8H $^*  09@ ! $*H !(Q;  & !:@$SXH !!F
(   [$YU88B@"#XH !!F  #>3G5A /]Z0F@ '* ,/B@ 
(!!G"@Q'_]5G'&   ,(^//_3""@ !P H9@  M* )/B@ 
(!!F  "J3G5A /]&0F@ '* ,/B@ $&8  )9.=4'M_,Y"
(*@ ##%M_=8 %C%\  ( +$*H "Z@1#XH !!F  !R3G5*
("W]^F<00BW]^DGM_1XP+?W480#_1DHM_?MG$$(M_?M)
(.W]:# M_=9A /\P3G5![?S.0J@ ##%M_=0 &$/M^\\A
($D ("%\    _P D,7P-@  L0J@ +J "/B@ $&<(#$?_
(-EF   *&V@ *_O.3G4_!V&.0J>I)" ?9PJPK?W&9@0O
( "I%$*G/SP  D*G+SS_____J7PK7_W./A]A   N+RW]
(,ZI%3\\  2IR$*G2&W]TJF1,"W]T@Q   %F[B\M_<ZI
((,N;?W"8 #T[$'Z C="0! 89PJ^ &<&$!C0P&#R+PA"
(*="IT*GJ8M.=4*G/SP  :F_+Q="9ZDU+SQ$4E92J4U"
(*<_/  "J;]"9ZDUJ3=.=4'MV<0P/"0\8 )"&%'(__Q.
('5415A4 "TH5&AI<R!F:6QE(&UU<W0@8F4@8V]N=F5R
('1E9"!W:71H($)I;DAE>"Y(97@I RHJ*@TJ*BI#3TU0
(%)%4U-%1! J*BI215-/55)#12!&3U)+#"HJ*D1!5$$@
($9/4DL.*BHJ14Y$($]&($1!5$$'*BHJ0U)#.@PJ*BI#
($A%0TM354TZ)5194$4@;V8@;F5W(&9I;&4@:7,N+BXN
("XN+BXN+BXN+BXN+CH@(D-214%43U(@;V8@;F5W(&9I
(&QE(&ES+BXN+BXN+BXN+CH@*$-O;G9E<G-I;VX@:6X@
('!R;V-E<W,@+2!0;&5A<V4@<W1A;F0@8GG)#" Z($1A
('1A($9O<FL0(#H@4F5S;W5R8V4@1F]R:Q%#4D,@:6X@
(&9I;&4Z(# P,# 40VAE8VMS=6T@:6X@9FEL93H@,# <
($YO(&-H96-K<W5M('!R97-E;G0@:6X@9FEL9<D40V%L
(&-U;&%T960@0U)#.B P,# P%T-A;&-U;&%T960@0VAE
(&-K<W5M.B P,"%465!%(&]F($%P<&QI8V%T:6]N(&1O
(&-U;65N="!I<SH@)$-214%43U(@;V8@07!P;&EC871I
(&]N(&1O8W5M96YT(&ES.B 14V%V92!D;V-U;65N="!A
(',ZWPY$:7)E8W1O<GD@9G5L;-X)1&ES:R!F=6QLW -)
("]/U!A7<FET92!P<F]T96-T960@9&ES:V5T=&73"T9I
(&QE(&QO8VME9-(-5F]L=6UE(&QO8VME9  +1FEL92!S
('ES=&5M    &    "@  "8\    "    "   #\\  &I
(/    $    4@0  $X$   $R  !.' !<    ' $R  A"
($Y(6    $I)0TXC    5D92148   !B0DY$3    &Y-
($5.50 ! 'I$3$]'  , DD1)5$P  P#"5TE.1    /)#
($]$10 ! /X  /__        3=@ @/__    '   3=0 
((#__P   2   $W0 (#__P   2L  $W,  +__P   7@ 
( !-Q  !__\   %+  !-R  $__\   0)  !-J  #__\ 
(  #>   3;   O__   #,0  3;@  ?__   "$@  3<  
( 3__P  !"(  $VD  /__P   Y$  $VL  +__P   TH 
( !-M  !__\   (K  !-O  !__\   2V  !-H   __\@
$P 390  39@  ?__-  $S0  39P
***END OF DATA
***CRC:609E

!!ChuquiCo!!Software!!
echo x - README
cat >README <<'!!ChuquiCo!!Software!!'
This directory contains the following files:


BinHex.hex -- binhex version of binhex. This should be converted by xbin
into a .rsrc file and downloaded to the mac. It can be used to convery
binhex format files to their component parts on the mac and to generate
binhex format files for uploading to unix and transport through the net.

README - this file

README.xbin - description of the xbin program.

fromhexu.c - unix based program to decode .dl (an alternate form of network
transmission) format files into .rsrc files for downloading. It is a
filter, use it in the form 'fromhexu <file.dl >file.rsrc'

macget.c- unix side of the download program. Set up macterminal to be an 8
bit path, no XON/XOFF, and that the computer on the other side is another
Mac and then type macget on unix. Use the mouse to
execute 'send file' from the 'File' menu. by default macget will get all
three parts of the file (data, rsrc and info), but the -d -r and -i flags 
override that. The -u flag is used to download a text file (.data part)
while doing neccessary translation of \r to \n to make it useful on a unix
site.

macput.c- unix side of the upload program. Same setup and option flags as
macget, simply type 'macput <file>' to start, and macterminal will
recognize it automatically.  'macput -u <file>' will do carriage return
mapping from unix to the mac for you.

tohexu.c - opposite of fromhexu. takes a .rsrc file and converts it to a
.dl format for transmission.

xbin.c - converts a BinHex format file to the component parts on the unix
end. Equivalent to BinHex on the Macintosh end-- useful for bootstrapping
BinHex to the Mac and doing the conversions before downloading (which
shrinks the files somewhat).

!!ChuquiCo!!Software!!
echo x - README.xbin
cat >README.xbin <<'!!ChuquiCo!!Software!!'
This program will convert a file in BinHex format
into binary files suitable for downloading via
Macterminal / macput from a un*x host.  It creates
all three forks (.info, .data, and .rsrc), so that
the filetype, author, create/modify times and eventually
the file flags (ie the Bundle Bit) are all passed on
to MacTerminal when the file is created on the Mac.

When you receive a BinHex file in the mail or news,
save the message in a file with extension ".hex" --
for example "freeware.hex".  Then invoke "xbin freeware".
This reads freeware.hex and creates freeware.data,
freeware.rsrc, and freeware.info.  When this is done,
you can download through MacTerminal by running
"macput freeware".

The compressed data format is almost identical to
that used by uuencode/uudecode.  They both store 6
bits of data per byte, both offset the binary data
by 0x20 (' '), and both have the number of bytes in
the record at the beginning of each record.  The
difference is exactly 2 bits.  In uuencode format
the first byte contains the entire (6 bit) byte count,
but in BinHex format the byte count is 8 bits -- 6 from
the first byte, and 2 from the second.

Note that the problem of trailing spaces has been worked
around in this program -- short buffers are filled out
with spaces as needed.  So there is no need to manually
restore lost spaces as before.

As soon as I can figure out how the crc is computed
I will post a new version of xbin which actually verifies
the crc value.  For now the crc line is ignored completely.
Given the crc formula, it will be straightforward to write
the complementary encoding program.  How about calling it bhex?

As usual, I'm open to suggestions and bug reports.  I hope
this will save a lot of people the trouble I went through
to figure out the format . . . enjoy!

	Dave Johnson
	Brown University Computer Science
	ddj%brown@csnet-relay.ARPA
	{ihnp4,decvax,allegra,linus}!brunix!ddj
!!ChuquiCo!!Software!!
echo x - fromhexu.c
cat >fromhexu.c <<'!!ChuquiCo!!Software!!'
/* fromhex.c, UNIX version */

#include <stdio.h>

int bytes,sum;

main()
{
	register i,v;
	register n;

	n = 0;
	v = 0;
	while ((i = getchar()) != EOF) {
		i &= 0177;
		if (i == '|') 
			break;
		if (i < 0100 || i > 0117)
			continue;
		v = (v << 4) | (i & 0xF);
		if ((++n & 1) == 0) {
			putchar(v);
			sum += v;
			v = 0;
			bytes++;
		}
	}
	n = 0;
	for (i = 0 ; i < 8 ; i++)
		n = (n << 4) | (getchar() & 0xF);
	if (n != (bytes + sum))
		fprintf(stderr, "bad checksum\n");
	else
		fprintf(stderr, "checksum good!\n");
	exit(0);
}
!!ChuquiCo!!Software!!
echo x - macget.c
cat >macget.c <<'!!ChuquiCo!!Software!!'
#include <stdio.h>
#include <signal.h>
#include <setjmp.h>
#include <sgtty.h>

#ifdef NO_RENAME
#define rename(old, new)	link(old, new); unlink(old)
#endif

/* Mac time of 00:00:00 GMT, Jan 1, 1970 */
#define TIMEDIFF 0x7c25b080

#define RECORDBYTES 132
#define DATABYTES 128
#define NAMEBYTES 63

#define RETRIES 10
#define SOHTIMO 10
#define LINTIMO 20
#define CHRTIMO 2

#define MAXRECNO 0xff
#define BYTEMASK 0xff

#define TMO -1
#define DUP '\000'
#define SOH '\001'
#define EOT '\004'
#define ACK '\006'
#define NAK '\025'
#define CAN '\030'
#define EEF '\032'
#define ESC '\033'

#define H_NLENOFF 1
#define H_NAMEOFF 2
/* 65 <-> 80 is the FInfo structure */
#define H_TYPEOFF 65
#define H_AUTHOFF 69

#define H_LOCKOFF 81
#define H_DLENOFF 83
#define H_RLENOFF 87
#define H_CTIMOFF 91
#define H_MTIMOFF 95

#define H_OLD_DLENOFF 81
#define H_OLD_RLENOFF 85

#define TEXT 0
#define DATA 1
#define RSRC 2
#define FULL 3

int mode, txtmode;
int pre_beta;	/* -o flag; for compatibility with MacTerminal Version -0.15X */

struct macheader {
	char m_name[NAMEBYTES+1];
	char m_type[4];
	char m_author[4];
	long m_datalen;
	long m_rsrclen;
	long m_createtime;
	long m_modifytime;
} mh;

struct filenames {
	char f_info[256];
	char f_data[256];
	char f_rsrc[256];
} files;

char tmpname[16];

int lastack;
char buf[DATABYTES];

/*
 * macget -- receive file from macintosh using xmodem protocol
 * Dave Johnson, Brown University Computer Science
 *
 * (c) 1984 Brown University 
 * may be used but not sold without permission
 *
 * created ddj 5/22/84 
 * revised ddj 6/29/84 -- added [-rdu] options
 * revised ddj 7/16/84 -- protocol changes for MacTerminal Beta Version 0.5X
 * revised ddj 7/31/84 -- pre-4.2 signal bugs fixed in timedout()
 * revised ddj 11/7/84 -- renamed send_sync() -> get_sync()
 */
char usage[] = "usage: \"macget [-o] [-rdu] [filename]\"\n";

main(ac, av)
char **av;
{
	char *name;

	mode = FULL;
	name = "";
	ac--; av++;
	while (ac) {
		if (av[0][0] == '-') {
			switch (av[0][1]) {
			case 'r':
				mode = RSRC;
				break;
			case 'd':
				mode = DATA;
				break;
			case 'u':
				mode = TEXT;
				break;
			case 'o':
				pre_beta++;
				break;
			default:
				fprintf(stderr, usage);
				exit(1);
			}
		}
		else {
			name = av[0];
		}
		ac--; av++;
	}

	setup_tty();
	if (get_sync() == ACK) {
		txtmode = 0;
		recv_hdr(name);
		if (mode == TEXT) txtmode++;
		recv_file(files.f_data, mh.m_datalen, 1);
		txtmode = 0;
		recv_file(files.f_rsrc, mh.m_rsrclen, 0);
	}
	reset_tty();
}

recv_hdr(name)
char *name;
{
	long get4();
	int n;
	FILE *fp;
	char *np;

	strcpy(tmpname, "#machdrXXXXXX");
	mktemp(tmpname);
	recv_file(tmpname, (long)DATABYTES, 1);

	fp = fopen(tmpname, "r");
	if (fp == NULL) {
		perror("temp file");
		cleanup(-1);
	}
	fread(buf, 1, DATABYTES, fp);
	fclose(fp);

	if (name && *name) {
		n = strlen(name);
		if (n > NAMEBYTES) n = NAMEBYTES;
		strncpy(mh.m_name, name, n);
		mh.m_name[n] = '\0';
	}
	else {
		n = buf[H_NLENOFF] & BYTEMASK;
		if (n > NAMEBYTES) n = NAMEBYTES;
		strncpy(mh.m_name, buf + H_NAMEOFF, n);
		mh.m_name[n] = '\0';
	}
	for (np = mh.m_name; *np; np++)
		if (*np == ' ') *np = '_';

	if (mode == FULL) {
		sprintf(files.f_info, "%s.info", mh.m_name);
		rename(tmpname, files.f_info);
		tmpname[0] = '\0';
		sprintf(files.f_data, "%s.data", mh.m_name);
		sprintf(files.f_rsrc, "%s.rsrc", mh.m_name);
	}
	else {
		unlink(tmpname);
		tmpname[0] = '\0';
		switch (mode) {
		case RSRC:
			sprintf(files.f_data, "/dev/null");
			sprintf(files.f_rsrc, "%s.rsrc", mh.m_name);
			break;

		case DATA:
			sprintf(files.f_data, "%s.data", mh.m_name);
			sprintf(files.f_rsrc, "/dev/null");
			break;

		case TEXT:
			sprintf(files.f_data, "%s.text", mh.m_name);
			sprintf(files.f_rsrc, "/dev/null");
			break;
		}
	}

	strncpy(mh.m_type, buf + H_TYPEOFF, 4);
	strncpy(mh.m_author, buf + H_AUTHOFF, 4);
	if (pre_beta) {
		mh.m_datalen = get4(buf + H_OLD_DLENOFF);
		mh.m_rsrclen = get4(buf + H_OLD_RLENOFF);
	}
	else {
		mh.m_datalen = get4(buf + H_DLENOFF);
		mh.m_rsrclen = get4(buf + H_RLENOFF);
		mh.m_createtime = get4(buf + H_CTIMOFF);
		mh.m_modifytime = get4(buf + H_MTIMOFF);
	}
}

recv_file(fname, bytes, more)
char *fname;
long bytes;
int more;
{
	register int status, n;
	FILE *outf;
	int naks = 0;

	lastack = 0;
	outf = fopen(fname, "w");
	if (outf == NULL) {
		perror(fname);
		cleanup(-1);
	}
	for (;;) {
		status = rec_read(buf, DATABYTES);
		switch (status) {
		case EOT:
			if (!pre_beta)
				tputc(ACK);
			if (more)
				tputc(NAK);
			fclose(outf);
			return;
		case ACK:
			tputc(ACK);
			naks = 0;
			n = (bytes > DATABYTES) ? DATABYTES : bytes;
			bytes -= n;
			fwrite(buf, n, 1, outf);
			break;
		case DUP:
			tputc(ACK);
			naks = 0;
			break;
		case NAK:
			purge(CHRTIMO);
			if (naks++ < RETRIES) {
				tputc(NAK);
				break;
			}
			/* fall through */
		case CAN:
			tputc(CAN);
			fclose(outf);
			/* unlink fname? */
			cleanup(-1);
			/* NOTREACHED */
		}
	}
}

get_sync()
{
	int c;

	for (;;) {
		c = tgetc(60);
		switch (c) {
		case ESC:
			break;
		case CAN:
		case EOT:
		case TMO:
			return c;
		default:
			continue;
		}
		c = tgetc(1);
		if (c != 'a')
			continue;
		tputc(ACK);
		return ACK;
	}
}

rec_read(buf, recsize)
char buf[];
int recsize;
{
	int c, rec, rec_bar, cksum;

	c = tgetc(SOHTIMO);
	switch (c) {
	case TMO:
	default:
		return NAK;
	case EOT:
		return EOT;
	case CAN:
		return CAN;
	case SOH:
		/* read header */
		rec = tgetc(CHRTIMO);
		if (rec == TMO)
			return NAK;
		rec_bar = tgetc(CHRTIMO);
		if (rec_bar == TMO)
			return NAK;

		/* check header */
		if (rec != MAXRECNO - rec_bar) return NAK;

		/* fill buffer */
		cksum = tgetrec(buf, recsize, LINTIMO);
		if (cksum == TMO)
			return NAK;

		/* get checksum */
		c = tgetc(CHRTIMO);
		if (c == TMO)
			return NAK;
		if (c != (cksum & BYTEMASK))
			return NAK;

		/* check record number */
		if (rec == lastack)
			return DUP;
		if (rec != ((lastack + 1) & MAXRECNO))
			return CAN;
		else {
			lastack = rec;
			return ACK;
		}
	}
	/* NOTREACHED */
}

purge(timeout)
int timeout;
{
	int c;

	do {
		c = tgetc(timeout);
	} while (c != TMO);
}

static int ttyfd;
static FILE *ttyf;
jmp_buf timobuf;

tgetrec(buf, count, timeout)
char *buf;
int count, timeout;
{
	char *bp;
	int i, cksum;

	if (setjmp(timobuf))
		return TMO;
	
	alarm(timeout);
	i = fread(buf, 1, count, ttyf);
	alarm(0);
	if (i != count)
		return TMO;
	
	cksum = 0;
	bp = buf;
	for (i = 0; i < count; bp++, i++) {
		cksum += *bp;
		if (txtmode && *bp == '\r')
			*bp = '\n';
	}
	return cksum;
}

tgetc(timeout)
int timeout;
{
	int c;

	if (setjmp(timobuf))
		return TMO;

	alarm(timeout);
	c = getc(ttyf);
	alarm(0);

	if (c == -1)	/* probably hung up or logged off */
		return EOT;
	else
		return c & BYTEMASK;
}

tputc(c)
char c;
{
	write(ttyfd, &c, 1);
}

timedout()
{
	signal(SIGALRM, timedout);	/* for pre-4.2 systems */
	longjmp(timobuf, 1);
}

static struct sgttyb otty, ntty;
/* should turn messages off */

setup_tty()
{
	int cleanup();
	int timedout();

	ttyf = stdin;
	ttyfd = fileno(stdout);
	ioctl(ttyfd, TIOCGETP, &otty);
	signal(SIGHUP, cleanup);
	signal(SIGINT, cleanup);
	signal(SIGQUIT, cleanup);
	signal(SIGTERM, cleanup);
	signal(SIGALRM, timedout);
	ntty = otty;
	ntty.sg_flags = RAW|ANYP;
	ioctl(ttyfd, TIOCSETP, &ntty);
}

reset_tty()
{
	sleep(2);	/* should wait for output to drain */
	ioctl(ttyfd, TIOCSETP, &otty);
}

cleanup(sig)
int sig;
{
	if (tmpname[0] != '\0')
		unlink(tmpname);
	reset_tty();
	exit(sig);
}

long
get4(bp)
char *bp;
{
	register int i;
	long value = 0;

	for (i = 0; i < 4; i++) {
		value <<= 8;
		value |= (*bp & BYTEMASK);
		bp++;
	}
	return value;
}
!!ChuquiCo!!Software!!
echo x - macput.c
cat >macput.c <<'!!ChuquiCo!!Software!!'
/*

Here is the source for the current incarnation of macput . . . .
It is now compatible with the 0.5 Beta version of MacTerminal, and
in case you still need to use the -0.15X version, there's the "-o"
option to provide compatibility.  Some minor bug fixes have been
made, as well as a couple of changes for portability to non-4.2 
systems.  Please pass any improvements/bug fixes on to me, and
if you know of any good protocols for use on a flow-controlled
line, let me know.

	Dave Johnson
	ddj%brown@csnet-relay.arpa
	Brown University Computer Science

*/
#include <stdio.h>
#include <signal.h>
#include <setjmp.h>
#include <sgtty.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/timeb.h>

/* Mac time of 00:00:00 GMT, Jan 1, 1970 */
#define TIMEDIFF 0x7c25b080

#define RECORDBYTES 132
#define DATABYTES 128
#define NAMEBYTES 63

#define RETRIES 10
#define ACKTIMO 10

#define MAXRECNO 0xff
#define BYTEMASK 0xff

#define TMO -1
#define DUP '\000'
#define SOH '\001'
#define EOT '\004'
#define ACK '\006'
#define NAK '\025'
#define CAN '\030'
#define EEF '\032'
#define ESC '\033'

#define H_NLENOFF 1
#define H_NAMEOFF 2
/* 65 <-> 80 is the FInfo structure */
#define H_TYPEOFF 65
#define H_AUTHOFF 69

#define H_LOCKOFF 81
#define H_DLENOFF 83
#define H_RLENOFF 87
#define H_CTIMOFF 91
#define H_MTIMOFF 95

#define H_OLD_DLENOFF 81
#define H_OLD_RLENOFF 85

#define TEXT 0
#define DATA 1
#define RSRC 2
#define FULL 3

int mode, txtmode;
int pre_beta;	/* -o flag; for compatibility with MacTerminal Version -0.15X */

struct macheader {
	char m_name[NAMEBYTES+1];
	char m_type[4];
	char m_author[4];
	long m_datalen;
	long m_rsrclen;
	long m_createtime;
	long m_modifytime;
} mh;

struct filenames {
	char f_info[256];
	char f_data[256];
	char f_rsrc[256];
} files;

int recno;
char buf[DATABYTES];

/*
 * macput -- send file to macintosh using xmodem protocol
 * Dave Johnson, Brown University Computer Science
 *
 * (c) 1984 Brown University 
 * may be used but not sold without permission
 *
 * created ddj 6/17/84 
 * revised ddj 7/16/84 -- protocol changes for MacTerminal Beta Version 0.5X
 * revised ddj 7/31/84 -- pre-4.2 signal bugs fixed in timedout()
 * revised ddj 7/31/84 -- fixed timeout problem in initial handshake
 */
char usage[] =
    "usage: \"macput [-o] [-rdu] [-t type] [-a author] [-n name] filename\"\n";

main(ac, av)
char **av;
{
	int n;
	char *filename;

	if (ac == 1) {
		fprintf(stderr, usage);
		exit(1);
	}

	mode = FULL;
	ac--; av++;
	while (ac) {
		if (av[0][0] == '-') {
			switch (av[0][1]) {
			case 'r':
				mode = RSRC;
				strncpy(mh.m_type, "APPL", 4);
				strncpy(mh.m_author, "CCOM", 4);
				break;
			case 'u':
				mode = TEXT;
				strncpy(mh.m_type, "TEXT", 4);
				strncpy(mh.m_author, "MACA", 4);
				break;
			case 'd':
				mode = DATA;
				strncpy(mh.m_type, "TEXT", 4);
				strncpy(mh.m_author, "????", 4);
				break;
			case 'n':
				if (ac > 1) {
					ac--; av++;
					n = strlen(av[0]);
					if (n > NAMEBYTES) n = NAMEBYTES;
					strncpy(mh.m_name, av[0], n);
					mh.m_name[n] = '\0';
					break;
				}
				else goto bad_usage;
			case 't':
				if (ac > 1) {
					ac--; av++;
					strncpy(mh.m_type, av[0], 4);
					break;
				}
				else goto bad_usage;
			case 'a':
				if (ac > 1) {
					ac--; av++;
					strncpy(mh.m_author, av[0], 4);
					break;
				}
				else goto bad_usage;
			case 'o':
				pre_beta++;
				break;
			default:
bad_usage:
				fprintf(stderr, usage);
				exit(1);
			}
		}
		else {
			filename = av[0];
		}
		ac--; av++;
	}

	setup_tty();
	find_files(filename, mode);
	if (mode != FULL)
		forge_info();

	if (send_sync() == ACK) {
		txtmode = 0;
		sleep(1);
		send_file(files.f_info, 1);

		if (mode != FULL)
			unlink(files.f_info);

		if (mode == TEXT) txtmode++;
		send_file(files.f_data, 1);

		txtmode = 0;
		send_file(files.f_rsrc, 0);
	}
	reset_tty();
}

find_files(filename, mode)
char *filename;
{
	int n, tdiff;
	struct tm *tp;
	struct timeb tbuf;
	struct stat stbuf;

	sprintf(files.f_data, "%s.data", filename);
	sprintf(files.f_rsrc, "%s.rsrc", filename);

	if (mode == FULL) {
		sprintf(files.f_info, "%s.info", filename);
		if (stat(files.f_info, &stbuf) != 0) {
			perror(files.f_info);
			cleanup(-1);
		}
		return;
	}
	else {
		strcpy(files.f_info, "#machdrXXXXXX");
		mktemp(files.f_info);
	}

	if (mode == RSRC) {
		strcpy(files.f_data, "/dev/null");
		if (stat(files.f_rsrc, &stbuf) != 0) {
			strcpy(files.f_rsrc, filename);
			if (stat(files.f_rsrc, &stbuf) != 0) {
				perror(files.f_rsrc);
				cleanup(-1);
			}
		}
		mh.m_datalen = 0;
		mh.m_rsrclen = stbuf.st_size;
	}
	else {
		strcpy(files.f_rsrc, "/dev/null");
		if (stat(files.f_data, &stbuf) != 0) {
			sprintf(files.f_data, "%s.text", filename);
			if (stat(files.f_data, &stbuf) != 0) {
				strcpy(files.f_data, filename);
				if (stat(files.f_data, &stbuf) != 0) {
					perror(files.f_data);
					cleanup(-1);
				}
			}
		}
		mh.m_datalen = stbuf.st_size;
		mh.m_rsrclen = 0;
	}

	if (!pre_beta) {
		ftime(&tbuf);
		tp = localtime(&tbuf.time);
		tdiff = TIMEDIFF - tbuf.timezone * 60;
		if (tp->tm_isdst)
			tdiff += 60 * 60;
		mh.m_createtime = stbuf.st_mtime + tdiff;
		mh.m_modifytime = stbuf.st_mtime + tdiff;
	}

	if (mh.m_name[0] == '\0') {
		n = strlen(filename);
		if (n > NAMEBYTES) n = NAMEBYTES;
		strncpy(mh.m_name, filename, n);
		mh.m_name[n] = '\0';
	}
}

forge_info()
{
	int n;
	char *np;
	FILE *fp;

	for (np = mh.m_name; *np; np++)
		if (*np == '_') *np = ' ';

	buf[H_NLENOFF] = n = np - mh.m_name;
	strncpy(buf + H_NAMEOFF, mh.m_name, n);
	strncpy(buf + H_TYPEOFF, mh.m_type, 4);
	strncpy(buf + H_AUTHOFF, mh.m_author, 4);
	if (pre_beta) {
		put4(buf + H_OLD_DLENOFF, mh.m_datalen);
		put4(buf + H_OLD_RLENOFF, mh.m_rsrclen);
	}
	else {
		put4(buf + H_DLENOFF, mh.m_datalen);
		put4(buf + H_RLENOFF, mh.m_rsrclen);
		put4(buf + H_CTIMOFF, mh.m_createtime);
		put4(buf + H_MTIMOFF, mh.m_modifytime);
	}
	fp = fopen(files.f_info, "w");
	if (fp == NULL) {
		perror("temp file");
		cleanup(-1);
	}
	fwrite(buf, 1, DATABYTES, fp);
	fclose(fp);
}

send_sync()
{
	int c, i;

	for (i = 0; i < 3; i++) {
		tputc(ESC);
		tputc('a');
		while ((c = tgetc(ACKTIMO)) != TMO) {
			switch (c) {
			case CAN:
			case EOT:
			case ACK:
				return c;
			default:
				continue;
			}
		}
		fprintf(stderr, "starting handshake timeout\r\n");
	}
	fprintf(stderr, "giving up\r\n");
	return CAN;
}

send_file(fname, more)
char *fname;
int more;
{
	register int status, i, n;
	FILE *inf;

	inf = fopen(fname, "r");
	if (inf == NULL) {
		perror(fname);
		cleanup(-1);
	}
	recno = 1;
	for (;;) {
		n = fread(buf, 1, DATABYTES, inf);
		if (n > 0) {
			for (i = 0; i < RETRIES; i++) {
				send_rec(buf, DATABYTES);
				status = tgetc(ACKTIMO);
				if (status != NAK)
					break;
			} 
			if (status == NAK || status == CAN) {
				fclose(inf);
				cleanup(-1);
				/* NOTREACHED */
			}
		}
		if (n < DATABYTES) {
			tputc(EOT);
			if (!pre_beta) {
				status = tgetc(ACKTIMO);
			}
			if (more) {
				status = tgetc(ACKTIMO);
			}
			return;
		}
		recno++;
		recno &= MAXRECNO;
	}
}

send_rec(buf, recsize)
char buf[];
int recsize;
{
	int i, cksum;
	char *bp;

	cksum = 0;
	bp = buf;
	for (i = 0; i < recsize; i++, bp++) {
		if (txtmode && *bp == '\n')
			*bp = '\r';
		cksum += *bp;
	}

	tputc(SOH);
	tputc((char)recno);
	tputc((char)(MAXRECNO - recno));
	tputrec(buf, recsize);
	tputc((char)cksum);
}

static int ttyfd;
static FILE *ttyf;
static jmp_buf timobuf;

tgetc(timeout)
int timeout;
{
	int c;

	if (setjmp(timobuf))
		return TMO;

	alarm(timeout);
	c = getc(ttyf);
	alarm(0);

	if (c == -1)	/* probably hung up or logged off */
		return EOT;
	else
		return c & BYTEMASK;
}

tputrec(buf, count)
char *buf;
int count;
{
	write(ttyfd, buf, count);
}

tputc(c)
char c;
{
	write(ttyfd, &c, 1);
}

timedout()
{
	signal(SIGALRM, timedout);	/* for pre-4.2 systems */
	longjmp(timobuf, 1);
}

static struct sgttyb otty, ntty;
/* should turn messages off */

setup_tty()
{
	int cleanup();
	int timedout();

	ttyf = stdin;
	ttyfd = fileno(stdin);
	ioctl(ttyfd, TIOCGETP, &otty);
	signal(SIGHUP, cleanup);
	signal(SIGINT, cleanup);
	signal(SIGQUIT, cleanup);
	signal(SIGTERM, cleanup);
	signal(SIGALRM, timedout);
	ntty = otty;
	ntty.sg_flags = RAW|ANYP;
	ioctl(ttyfd, TIOCSETP, &ntty);
}

reset_tty()
{
	if (ttyf != NULL) {
		sleep(2);	/* should wait for output to drain */
		ioctl(ttyfd, TIOCSETP, &otty);
	}
}

cleanup(sig)
int sig;
{
	reset_tty();
	exit(sig);
}

put4(bp, value)
char *bp;
long value;
{
	register int i, c;

	for (i = 0; i < 4; i++) {
		c = (value >> 24) & BYTEMASK;
		value <<= 8;
		*bp++ = c;
	}
}
!!ChuquiCo!!Software!!
echo x - tohexu.c
cat >tohexu.c <<'!!ChuquiCo!!Software!!'
#include <stdio.h>

char hex[] = "@ABCDEFGHIJKLMNO";
int bytes,sum;
unsigned long htonl();

main(argc,argv)
	char **argv;
{
	register i,len;
	register char *cp;

	len = 0;
	while ((i = getchar()) != EOF) {
		bytes++;
		sum += i;
		putchar(hex[i>>4]);
		putchar(hex[i&0xF]);
		if (++len > 32) {
			putchar('\n');
			len = 0;
		}
	}
	fprintf(stderr, "bytes %d, sum %d\n", bytes, sum);
	putchar('|');
	sum += bytes;
	sum = htonl(sum);
	cp = (char *)&sum;
	for (len = 0 ; len < 4 ; len++) {
		i = (*cp++ & 0xff);
		putchar(hex[i>>4]);
		putchar(hex[i&0xF]);
	}
	putchar('\n');
	exit(0);
}

#define nohtonl
#ifdef nohtonl	/* if not in library */
/*
 * "Host" to "net" byte order swappers.
 */
unsigned short htons(a)
	unsigned short a;
{
	unsigned short result;
	register char *sp = (char *)&a;
	register char *dp = (char *)&result;

	dp[1] = *sp++;
	dp[0] = *sp;
	return (result);
}


unsigned long htonl(a)
	unsigned long a;
{
	unsigned long result;
	register char *sp = (char *)&a;
	register char *dp = (char *)&result;

	dp[3] = *sp++;
	dp[2] = *sp++;
	dp[1] = *sp++;
	dp[0] = *sp;
	return (result);
}
#endif
!!ChuquiCo!!Software!!
echo x - xbin.c
cat >xbin.c <<'!!ChuquiCo!!Software!!'
#include <stdio.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/timeb.h>

/* Mac time of 00:00:00 GMT, Jan 1, 1970 */
#define TIMEDIFF 0x7c25b080

#define DATABYTES 128

#define BYTEMASK 0xff

#define NAMEBYTES 63
#define H_NLENOFF 1
#define H_NAMEOFF 2

/* 65 <-> 80 is the FInfo structure */
#define H_TYPEOFF 65
#define H_AUTHOFF 69
#define H_FLAGOFF XXX

#define H_LOCKOFF 81
#define H_DLENOFF 83
#define H_RLENOFF 87
#define H_CTIMOFF 91
#define H_MTIMOFF 95

#define H_OLD_DLENOFF 81
#define H_OLD_RLENOFF 85

struct macheader {
	char m_name[NAMEBYTES+1];
	char m_type[4];
	char m_author[4];
	long m_flags;
	long m_datalen;
	long m_rsrclen;
	long m_createtime;
	long m_modifytime;
} mh;

struct filenames {
	char f_info[256];
	char f_data[256];
	char f_rsrc[256];
} files;

FILE *ifp;
int pre_beta;
int compressed;

/*
 * xbin -- unpack BinHex style .HEX file into suitable
 * format for downloading with macput
 * Dave Johnson, Brown University Computer Science
 *
 * (c) 1984 Brown University
 * may be used but not sold without permission
 *
 * created ddj 12/16/84
 */
char usage[] = "usage: \"xbin [-o] [-n name] filename\"\n";

main(ac, av)
char **av;
{
	char *filename, *macname;

	filename = ""; macname = "";
	ac--; av++;
	while (ac) {
		if (av[0][0] == '-') {
			switch (av[0][1]) {
			case 'o':
				pre_beta++;
				break;
			case 'n':
				if (ac > 1) {
					ac--; av++;
					macname = av[0];
					break;
				}
				else
					goto bad_usage;
			default:
				goto bad_usage;
			}
		}
		else {
			if (*filename == '\0')
				filename = av[0];
			else
				goto bad_usage;
		}
		ac--; av++;
	}
	if (*filename == '\0') {
bad_usage:
		fprintf(stderr, usage);
		exit(1);
	}

	setup_files(filename, macname);
	parse_file();
	forge_info();	/* now that we know the size of the forks */
}

setup_files(filename, macname)
char *filename;		/* input file name -- .hex extension optional */
char *macname;		/* name to use on the mac side of things */
{
	char namebuf[256];
	int n, tdiff;
	struct tm *tp;
	struct timeb tbuf;
	struct stat stbuf;

	/* find input .hex file and open it */
	sprintf(namebuf, "%s.hex", filename);
	if (stat(namebuf, &stbuf) != 0) {
		strcpy(namebuf, filename);
		if (stat(namebuf, &stbuf) != 0) {
			perror(namebuf);
			exit(-1);
		}
	}
	ifp = fopen(namebuf, "r");
	if (ifp == NULL) {
		perror(namebuf);
		exit(-1);
	}

	/* set up names for output files and create them */
	if (macname[0] == '\0') {
		macname = filename;
	}
	n = strlen(macname);
	if (n > NAMEBYTES) n = NAMEBYTES;
	strncpy(mh.m_name, macname, n);
	mh.m_name[n] = '\0';

	sprintf(files.f_data, "%s.data", mh.m_name);
	close(creat(files.f_data, 0666));
	sprintf(files.f_rsrc, "%s.rsrc", mh.m_name);
	close(creat(files.f_rsrc, 0666));
	sprintf(files.f_info, "%s.info", mh.m_name);
	/* info file gets created later */

	/* get file times and convert to mac time format */
	ftime(&tbuf);
	tp = localtime(&tbuf.time);
	tdiff = TIMEDIFF - tbuf.timezone * 60;
	if (tp->tm_isdst)
		tdiff += 60 * 60;

	mh.m_createtime = stbuf.st_mtime + tdiff;
	mh.m_modifytime = stbuf.st_mtime + tdiff;
}

forge_info()
{
	char buf[DATABYTES];
	char *np;
	FILE *fp;
	int n;

	for (np = mh.m_name; *np; np++)
		if (*np == '_') *np = ' ';

	buf[H_NLENOFF] = n = np - mh.m_name;
	strncpy(buf + H_NAMEOFF, mh.m_name, n);
	strncpy(buf + H_TYPEOFF, mh.m_type, 4);
	strncpy(buf + H_AUTHOFF, mh.m_author, 4);
	/* put4(buf + H_FLAGOFF, mh.m_flag);	XXX */
	if (pre_beta) {
		put4(buf + H_OLD_DLENOFF, mh.m_datalen);
		put4(buf + H_OLD_RLENOFF, mh.m_rsrclen);
	}
	else {
		put4(buf + H_DLENOFF, mh.m_datalen);
		put4(buf + H_RLENOFF, mh.m_rsrclen);
		put4(buf + H_CTIMOFF, mh.m_createtime);
		put4(buf + H_MTIMOFF, mh.m_modifytime);
	}
	fp = fopen(files.f_info, "w");
	if (fp == NULL) {
		perror("info file");
		exit(-1);
	}
	fwrite(buf, 1, DATABYTES, fp);
	fclose(fp);
}

parse_file()
{
	char ibuf[BUFSIZ];
	int compressed = 0;
	int forks = 0;
	int n;

	while (fgets(ibuf, BUFSIZ, ifp) != NULL) {
		n = strlen(ibuf);
		if (n >= 7 && ibuf[0] == '#' || ibuf[n-6] == '$') {
			if (n >= 11)
				strncpy(mh.m_type, &ibuf[1], 4);
			if (n >= 15)
				strncpy(mh.m_author, &ibuf[5], 4);
			sscanf(&ibuf[n-5], "%4x", &mh.m_flags);
			break;
		}
	}
	while (forks < 2 && fgets(ibuf, BUFSIZ, ifp) != NULL) {
		if (forks == 0 && strncmp(ibuf, "***COMPRESSED", 13) == 0) {
			compressed++;
			continue;
		}
		if (strncmp(ibuf, "***DATA", 7) == 0) {
			mh.m_datalen = make_file(files.f_data, compressed);
			forks++;
			continue;
		}
		if (strncmp(ibuf, "***RESOURCE", 11) == 0) {
			mh.m_rsrclen = make_file(files.f_rsrc, compressed);
			forks++;
			continue;
		}
	}
}

static int crc;

make_file(fname, compressed)
char *fname;
int compressed;
{
	register int n;
	char ibuf[BUFSIZ];
	FILE *outf;
	int nbytes = 0;

	outf = fopen(fname, "w");
	if (outf == NULL) {
		perror(fname);
		exit(-1);
	}

	while (fgets(ibuf, BUFSIZ, ifp) != NULL) {
		if (strncmp(ibuf, "***END", 6) == 0)
			break;
		if (compressed)
			nbytes += comp_to_bin(ibuf, outf);
		else
			nbytes += hex_to_bin(ibuf, outf);
	}
	/* XXX read crc record and do crc check */

	return nbytes;
}

#define SIXB(c) (((c)-0x20) & 0x3f)

comp_to_bin(ibuf, outf)
char ibuf[];
FILE *outf;
{
	char obuf[BUFSIZ];
	register char *ip = ibuf;
	register char *op = obuf;
	register int n, outcount;
	int numread, incount;

	numread = strlen(ibuf);
	ip[numread-1] = ' ';		/* zap out the newline */
	outcount = (SIXB(ip[0]) << 2) | (SIXB(ip[1]) >> 4);
	incount = ((outcount / 3) + 1) * 4;
	for (n = numread; n < incount; n++)	/* restore lost spaces */
		ibuf[n] = ' ';

	n = 0;
	while (n <= outcount) {
		*op++ = SIXB(ip[0]) << 2 | SIXB(ip[1]) >> 4;
		*op++ = SIXB(ip[1]) << 4 | SIXB(ip[2]) >> 2;
		*op++ = SIXB(ip[2]) << 6 | SIXB(ip[3]);
		ip += 4;
		n += 3;
	}
	fwrite(obuf+1, 1, outcount, outf);
	return outcount;
}

hex_to_bin(ibuf, outf)
char ibuf[];
FILE *outf;
{
	register char *ip = ibuf;
	register int n, outcount;
	int c;

	n = strlen(ibuf) - 1;
	outcount = n / 2;
	for (n = 0; n < outcount; n++) {
		c = hexit(*ip++);
		c = (c << 4) | hexit(*ip++);
		fputc(c , outf);
	}
	return outcount;
}

hexit(c)
int c;
{
	if ('0' <= c && c <= '9')
		return c - '0';
	if ('A' <= c && c <= 'F')
		return c - 'A' + 10;
}

put4(bp, value)
char *bp;
long value;
{
	register int i, c;

	for (i = 0; i < 4; i++) {
		c = (value >> 24) & BYTEMASK;
		value <<= 8;
		*bp++ = c;
	}
}
!!ChuquiCo!!Software!!
-- 
From the ministry of silly talks:		Chuq Von Rospach
{allegra,cbosgd,decwrl,hplabs,ihnp4,seismo}!nsc!chuqui  nsc!chuqui@decwrl.ARPA

Deadbone erotica is the prickly panic of forgotten milleniums, it is the moldy 
billion year madness that creeps deep along the spinal behind of my mind.