home *** CD-ROM | disk | FTP | other *** search
/ Hall of Fame / HallofFameCDROM.cdr / proglc / zoo141_c.lzh / PORTABLE.C < prev    next >
C/C++ Source or Header  |  1987-02-07  |  20KB  |  687 lines

  1. #include "options.h"
  2. /*
  3. Copyright (C) 1986 Rahul Dhesi -- All rights reserved
  4. */
  5. /**********************
  6. portable.c contains functions needed to make Zoo portable to various
  7. implementations of C.
  8.  
  9. Note:  Provided a 2's complement machine is used, all functions in
  10. this file are themselves machine-independent and need not be changed
  11. when implementing Zoo on a different machine.  Some code will choke
  12. on 1's complement machines--I think.  
  13.  
  14. For machine-dependent declarations see files "machine.h" and "options.h". 
  15.  
  16. For machine-dependent functions see file "machine.c"
  17. */
  18.  
  19. /* See if we could just use these for MSC */
  20. #ifdef MSC
  21. #ifndef PORTABLE
  22. #define PORTABLE
  23. #endif
  24. #endif
  25.  
  26.  
  27. #ifdef PORTABLE
  28. #include <stdio.h>
  29. #include "various.h"
  30. #include "zoofns.h"
  31.  
  32. #include "machine.h"
  33. #include "zoo.h"
  34. #include "debug.h"
  35. #include "assert.h"
  36.  
  37. #ifdef NEEDCTYP
  38. #include <ctype.h>              /* for tolower() */
  39. #endif
  40.  
  41. #ifdef DEBUG
  42. extern int verbose;
  43. #endif
  44.  
  45. /* Functions defined for use within this file only.  */
  46. #ifdef LINT_ARGS
  47. long to_long (BYTE[]);
  48. int to_int (BYTE[]);
  49. void b_to_zooh(struct zoo_header *, BYTE[]);
  50. void b_to_dir(struct direntry *, BYTE[]);
  51. int dir_to_b(BYTE[], struct direntry *);
  52. void zooh_to_b(BYTE[], struct zoo_header *);
  53. void splitlong(BYTE[], long);
  54. void splitint(BYTE[], int);
  55. #else
  56. long to_long ();
  57. int to_int ();
  58. void b_to_zooh();
  59. void b_to_dir();
  60. int dir_to_b();
  61. void zooh_to_b();
  62. void splitlong();
  63. void splitint();
  64. #endif
  65.  
  66. extern unsigned int crccode;
  67.  
  68.  
  69. /************************************************************************/
  70. /*** Following are functions that make up for various implementations ***/
  71. /*** of C not having certain library routines.                        ***/
  72. /************************************************************************/
  73.  
  74. #ifndef MSC
  75. /**********************
  76. strlwr() converts a string to lowercase and returns a pointer to the string 
  77. */
  78. char *strlwr (str)
  79. char *str;
  80. {
  81.    register char *s;
  82.    s = str;
  83.    while (*s != '\0') {
  84.       *s = toascii(*s);
  85.       if (isupper(*s))
  86.          *s = tolower(*s);
  87.       s++;
  88.    }
  89.    return (str);
  90. }
  91.  
  92. #ifdef COMMENT
  93. /**********************
  94. strupr() converts a string to uppercase and returns a pointer to the string
  95. */
  96. char *strupr (str)
  97. char *str;
  98. {
  99.    register char *s;
  100.    s = str;
  101.    while (*s != '\0') {
  102.       *s = toascii(*s);
  103.       if (islower(*s))
  104.          *s = toupper(*s);
  105.       s++;
  106.    }
  107.    return (str);
  108. }
  109. #endif /* COMMENT */
  110.  
  111. /**********************
  112. strcmpi() compares strings just like strcmp() but it does it without regard to
  113. case.
  114. */
  115. int strcmpi (s1, s2)
  116. register char *s1, *s2;
  117. {
  118.    for ( ; tolower(*s1) == tolower(*s2);  s1++, s2++)
  119.       if (*s1 == '\0')
  120.          return(0);
  121.    return(tolower(*s1) - tolower(*s2));
  122. }
  123.  
  124. /**********************
  125. memset() exists in Microsoft C and UNIX System V but not in Xenix.  It sets 
  126. the first "cnt" bytes of "dest" to the character "c" and returns a pointer to
  127. "dest".
  128. */
  129. char *memset (dest, c, cnt)
  130. char *dest;
  131. int c;
  132. unsigned cnt;
  133. {
  134.    register unsigned i;
  135.    for (i = 0; i < cnt; i++) {
  136.       *(dest + i) = c;
  137.    }
  138. }
  139.  
  140. /**********************
  141. fputchar() writes a character to stdout.  It is identical to putchar
  142. but is a function, not a macro.
  143. */
  144. int fputchar (c)
  145. int c;
  146. {
  147.    return (fputc(c, stdout));
  148. }
  149.  
  150. /**********************
  151. tell() returns the current position of the file handle supplied
  152. */
  153. long tell (handle)
  154. int handle;
  155. {
  156.    return (lseek (handle, 0L, 1));     /* seek to current position */
  157. }
  158. #endif /* ifndef MSC */
  159.  
  160.  
  161. /***********************************************************************/
  162. /*** Following are declarations and functions that are written in a  ***/
  163. /*** machine-independent way but they implement machine-dependent    ***/
  164. /*** activities                                                      ***/
  165. /***********************************************************************/
  166.  
  167. #ifndef MSC
  168. /**********************
  169. to_long() converts four consecutive bytes, in order of increasing
  170. significance, to a long integer.  It is used to make Zoo independent of the
  171. byte order of the system.  
  172. */
  173. long to_long(data)
  174. BYTE data[];
  175. {
  176.    return (long) ((unsigned long) data[0] | ((unsigned long) data[1] << 8) |
  177.          ((unsigned long) data[2] << 16) | ((unsigned long) data[3] << 24));
  178. }
  179.  
  180. /********************
  181. splitlong() converts a long integer to four consecutive BYTEs in order
  182. of increasing significance.
  183. */
  184. void splitlong(bytes, bigword)
  185. BYTE bytes[];
  186. long bigword;
  187. {
  188.    int i;
  189.    for (i = 0; i < 4; i++) {
  190.       bytes[i] = bigword & 0xff;
  191.       bigword = (unsigned long) bigword >> 8;
  192.    }
  193. }     
  194.  
  195. /*******************
  196. splitint() converts an integer to two consecutive BYTEs in order
  197. of increasing significance.
  198. */
  199. void splitint(bytes, word)
  200. BYTE bytes[];
  201. int word;
  202. {
  203.    bytes[0] = word & 0xff;
  204.    word = (unsigned int) word >> 8;
  205.    bytes[1] = word & 0xff;
  206. }
  207.  
  208. /**********************
  209. to_int() converts two consecutive bytes, in order of increasing
  210. significance, to an integer, in a machine-independent manner
  211. */
  212. int to_int(data)
  213. BYTE data[];
  214. {
  215.    return (int) ((unsigned int) data[0] | ((unsigned int) data[1] << 8));
  216. }
  217.  
  218. #else /* else of ifndef MSC */
  219.  
  220. long to_long(data)
  221. BYTE data[];
  222. {
  223.    return ( * (long *) data );
  224. }
  225.  
  226. /********************
  227. splitlong() converts a long integer to four consecutive BYTEs in order
  228. of increasing significance.
  229. */
  230. void splitlong(bytes, bigword)
  231. BYTE bytes[];
  232. long bigword;
  233. {
  234.    * (long *) bytes = bigword;
  235. }     
  236.  
  237. /*******************
  238. splitint() converts an integer to two consecutive BYTEs in order
  239. of increasing significance.
  240. */
  241. void splitint(bytes, word)
  242. BYTE bytes[];
  243. int word;
  244. {
  245.    * (int *) bytes = word;
  246. }
  247.  
  248. /**********************
  249. to_int() converts two consecutive bytes, in order of increasing
  250. significance, to an integer.
  251. */
  252. int to_int(data)
  253. BYTE data[];
  254. {
  255.    return (*(int *) data);
  256. }
  257.  
  258. #endif /* ifndef MSC .. else ... */
  259.  
  260.  
  261. #ifndef FIZ
  262. /**********************
  263. Function frd_zooh() reads the header of a Zoo archive in a machine-
  264. independent manner, from a FILE.
  265. */
  266. int frd_zooh(zoo_header, zoo_file)
  267. struct zoo_header *zoo_header;
  268. FILE *zoo_file;
  269. {
  270.    int status;
  271.    BYTE bytes[SIZ_ZOOH];         /* canonical header representation */
  272. #ifdef DEBUG
  273.    if (verbose) {
  274.       printf("At file position [%8lx] ", ftell(zoo_file));
  275.    }
  276. #endif
  277.    status = fread ((char *) bytes, 1, SIZ_ZOOH, zoo_file);
  278.    b_to_zooh (zoo_header, bytes);   /* convert array to structure */
  279. #ifdef DEBUG
  280.    if (verbose) {
  281.       printf("frd_zooh: reading\n");
  282.       show_h(zoo_header);
  283.    }
  284. #endif
  285.    if (status < SIZ_ZOOH)
  286.       return (-1);
  287.    else
  288.       return (0);
  289. }
  290. #endif /* ifndef FIZ */
  291.  
  292.  
  293. /**********************
  294. Function frd_dir() reads a directory entry in a machine-independent manner,
  295. from a FILE.
  296. */
  297. int frd_dir(direntry, zoo_file) 
  298. struct direntry *direntry; 
  299. FILE *zoo_file;
  300. {
  301.    int status;
  302.    BYTE bytes[MAXDIRSIZE];    /* big enough to hold variable part too */
  303.  
  304.    /* To simplify things, we read the maximum possible size of the
  305.    directory entry including the variable size and discard what is not
  306.    needed */
  307. #ifdef DEBUG
  308.    if (verbose) {
  309.       printf("At file position [%8lx] ", ftell(zoo_file));
  310.    }
  311. #endif
  312.    status = fread ((char *) bytes, 1, MAXDIRSIZE, zoo_file);
  313.    if (status < SIZ_DIR)
  314.       return (-1);
  315.    b_to_dir (direntry, bytes);
  316. #ifdef DEBUG
  317.    if (verbose) {
  318.       printf("frd_dir: reading\n");
  319.       show_dir(direntry);
  320.    }
  321. #endif
  322.    return (0);
  323. }
  324.  
  325. #ifndef FIZ
  326. /**********************
  327. Function rd_zooh() reads a Zoo archive header in a machine-dependent manner,
  328. from a file handle.
  329. */
  330. int rd_zooh (header, zoo_han)
  331. struct zoo_header *header;
  332. int zoo_han;
  333. {
  334.    int status;
  335.    BYTE bytes[SIZ_ZOOH];
  336. #ifdef DEBUG
  337.    if (verbose) {
  338.       printf("At file position [%8lx] ", tell(zoo_han));
  339.    }
  340. #endif
  341.    status = read (zoo_han, (char *) bytes, SIZ_ZOOH);
  342.    b_to_zooh (header, bytes);
  343. #ifdef DEBUG
  344.    if (verbose) {
  345.       printf("rd_zooh: reading\n");
  346.       show_h(header);
  347.    }
  348. #endif
  349.    return (status);
  350. }
  351.  
  352. /**********************
  353. Function rd_dir() reads a directory entry in a machine-independent manner
  354. from a handle.
  355. */
  356. int rd_dir(direntry, zoo_han)
  357. struct direntry *direntry;
  358. int zoo_han;
  359. {
  360.    int status;
  361.    BYTE bytes[MAXDIRSIZE];    /* big enough to hold variable part too */
  362.    /* To simplify things, we read the maximum possible size of the
  363.    directory entry including the variable size and discard what is not
  364.    needed */
  365. #ifdef DEBUG
  366.    if (verbose) {
  367.       printf("At file position [%8lx] ", tell(zoo_han));
  368.    }
  369. #endif
  370.    status = read (zoo_han, (char *) bytes, MAXDIRSIZE);
  371.    if (status < SIZ_DIR)
  372.       return (-1);
  373.    b_to_dir (direntry, bytes);
  374. #ifdef DEBUG
  375.    if (verbose) {
  376.       printf("rd_dir: reading\n");
  377.       show_dir(direntry);
  378.    }
  379. #endif
  380.    return (0);
  381. }
  382.  
  383. /***********************
  384. Function fwr_dir() writes a directory entry in a machine-independent manner
  385. to a FILE.  Return value is -1 on error, else 0.
  386. */
  387. int fwr_dir(direntry, zoo_file)
  388. struct direntry *direntry;
  389. FILE *zoo_file;
  390. {
  391.    int size;
  392.    BYTE bytes[MAXDIRSIZE];
  393.    assert (direntry->type <= 2);
  394.    size = dir_to_b (bytes, direntry);
  395. #ifdef DEBUG
  396.    if (verbose) {
  397.       printf("At file position [%8lx] ", ftell(zoo_file));
  398.       printf("fwr_dir: writing\n");
  399.       show_dir(direntry);
  400.    }
  401. #endif
  402.  
  403.    if (fwrite ((char *) bytes, 1, size, zoo_file) != size)
  404.       return (-1);
  405.    else
  406.       return (0);
  407. }
  408.  
  409. /***********************
  410. Function wr_dir() writes a directory entry in a machine-independent manner
  411. to a handle.  Return value is -1 on error else 0.
  412. */
  413. int wr_dir(direntry, zoo_han)
  414. struct direntry *direntry;
  415. int zoo_han;
  416. {
  417.    int size;
  418.    BYTE bytes[MAXDIRSIZE];
  419.    assert (direntry->type <= 2);
  420.    size = dir_to_b (bytes, direntry);
  421. #ifdef DEBUG
  422.    if (verbose) {
  423.       printf("At file position [%8lx] ", tell(zoo_han));
  424.       printf("wr_dir:  writing\n");
  425.       show_dir(direntry);
  426.    }
  427. #endif
  428.    if (write (zoo_han, (char *) bytes, size) != size)
  429.       return (-1);
  430.    else
  431.       return (0);
  432. }
  433.  
  434. /***********************
  435. Function wr_zooh() writes an archive header in a machine-independent manner
  436. to a handle.  Return value -1 if error else 0.
  437. */
  438. int wr_zooh(zoo_header, zoo_han)
  439. struct zoo_header *zoo_header;
  440. int zoo_han;
  441. {
  442.    BYTE bytes[SIZ_DIR];
  443.    zooh_to_b (bytes, zoo_header);
  444.    if (write (zoo_han, (char *) bytes, SIZ_ZOOH) != SIZ_ZOOH)
  445.       return (-1);
  446.    else
  447.       return (0);
  448. }
  449.  
  450. /***********************
  451. Function fwr_zooh() writes an archive header in a machine-independent manner
  452. to a FILE.  Return value is -1 if error else 0.
  453. */
  454. int fwr_zooh(zoo_header, zoo_file)
  455. struct zoo_header *zoo_header;
  456. FILE *zoo_file;
  457. {
  458.    BYTE bytes[SIZ_DIR];
  459.    zooh_to_b (bytes, zoo_header);
  460.    if (fwrite ((char *) bytes, 1, SIZ_ZOOH, zoo_file) != SIZ_ZOOH)
  461.       return (-1);
  462.    else
  463.       return (0);
  464. }
  465.  
  466. /***********************
  467. b_to_zooh() converts an array of BYTE to a zoo_header structure.
  468. */
  469. void b_to_zooh (zoo_header, bytes)
  470. struct zoo_header *zoo_header;
  471. BYTE bytes[];
  472. {
  473.    int i;
  474.    for (i = 0; i < SIZ_TEXT; i++)                     /* copy text */
  475.       zoo_header->text[i] = bytes[TEXT_I + i];
  476.    zoo_header->zoo_tag = to_long(&bytes[ZTAG_I]);     /* copy zoo_tag */
  477.    zoo_header->zoo_start = to_long(&bytes[ZST_I]);    /* copy zoo_start */
  478.    zoo_header->zoo_minus = to_long(&bytes[ZSTM_I]);
  479.    zoo_header->major_ver = bytes[MAJV_I];          /* copy versions */
  480.    zoo_header->minor_ver = bytes[MINV_I];
  481. }
  482.  
  483. /***********************
  484. zooh_to_b() converts a zoo_header structure to an array of BYTE.
  485. */
  486. void zooh_to_b (bytes, zoo_header)
  487. struct zoo_header *zoo_header;
  488. BYTE bytes[];
  489. {
  490.    int i;
  491.    for (i = 0; i < SIZ_TEXT; i++)                     /* copy text */
  492.       bytes[TEXT_I + i] = zoo_header->text[i];
  493.    splitlong (&bytes[ZTAG_I], zoo_header->zoo_tag);
  494.    splitlong (&bytes[ZST_I], zoo_header->zoo_start);
  495.    splitlong (&bytes[ZSTM_I], zoo_header->zoo_minus);
  496.    bytes[MAJV_I] =   zoo_header->major_ver;           /* copy versions */ 
  497.    bytes[MINV_I] =   zoo_header->minor_ver;
  498. } /* zooh_to_b() */
  499.  
  500. /************************
  501. dir_to_b() converts a directory entry structure to an array of BYTE.
  502. */
  503. int dir_to_b (bytes, direntry)
  504. struct direntry *direntry;
  505. BYTE bytes[];
  506. {
  507.    int i;
  508.    int cursize;
  509.    int fixsize;
  510.    splitlong(&bytes[DTAG_I], direntry->zoo_tag);
  511.    bytes[DTYP_I] = direntry->type ;
  512.    bytes[PKM_I] = direntry->packing_method ;
  513.    splitlong(&bytes[NXT_I], direntry->next);
  514.    splitlong(&bytes[OFS_I], direntry->offset);
  515.    splitint(&bytes[DAT_I], direntry->date);
  516.    splitint(&bytes[TIM_I], direntry->time);
  517.    splitint(&bytes[CRC_I], direntry->file_crc);
  518.    splitlong(&bytes[ORGS_I], direntry->org_size);
  519.    splitlong(&bytes[SIZNOW_I], direntry->size_now);
  520.    bytes[DMAJ_I] = direntry->major_ver;
  521.    bytes[DMIN_I] = direntry->minor_ver;
  522.    bytes[DEL_I] = direntry->deleted;
  523.    bytes[STRUC_I] = direntry->struc;
  524.    splitlong(&bytes[CMT_I], direntry->comment);
  525.    splitint(&bytes[CMTSIZ_I], direntry->cmt_size);
  526.    for (i = 0; i < FNM_SIZ; i++)
  527.       bytes[FNAME_I + i] = direntry->fname[i];
  528.    bytes[TZ_I] = NO_TZ;       /* assume unknown */
  529.    bytes[NAMLEN_I] = 0;
  530.    bytes[DIRLEN_I] = 0;
  531.  
  532.    cursize = SIZ_DIR;         /* to count size of directory */
  533.    fixsize = SIZ_DIR;         /* size of fixed part */
  534.    assert (direntry->type <= 2);
  535.    if (direntry->type == 2) { /* handle stuff relevant to type 2 */
  536.       cursize = SIZ_DIRL;
  537.       fixsize = SIZ_DIRL;
  538.       bytes[TZ_I] = direntry->tz;
  539.       assert(direntry->namlen < 256 && direntry->namlen >= 0);
  540.       if (direntry->namlen > 0 || direntry->dirlen > 0)
  541.          cursize += 2;        /* space for namlen and dirlen */
  542.       if (direntry->namlen > 0) {
  543.          bytes[NAMLEN_I] = direntry->namlen;
  544.          for (i = 0; i < direntry->namlen; i++)
  545.             bytes[LFNAME_I+i] = direntry->lfname[i];
  546.          cursize += direntry->namlen;
  547.       } 
  548.       assert(direntry->dirlen < 256 && direntry->dirlen >= 0);
  549.       if (direntry->dirlen > 0) {
  550.          bytes[DIRLEN_I] = direntry->dirlen;
  551.          for (i = 0; i < direntry->dirlen; i++)
  552.             bytes[cursize+i] = direntry->dirname[i];
  553.          cursize += direntry->dirlen;
  554.       }
  555.       splitint(&bytes[cursize], direntry->system_id);
  556.    }
  557.  
  558.    /* Total length of directory entry is now cursize. */
  559.    splitint(&bytes[VARDIRLEN_I], cursize - fixsize);
  560.    assert(cursize == 
  561.             ((bytes[DIRLEN_I] > 0 || bytes[NAMLEN_I] > 0) ? 2 : 0) +
  562.             fixsize + bytes[DIRLEN_I] + bytes[NAMLEN_I]
  563.          );
  564.  
  565.    /* Do CRC assuming CRC field is zero, and stuff CRC into field. */
  566.    splitint(&bytes[DCRC_I], 0);           /* fill with zeroes */
  567.    crccode = 0;
  568.    addbfcrc(bytes, cursize);              /* update CRC */
  569.    splitint(&bytes[DCRC_I], crccode);
  570.  
  571.    /* return total length of directory entry */
  572.    return (cursize);
  573.  
  574.  
  575. } /* dir_to_b() */
  576. #endif /* ifndef FIZ */
  577.  
  578. /* b_to_dir() converts bytes to directory entry structure.  The CRC of the
  579. directory bytes, if any, is checked and a zero or nonzero value is returned
  580. in direntry->dir_crc according as the check is good or bad */
  581.  
  582. void b_to_dir(direntry, bytes)
  583. struct direntry *direntry;
  584. BYTE bytes[];
  585. {
  586.    int i;
  587.    unsigned int savecrc;
  588.    direntry->zoo_tag = to_long(&bytes[DTAG_I]);
  589.    direntry->type = bytes[DTYP_I];
  590.    direntry->packing_method = bytes[PKM_I];
  591.    direntry->next = to_long(&bytes[NXT_I]);
  592.    direntry->offset = to_long(&bytes[OFS_I]);
  593.    direntry->date = to_int(&bytes[DAT_I]);
  594.    direntry->time = to_int(&bytes[TIM_I]);
  595.    direntry->file_crc = to_int(&bytes[CRC_I]);
  596.    direntry->org_size = to_long(&bytes[ORGS_I]);
  597.    direntry->size_now = to_long(&bytes[SIZNOW_I]);
  598.    direntry->major_ver = bytes[DMAJ_I];
  599.    direntry->minor_ver = bytes[DMIN_I];
  600.    direntry->deleted = bytes[DEL_I];
  601.    direntry->struc = bytes[STRUC_I];
  602.    direntry->comment = to_long(&bytes[CMT_I]);
  603.    direntry->cmt_size = to_int(&bytes[CMTSIZ_I]);
  604.    for (i = 0; i < FNM_SIZ; i++)
  605.       direntry->fname[i] = bytes[FNAME_I + i];
  606.  
  607.    /* start by assuming variable part is zero bytes */
  608.    direntry->var_dir_len = direntry->dir_crc    = 0;
  609.    direntry->namlen      = direntry->dirlen     = 0;
  610.    direntry->lfname[0]   = direntry->dirname[0] = '\0';
  611.    direntry->tz = NO_TZ;               /* assume unknown */
  612.    direntry->system_id = SYSID_NIX;    /* default system_id if not present */
  613.  
  614.    assert (direntry->type <= 2);
  615.    if (direntry->type == 2) {
  616.       direntry->var_dir_len = to_int(&bytes[VARDIRLEN_I]);
  617.       assert(direntry->var_dir_len <= MAXDIRSIZE);
  618.       if (direntry->var_dir_len > MAXDIRSIZE)
  619.          direntry->var_dir_len = MAXDIRSIZE;
  620.       direntry->tz = bytes[TZ_I];   
  621.       if (direntry->var_dir_len > 0)
  622.          direntry->namlen = bytes[NAMLEN_I];
  623.       if (direntry->var_dir_len > 1)
  624.          direntry->dirlen = bytes[DIRLEN_I];
  625.       for (i = 0; i < direntry->namlen; i++)
  626.          direntry->lfname[i] = bytes[LFNAME_I + i];
  627.       for (i = 0; i < direntry->dirlen; i++)
  628.          direntry->dirname[i] = bytes[DIRNAME_I + direntry->namlen + i];
  629.       if (direntry->var_dir_len > direntry->namlen + direntry->dirlen + 2) {
  630.          direntry->system_id = to_int(&bytes[DIRNAME_I+direntry->namlen+i]);
  631.       }
  632.       /* do CRC calculation */
  633.       savecrc = (unsigned int) to_int(&bytes[DCRC_I]);
  634.       crccode = 0;
  635.       splitint(&bytes[DCRC_I], 0);
  636.       addbfcrc(bytes, SIZ_DIRL + direntry->var_dir_len);
  637.       direntry->dir_crc = crccode - savecrc;
  638.    }
  639. }
  640.  
  641. #ifdef DEBUG
  642. /* dump contents of archive header */
  643. show_h (zoo_header)
  644. struct zoo_header *zoo_header;
  645. {
  646.    int i;
  647.    printf ("Header text:\n");
  648.    for (i = 0; i < SIZ_TEXT-1;  i++)   /* all but trailing ^Z */
  649.       putchar(zoo_header->text[i]);
  650.    putchar('\n');
  651.    printf ("zoo_tag = [%8lx] zoo_start = [%8lx] zoo_minus = [%8lx]\n",
  652.             zoo_header->zoo_tag, zoo_header->zoo_start, 
  653.             zoo_header->zoo_minus);
  654.    printf ("major_ver.minor_ver = [%d.%d]\n",
  655.             zoo_header->major_ver, zoo_header->minor_ver);
  656.    printf ("---------\n");
  657. }
  658.  
  659. /* dump contents of directory entry */
  660. show_dir (direntry)
  661. struct direntry *direntry;
  662. {
  663.    int i;
  664.    printf ("Directory entry for file [%s][%s]:\n",
  665.             direntry->fname, direntry->lfname);
  666.    printf ("tag = [%8lx] type = [%d] PM = [%d] Next = [%8lx] Offset = [%8lx]\n",
  667.             direntry->zoo_tag, (int) direntry->type, 
  668.             (int) direntry->packing_method, direntry->next, 
  669.             direntry->offset);
  670.    printf ("Orig size = [%ld] Size now = [%ld] dmaj_v.dmin_v = [%d.%d]\n",
  671.          direntry->org_size, direntry->size_now,
  672.          (int) direntry->major_ver, (int) direntry->minor_ver);
  673.    printf ("Struc = [%d] DEL = [%d] comment_offset = [%8lx] cmt_size = [%d]\n",
  674.          (int) direntry->struc, (int) direntry->deleted, direntry->comment,
  675.          direntry->cmt_size);
  676.    printf ("var_dir_len = [%d] TZ = [%d] dir_crc = [%4x]\n",
  677.             direntry->var_dir_len, (int) direntry->tz, direntry->dir_crc);
  678.    printf ("system_id = [%d]  dirlen = [%d]  namlen = [%d]\n", 
  679.             direntry->system_id, direntry->dirlen, direntry->namlen);
  680.    if (direntry->dirlen > 0)
  681.       printf ("dirname = [%s]\n", direntry->dirname);
  682.    printf ("---------\n");
  683. }
  684. #endif   /* DEBUG */
  685.  
  686. #endif   /* PORTABLE */
  687.