home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume11 / zoo / part06 < prev    next >
Encoding:
Internet Message Format  |  1987-08-17  |  60.8 KB

  1. Path: uunet!rs
  2. From: rs@uunet.UU.NET (Rich Salz)
  3. Newsgroups: comp.sources.unix
  4. Subject: v11i015:  File archive program, Part06/07
  5. Message-ID: <995@uunet.UU.NET>
  6. Date: 18 Aug 87 22:48:54 GMT
  7. Organization: UUNET Communications Services, Arlington, VA
  8. Lines: 1843
  9. Approved: rs@uunet.UU.NET
  10.  
  11. Submitted-by: iuvax!bsu-cs!dhesi@seismo.CSS.GOV (Rahul Dhesi)
  12. Posting-number: Volume 11, Issue 15
  13. Archive-name: zoo/Part06
  14.  
  15. #! /bin/sh
  16. #
  17. # This is a shell archive, meaning:
  18. # 1. Remove everything above the #! /bin/sh line.
  19. # 2. Save the resulting text in a file.
  20. # 3. Execute the file with /bin/sh (not csh) to create:
  21. #    zooadd.c
  22. #    zooadd2.c
  23. #    zoodel.c
  24. #    zooext.c
  25. #    zoofns.h
  26. export PATH; PATH=/bin:/usr/bin:$PATH
  27. if test -f 'zooadd.c'
  28. then
  29.     echo shar: "will not over-write existing file 'zooadd.c'"
  30. else
  31. sed 's/^X//' << \SHAR_EOF > 'zooadd.c'
  32. X#ifndef LINT
  33. X/* @(#) zooadd.c 1.22 87/05/30 00:04:52 */
  34. Xstatic char sccsid[]="@(#) zooadd.c 1.22 87/05/30 00:04:52";
  35. X#endif /* LINT */
  36. X
  37. X/*
  38. XCopyright (C) 1986, 1987 Rahul Dhesi -- All rights reserved
  39. X*/
  40. X#include "options.h"
  41. X/* Adds files specified in parameter-list to archive zoo_path. */
  42. X
  43. X#define LONGEST    20                    /* assumed length of longest filename */
  44. X#include "zoomem.h"             /* to define MAXADD */
  45. X#include "zoo.h"
  46. X#include <stdio.h>
  47. X#include "various.h"
  48. X#include "parse.h"
  49. X#include "debug.h"
  50. X
  51. X#include "portable.h"
  52. X/* for low-level I/O */
  53. X#ifdef NOFCNTL
  54. X#include <file.h>
  55. X#else
  56. X#include <fcntl.h>
  57. X#endif
  58. X
  59. X#ifdef FLAT
  60. X#include <types.h>
  61. X#include <stat.h>
  62. X#else
  63. X#include <sys/types.h>
  64. X#include <sys/stat.h>
  65. X#endif
  66. X
  67. X#ifdef IGNORECASE
  68. X#define    COMPARE    strcmpi
  69. X#else
  70. X#define    COMPARE    strcmp
  71. X#endif
  72. X
  73. X#include "zoofns.h"
  74. X#include "errors.i"
  75. Xextern int break_hit;
  76. Xextern int quiet;
  77. X
  78. X#ifdef LINT_ARGS
  79. Xvoid opts_add (char *, int *, int *, int *, int *, int *, int *,
  80. X               int *, int *, int *, int *, int *);
  81. Xint ver_too_high (struct zoo_header *);
  82. Xget_comment (struct direntry *, FILE *, char *);
  83. Xvoid copyfields (struct direntry *, struct tiny_header *);
  84. Xvoid storefname (struct direntry *, char *, int);
  85. Xchar *choosefname (struct direntry *);
  86. X#else
  87. Xvoid opts_add();
  88. Xint ver_too_high ();
  89. Xget_comment ();
  90. Xvoid copyfields ();
  91. Xvoid storefname ();
  92. Xchar *choosefname ();
  93. X#endif
  94. X
  95. Xextern struct zoo_header zoo_header;
  96. X
  97. Xextern char file_leader[];
  98. Xextern unsigned int crccode;
  99. X
  100. Xvoid zooadd(zoo_path, argc, argv, option)
  101. Xchar *zoo_path;      /* pathname of zoo archive to add to */
  102. Xint argc;            /* how many filespecs supplied */
  103. Xchar **argv;         /* array of pointers to filespecs */
  104. Xchar *option;        /* option string */
  105. X{
  106. Xchar *whichname;                          /* which name to show user */
  107. Xchar *flist[MAXADD];                      /* list of ptrs to input fnames */
  108. Xint fptr;                                 /* will point to within flist */
  109. Xint zoo_han;                              /* handle for open archive */
  110. Xint this_han;                             /* handle of file to add */
  111. Xchar zoo_fname[LFNAMESIZE];               /* basename of archive itself */
  112. Xchar zoo_bak[LFNAMESIZE];                 /* name of archive's backup */
  113. Xchar this_fname[LFNAMESIZE];              /* just filename of file to add */
  114. Xchar latest_name[LFNAMESIZE];             /* latest name in archive */
  115. Xlong last_old = 0L;                       /* last direntry in old chain */
  116. XFILE *zoo_file;                           /* stream for open archive */
  117. Xchar *this_path;                          /* pathname of file to add */
  118. X
  119. X#ifdef NOENUM
  120. X#define NEW_ZOO 1
  121. X#define OLD_ZOO 2
  122. Xint zoo_status;
  123. X#else
  124. Xenum {NEW_ZOO, OLD_ZOO} zoo_status;       /* newly created or not */
  125. X#endif
  126. X
  127. Xlong this_dir_offset;                     /* pointers to within archive */
  128. Xlong save_position;                       /* pointer to within archive */
  129. Xlong prev_pos;                            /* posn of prev file of same name */
  130. Xstruct direntry direntry;                 /* directory entry */
  131. Xstruct direntry dir2entry;                /* spare */
  132. Xstruct tiny_header tiny_header;           /* for Z format archives */
  133. Xint status;                               /* error status */
  134. Xint success;                              /* successful addition of file? */
  135. Xint addcount = 0;                         /* number added */
  136. Xint update=0;                             /* add only files already in archive */
  137. Xint suppress=0;                           /* suppress compression */
  138. Xint new=0;                                /* add only files not in archive */
  139. Xint zootime = 0;                          /* just set archive time */
  140. Xint add_comment = 0;                      /* add comment */
  141. Xint pack = 0;                             /* pack after adding */
  142. Xint need_dir = 1;                         /* store directories too */
  143. Xint delcount = 0;                         /* count of deleted entries */
  144. Xint exit_status = 0;                      /* exit status to set */
  145. X
  146. Xunsigned int latest_date = 0;             /* to set time on archive itself */
  147. Xunsigned int latest_time = 0;             /* .. same */
  148. Xint move = 0;                             /* delete after adding to archive */
  149. Xint longest;                              /* length of longest pathname added */
  150. Xint firstfile = 1;                        /* first file being added? */
  151. Xint z_fmt = 0;                            /* look for Z format files? */
  152. Xint inargs = 0;                                    /* read filenames from stdin? */
  153. X
  154. X/* on entry option points to first letter */
  155. X
  156. Xopts_add (option, &zootime, &quiet, &suppress, &move, &new, &pack,
  157. X          &update, &add_comment, &z_fmt, &need_dir, &inargs);
  158. X
  159. X/* POSSIBLE RACE CONDITION BETWEEN TESTING EXISTENCE AND CREATING FILE */
  160. Xif (exists (zoo_path)) {
  161. X    zoo_file = fopen (zoo_path, "r+b");            /* binary open, no create */
  162. X   zoo_status = OLD_ZOO;
  163. X} else {
  164. X   if (!zootime)
  165. X        zoo_file = fopen (zoo_path, "w+b");        /* binary create/truncate */
  166. X   else
  167. X      zoo_file = NULL;     /* don't create if just setting time */
  168. X   zoo_status = NEW_ZOO;
  169. X}
  170. X
  171. Xif (zoo_file == NULL)
  172. X   prterror ('f', could_not_open, zoo_path);
  173. Xzoo_han = fileno(zoo_file);            /* get file handle */
  174. X
  175. Xbasename(zoo_path, zoo_fname);      /* get basename of archive */
  176. Xrootname (zoo_path, zoo_bak);       /* name without extension */
  177. Xstrcat (zoo_bak, BACKUP_EXT);       /* name of backup of this archive */
  178. X
  179. X/* 
  180. XFrom now on, both zoo_file and zoo_han can be used (one for stream I/O and
  181. Xthe other for low-level I/O).  But before doing any low-level I/O, or 
  182. Xbefore switching between reading and writing on the stream, a seek
  183. Xmust be done on the stream to flush buffered data and synchronize file
  184. Xpointers.
  185. X*/
  186. X
  187. X/* Now we prepare the archive for adding one or more files.  If the archive
  188. Xhas just been created, we write the archive header */
  189. X
  190. Xaddfname ("",0L,0,0); /* initialize table of files already in archive */
  191. Xif (zoo_status == NEW_ZOO) {                 /* newly-created archive */
  192. X   fwr_zooh (&zoo_header, zoo_file);
  193. X   /* fwrite ((char *) &zoo_header, sizeof(zoo_header), 1, zoo_file); */
  194. X   fseek (zoo_file, zoo_header.zoo_start, 0); /* seek to where data begins */
  195. X} else {
  196. X   /* read header and rewrite with updated version numbers */
  197. X   rwheader (&zoo_header, zoo_file);
  198. X   /* initialize latest_name to null string */
  199. X    /* NOTE:  latest_name is not currently used for anything, but
  200. X        may be used in the future for inserting files into the
  201. X        archive in alphabetic order. */
  202. X   *latest_name = '\0';
  203. X
  204. X   /* Skip existing files but add them to a list.  The variable last_old 
  205. X   gets the tail of the old chain of directory entries */
  206. X   skip_files (zoo_file, &latest_date, &latest_time, &delcount, 
  207. X               latest_name, &last_old);
  208. X}
  209. X/* The file pointer is now positioned correctly to add a file to archive, 
  210. Xunless the null directory entry is too short.  This will be fixed below. */
  211. X
  212. X/* If we are just setting time, do it and run. */
  213. Xif (zootime) {
  214. X#ifdef NIXTIME
  215. X   fclose (zoo_file);
  216. X   setutime (zoo_path, latest_date, latest_time);
  217. X#else
  218. X   settime (zoo_han, latest_date, latest_time);
  219. X   fclose (zoo_file);
  220. X#endif
  221. X   prterror ('m', "Archive time adjusted.\n");
  222. X   exit (0);
  223. X}
  224. X
  225. X/* make list of files, excluding archive and its backup */
  226. Xlongest = LONGEST;
  227. Xif (!inargs) {
  228. X   makelist(argc, argv, flist, MAXADD-2, zoo_fname, zoo_bak, ".", &longest);
  229. X   /*                                    ^^         ^^       ^^ exclude */
  230. X}
  231. X
  232. Xfptr = 0;    /* ready to get filename (if makelist() was called) or to
  233. X                    begin adding filenames (if reading them from stdin) */
  234. X
  235. Xwhile (1) {
  236. X   unsigned int this_date, this_time;
  237. X   int INLIST; /* boolean */
  238. X   int RECENT; /* boolean */
  239. X   int danger; /* if update requested and disk copy is out of date */
  240. X    if (inargs) {
  241. X    again: /* loop back if filename was same as archive name or its backup */
  242. X        this_path = getstdin();            /* pathname from stdin, in static area */
  243. X        modpath (this_path);
  244. X        /* if moving files, add to list for later deletion;  if list overflows,
  245. X            terminate addition loop and give warning message */
  246. X        if (move) {
  247. X            if (fptr >= MAXADD-2) {
  248. X                prterror ('w', too_many_files, MAXADD-2);
  249. X                this_path = NULL;
  250. X            } else if (this_path != NULL) {
  251. X                if (!COMPARE(zoo_fname,nameptr(this_path)) ||
  252. X                            !COMPARE(zoo_bak,nameptr(this_path)))
  253. X                    goto again;
  254. X                else
  255. X                    flist[fptr++] = strdup (this_path);
  256. X            }
  257. X        }
  258. X    } else  {
  259. X        this_path = flist[fptr++];
  260. X    }
  261. X    /* exit the addition loop when no more pathnames are left */
  262. X    if (this_path == NULL) {
  263. X        /* in case stdin was being read, make sure flist is NULL-terminated */
  264. X        flist[fptr] = NULL;
  265. X        break;
  266. X    }
  267. X
  268. X   basename (this_path, this_fname);   /* get just filename for later */
  269. X
  270. X   this_han = OPEN(this_path, F_READ);
  271. X   if (this_han == -1) {
  272. X      prterror ('e', could_not_open, this_path);
  273. X      exit_status++;
  274. X      continue;
  275. X   }
  276. X
  277. X#ifndef PORTABLE
  278. X   /* Test to see if this is a Z format file.  We assume the file is Z format
  279. X      if (a) tag is correct and (b) type is 1 and (c) embedded filename
  280. X      is not longer than FNAMESIZE.  
  281. X   */
  282. X   if (z_fmt) {
  283. X      read (this_han, (char *) &tiny_header, sizeof(tiny_header));
  284. X      if (tiny_header.tinytag == TINYTAG && tiny_header.type == 1 &&
  285. X                        strlen (tiny_header.fname) <= FNAMESIZE)
  286. X          /* ok */ ;
  287. X      else {
  288. X         close (this_han);
  289. X         prterror ('e', "File %s does not have Z format.\n", this_fname);
  290. X         exit_status++;
  291. X         continue;
  292. X      }
  293. X   }
  294. X#endif
  295. X
  296. X   /* get file time;  also fix name */
  297. X#ifndef PORTABLE
  298. X   if (z_fmt) {
  299. X      direntry.date = tiny_header.date;
  300. X      direntry.time = tiny_header.time;
  301. X      strcpy (direntry.fname, tiny_header.fname);
  302. X      direntry.dirlen = direntry.namlen = 0;
  303. X   } else {
  304. X#endif
  305. X
  306. X      /* Get timstamp of file being added */
  307. X#ifdef GETUTIME
  308. X      getutime (this_path, &direntry.date, &direntry.time);
  309. X#else
  310. X      gettime (this_han, &direntry.date, &direntry.time);
  311. X#endif
  312. X
  313. X#ifdef FOLD
  314. X      strlwr(this_fname);
  315. X#endif
  316. X      dosname (this_fname, direntry.fname);  /* MSDOS filename */
  317. X
  318. X   /*
  319. X   Store long filename into direntry.lfname iff it is different from MSDOS
  320. X   filename.  Also store directory name if need_dir is true.  Moved out of 
  321. X   zooadd() so zooadd() doesn't get too big for optimization.
  322. X   */
  323. X   storefname (&direntry, this_path, need_dir);
  324. X
  325. X#ifndef PORTABLE
  326. X   }
  327. X#endif
  328. X
  329. X#ifdef DEBUG
  330. Xprintf ("zooadd:  direntry.lfname = [%s]  direntry.dirname = [%s]\n",
  331. X                  direntry.lfname, direntry.dirname);
  332. X#endif
  333. X
  334. X   /* if update option, then we add file if it is already in the archive 
  335. X      AND the archived file is older */
  336. X
  337. X   /* The following logic was derived from a Karnaugh map so it may
  338. X      be hard to understand.  Essentially, if U=update requested,
  339. X      N=new files requested, I=file is already in archive, and
  340. X      R=file being archived is more recent than file already in
  341. X      archive, then the boolean equation is:
  342. X
  343. X      add = U' (N' + I') + U (IR  + I'N)
  344. X   */
  345. X
  346. X   /* Get the filename to use for this addition.  */
  347. X   whichname = choosefname(&direntry);
  348. X
  349. X   /* get position in archive of any old file of same name, ignoring
  350. X        any directory prefix if need_dir is not true */
  351. X   prev_pos = inlist (fullpath (&direntry), &this_date, &this_time, !need_dir);
  352. X
  353. X   INLIST = prev_pos > 0;  /* already in archive if positive value */
  354. X   if (INLIST) {
  355. X      int result;
  356. X      result = cmpnum (direntry.date, direntry.time, this_date, this_time);
  357. X      RECENT = result > 0;
  358. X      danger = result < 0;
  359. X   } else
  360. X      danger = 0; /* And RECENT is undefined and should not be used */
  361. X
  362. X   if (
  363. X         !update && (!new || !INLIST) ||
  364. X         update && (INLIST && RECENT || !INLIST && new)
  365. X      )
  366. X         ;  /* then continue and add file */
  367. X   else {
  368. X      if (update && danger)
  369. X         prterror ('w', "Archived copy of %s is newer.\n", whichname);
  370. X      close (this_han);
  371. X      continue;   /* cycle back, skip this file */
  372. X   }
  373. X
  374. X#ifdef CHEKDIR
  375. X   /* Don't add if this is a directory */
  376. X   if (isadir (this_han)) {
  377. X      close (this_han);
  378. X      continue;
  379. X   }
  380. X#endif
  381. X
  382. X#ifdef CHEKUDIR
  383. X   /* Don't add if this is a directory */
  384. X   if (isuadir (this_path)) {
  385. X      close (this_han);
  386. X      continue;
  387. X   }
  388. X#endif
  389. X
  390. X   /* Create directory entry for new file (but don't add just yet) */
  391. X   /* NOTE:  we already got file date and time above for update option */
  392. X    /* add tag, type, timezone, struc, system_id, and var_dir_len */
  393. X    newdir (&direntry);
  394. X
  395. X   /* 
  396. X   Write a null direntry entry.  Thus, if an error occurs or the program
  397. X   is interrupted, the end of the archive will still be meaningful.
  398. X   Special check needed for first one written.
  399. X   */
  400. X
  401. X   direntry.next = direntry.offset = 0L;     /* trailing null entry */
  402. X   this_dir_offset = ftell (zoo_file);
  403. X   if (!firstfile) {
  404. X      writedir (&direntry, zoo_file);
  405. X   } else {
  406. X      /*
  407. X      Before adding the first file to the archive, we must make sure that
  408. X      the previous directory chain (if any) is properly terminated with a
  409. X      null entry of the right size.  If this is a new archive, we simply
  410. X      write a new null entry of the right size.  If this is an existing
  411. X      archive, we must check the size of the previous trailing null entry. 
  412. X      If it is too small, we will back up to the most recent real directory
  413. X      entry and change its .next field to point to end of file.  
  414. X      */
  415. X
  416. X      if (zoo_status == NEW_ZOO) {
  417. X         writedir (&direntry, zoo_file);        /* write null dir entry */
  418. X      } else {
  419. X#define  DIRLEN(x)   ((x.type<2) ? SIZ_DIR : (SIZ_DIRL+x.var_dir_len))
  420. X         struct direntry tmpentry;
  421. X         long tmppos;
  422. X         int oldlen, newlen;
  423. X         tmppos = ftell(zoo_file);
  424. X         frd_dir (&tmpentry, zoo_file);
  425. X         oldlen = DIRLEN(tmpentry);             /* get length of direntry */
  426. X         newlen = DIRLEN(direntry);             /* ditto */
  427. X
  428. X         if (newlen > oldlen) {                 /* trouble */
  429. X            fseek (zoo_file, last_old, 0);      /* back to previous entry */
  430. X            frd_dir (&tmpentry, zoo_file);
  431. X            fseek (zoo_file, 0L, 2);            /* get EOF position */
  432. X            tmpentry.next = ftell(zoo_file);    /* point to EOF */
  433. X            fseek (zoo_file, last_old, 0);      /* back to previous entry */
  434. X            writedir (&tmpentry, zoo_file);     /* update it */
  435. X            fseek (zoo_file, 0L, 2);            /* to EOF ... */
  436. X            this_dir_offset = ftell (zoo_file);
  437. X            writedir (&direntry, zoo_file);     /* ...write null dir entry */
  438. X         } else
  439. X            fseek (zoo_file, tmppos, 0);        /* long enough -- let it be */
  440. X      } /* if (zoo_status == NEW_ZOO) ... */
  441. X   } /* if (!firstfile) ... */
  442. X
  443. X   /* Now `this_dir_offset' is where the next directory entry will go */
  444. X
  445. X   /* first file added goes at EOF to avoid overwriting comments */
  446. X   if (firstfile) {
  447. X      fseek (zoo_file, 0L, 2);                     /* EOF */
  448. X      direntry.offset = ftell (zoo_file) + SIZ_FLDR;
  449. X   } else {
  450. X      direntry.offset = this_dir_offset + SIZ_DIRL + 
  451. X         direntry.var_dir_len + SIZ_FLDR;
  452. X   }
  453. X
  454. X   direntry.major_ver = MAJOR_EXT_VER;    /* minimum version number needed */
  455. X   direntry.minor_ver = MINOR_EXT_VER;    /* .. to extract */
  456. X   direntry.deleted = 0;               /* not deleted, naturally */
  457. X   direntry.comment = 0L;              /* no comment (yet) */
  458. X   direntry.cmt_size = 0;          /* .. so no size either */
  459. X
  460. X   save_position = direntry.offset;          /* save position in case of error */
  461. X
  462. X   fseek (zoo_file, direntry.offset - SIZ_FLDR, 0);
  463. X   fwrite (file_leader, SIZ_FLDR, 1, zoo_file);
  464. X   fseek (zoo_file, ftell (zoo_file), 0);    /* for low-level I/O */
  465. X
  466. X#ifdef PORTABLE
  467. X   prterror ('m', "%-*s -- ", longest, this_path);
  468. X#else
  469. X   if (z_fmt)
  470. X      prterror ('m', "%-12s <== %-*s -- ", 
  471. X         direntry.fname, longest, this_path);
  472. X   else
  473. X      prterror ('m', "%-*s -- ", longest, this_path);
  474. X
  475. X#ifdef COMMENT
  476. X   prterror ('m', z_fmt ? "%-12s <== %-12s -- " : "%-12s -- ",
  477. X                      direntry.fname, this_fname);       
  478. X   prterror ('m', z_fmt ? "%-12s <== %-12s -- " : "%-12s -- ",
  479. X                      direntry.fname, this_fname);       
  480. X#endif /* COMMENT */
  481. X#endif /* PORTABLE */
  482. X
  483. X   crccode = 0;
  484. X   if (z_fmt) {
  485. X      direntry.packing_method = tiny_header.packing_method;
  486. X      lseek (this_han, (long) (sizeof(tiny_header) + tiny_header.cmt_size), 0);
  487. X      status = getfile (this_han, zoo_han, tiny_header.size_now, 1);
  488. X   } else if (suppress) {                    /* suppress compression */
  489. X      direntry.packing_method = 0;           /* no compression */
  490. X      status = getfile (this_han, zoo_han, -1L, 1);
  491. X      /* status = copyfile (this_han, zoo_han); */
  492. X   } else {
  493. X      direntry.packing_method = 1;           /* compressed */
  494. X      status = lzc(this_han, zoo_han);       /* add with compression */
  495. X   }
  496. X   if (status != 0) { /* if I */
  497. X      ++exit_status;                         /* remember error */
  498. X      if (status == 1)
  499. X         prterror ('F', no_memory);
  500. X      else if (status == 2)
  501. X         prterror ('F', disk_full);
  502. X      else if (status == 3)
  503. X         prterror ('F', "Read error.\n");
  504. X      else
  505. X         prterror ('F', internal_error);
  506. X      success = 0;
  507. X   } else {
  508. X      direntry.next  = ftell(zoo_file);
  509. X      direntry.size_now = direntry.next - direntry.offset;
  510. X
  511. X      /* find and store original size of file just compressed */
  512. X      direntry.org_size = tell (this_han);  /* should be EOF already */
  513. X
  514. X      /* If the compressed one is bigger, just copy */
  515. X
  516. X      if (direntry.size_now >= direntry.org_size &&   /* if II */
  517. X            direntry.packing_method > 0) {
  518. X         lseek (zoo_han, save_position, 0);     /* ..restore file pointer */
  519. X         trunc (zoo_han);                       /* ..truncate file */
  520. X         direntry.packing_method = 0;           /* ..and just copy */
  521. X         lseek (this_han, 0L, 0);               /* (but rewind first!) */
  522. X         crccode = 0;                           /* re-start crc from 0 */
  523. X         status = getfile (this_han, zoo_han, -1L, 1);
  524. X         /* status = copyfile (this_han, zoo_han); */
  525. X         if (status != 0) {  /* if III */
  526. X            success = 0;
  527. X            printf (disk_full);
  528. X            exit_status++;
  529. X         } else {
  530. X            success = 1;
  531. X            direntry.next  = ftell(zoo_file);
  532. X            direntry.size_now = direntry.next - direntry.offset;
  533. X         } /* end if III */
  534. X      } else {
  535. X         success = 1;
  536. X      } /* end if II */
  537. X
  538. X   } /* end if I */
  539. X
  540. X   if (success) {                               /* file successfully added */
  541. X      addcount++;                               /* how many added */
  542. X      direntry.file_crc = crccode;
  543. X
  544. X      /* remember most recent date and time */
  545. X      if (cmpnum (direntry.date,direntry.time,latest_date,latest_time) > 0) {
  546. X            latest_date = direntry.date;
  547. X            latest_time = direntry.time;
  548. X      }
  549. X
  550. X      /* mark any previous version of this file in archive as deleted */
  551. X      dir2entry.comment = 0L;       /* for later use assigning to direntry */
  552. X      dir2entry.cmt_size = 0;
  553. X
  554. X      if (!z_fmt)
  555. X         prterror ('M', " (%2d%%) ", cfactor (direntry.org_size, direntry.size_now));
  556. X
  557. X      if (prev_pos > 0) {
  558. X         long save_pos = ftell(zoo_file); /*DEBUG*/
  559. X         ++delcount;          /* remember to pack */
  560. X         prterror ('M', "replaced\n");
  561. X         fseek (zoo_file, prev_pos, 0);
  562. X         readdir (&dir2entry, zoo_file, 1);
  563. X         dir2entry.deleted = 1;        /* mark as deleted */
  564. X         fseek (zoo_file, prev_pos, 0);
  565. X         writedir (&dir2entry, zoo_file);
  566. X         fseek (zoo_file, save_pos, 0); /*DEBUG*/
  567. X      } else prterror ('M', "added\n");
  568. X
  569. X      /* Preserve any old comment if we replaced the file */
  570. X      direntry.comment = dir2entry.comment;
  571. X      direntry.cmt_size = dir2entry.cmt_size;
  572. X
  573. X#ifndef PORTABLE
  574. X      /* Copy comment if any from Z format file */
  575. X      if (z_fmt && tiny_header.cmt_size != 0) {
  576. X         lseek (this_han, (long) sizeof(tiny_header), 0); /* get to comment */
  577. X#ifdef COMMENT
  578. X         fseek (zoo_file, 0L, 2);   /* append comment to end */
  579. X#endif
  580. X         direntry.comment = ftell (zoo_file);
  581. X         direntry.cmt_size = tiny_header.cmt_size;
  582. X         /* 4th param is 0 for no CRC */
  583. X         getfile (this_han, zoo_han, (long) tiny_header.cmt_size, 0);
  584. X         direntry.next = ftell(zoo_file);
  585. X      } 
  586. X#endif
  587. X
  588. X      /* if user requested comments, any previous comment in a Z format
  589. X         file may now be manually overwritten */
  590. X      if (add_comment && !feof (stdin)) {
  591. X         show_comment (&direntry, zoo_file, 1, whichname);
  592. X         get_comment (&direntry, zoo_file, this_path);
  593. X         direntry.next = ftell(zoo_file);    /* update .next ptr */
  594. X      } /* end if */
  595. X
  596. X#ifndef PORTABLE
  597. X      /* if adding Z format archive, copy relevant fields from its header */
  598. X      if (z_fmt) {   /* moved out to shorten code & allow optimizer to work */
  599. X         copyfields (&direntry, &tiny_header);
  600. X      }
  601. X#endif
  602. X
  603. X      debug((printf ("zooadd:  our new .next = [%lx].\n", direntry.next)))
  604. X
  605. X      {
  606. X         long savepos = ftell(zoo_file);    /* save position */
  607. X         fseek (zoo_file, this_dir_offset, 0);
  608. X         writedir (&direntry, zoo_file);
  609. X         fseek (zoo_file, savepos, 0);    /* restore position */
  610. X      }
  611. X
  612. X   } else {                               /* file was not properly added */
  613. X      lseek (zoo_han, save_position, 0);     /* ..restore file pointer */
  614. X      trunc (zoo_han);                       /* ..truncate file */
  615. X   } /* end if */
  616. X   close (this_han);
  617. Xif (!success)
  618. X   break;
  619. Xfirstfile = 0;
  620. X} /* end for */
  621. X
  622. Xsave_position = ftell (zoo_file);
  623. X
  624. X/* Write a null direntry entry */
  625. Xfseek (zoo_file, save_position, 0);
  626. Xwritenull (zoo_han, MAXDIRSIZE);
  627. Xtrunc (zoo_han);    /* truncate */
  628. X
  629. X#ifdef NIXTIME
  630. Xfclose (zoo_file);
  631. Xsetutime (zoo_path, latest_date, latest_time);
  632. X#else
  633. Xsettime (zoo_han, latest_date, latest_time);
  634. Xfclose (zoo_file);
  635. X#endif
  636. X
  637. Xif (!addcount) {                    /* no files added */
  638. X   prterror ('m', "No files added.\n");
  639. X   if (zoo_status == NEW_ZOO)
  640. X      unlink (zoo_path);
  641. X} else {
  642. X   if (delcount && pack) { /* pack if user asked and found deleted entries */
  643. X      prterror ('M', "-----\nPacking...");
  644. X      zoopack (zoo_path, "PP");
  645. X      prterror ('M', "done\n");
  646. X   }
  647. X
  648. X   /* If files to move & we added some and no error so far, delete originals */
  649. X   if (move && !exit_status)
  650. X      if (kill_files (flist, longest) != 0)
  651. X         exit_status++;
  652. X}
  653. X
  654. Xif (exit_status)
  655. X   exit (1);
  656. X} /* end zoo_add */
  657. SHAR_EOF
  658. fi
  659. if test -f 'zooadd2.c'
  660. then
  661.     echo shar: "will not over-write existing file 'zooadd2.c'"
  662. else
  663. sed 's/^X//' << \SHAR_EOF > 'zooadd2.c'
  664. X#ifndef LINT
  665. X/* @(#) zooadd2.c 1.11 87/05/29 12:55:51 */
  666. Xstatic char sccsid[]="@(#) zooadd2.c 1.11 87/05/29 12:55:51";
  667. X#endif /* LINT */
  668. X
  669. X/*
  670. XCopyright (C) 1986, 1987 Rahul Dhesi -- All rights reserved
  671. X*/
  672. X#include "options.h"
  673. X#include "zoo.h"
  674. X#include <stdio.h>
  675. X#include "various.h"
  676. X#include "zoofns.h"
  677. X#include "errors.i"
  678. X#include "assert.h"
  679. X#include "debug.h"
  680. X#include "parse.h"
  681. X
  682. X/*
  683. XMiscellaneous routines to support zooadd().
  684. X*/
  685. X
  686. X/****************
  687. XThis function is called with zoo_file positioned to the first
  688. Xdirectory entry in an archive.  It skips past all existing files,
  689. Xcounts the number of deleted files, saves the latest data and time
  690. Xencountered, and adds all filenames encountered to a global list. The
  691. Xlong filename is added if available, else the MSDOS filename is
  692. Xadded.  
  693. X*/
  694. X
  695. Xvoid skip_files (zoo_file, latest_date, latest_time, delcount, 
  696. X                  latest_name, latest_pos)
  697. XFILE *zoo_file;
  698. Xunsigned int *latest_date, *latest_time;
  699. Xint *delcount;
  700. Xchar latest_name[];
  701. Xlong *latest_pos;
  702. X{
  703. X   char *whichname;                    /* will point to name to use */
  704. X   long save_offset, next_ptr;
  705. X   struct direntry direntry;
  706. X   struct direntry *drp = &direntry;
  707. X
  708. X   *latest_pos = 0L;
  709. X   do {
  710. X      /* read a directory entry */
  711. X      save_offset = ftell (zoo_file);     /* save pos'n of this dir entry */
  712. X      readdir (&direntry, zoo_file, 1);   /* read directory entry */
  713. X      if (drp->next == 0L) {                 /* END OF CHAIN */
  714. X         fseek (zoo_file, save_offset, 0);      /* back up */
  715. X         break;                                 /* EXIT on end of chain */
  716. X      } else
  717. X         *latest_pos = save_offset;
  718. X      /* remember most recent date and time, for files not marked deleted */
  719. X      if (!drp->deleted)
  720. X         if (drp->date > *latest_date ||
  721. X            (drp->date == *latest_date && drp->time > *latest_time)) {
  722. X               *latest_date = drp->date;
  723. X               *latest_time = drp->time;
  724. X         }
  725. X      next_ptr = drp->next;            /* ptr to next dir entry */
  726. X      if (drp->deleted)
  727. X         ++(*delcount);                      /* count deleted entries */
  728. X      /* add name of file and position of direntry into global list */
  729. X      /* but only if the entry is not deleted */
  730. X      if (!drp->deleted) {
  731. X#ifdef FOLD
  732. X            /* IS THIS REALLY NEEDED?  IF SO, WHAT ABOUT drp->lfname? */
  733. X         strlwr(drp->fname);
  734. X#endif
  735. X            /* add full pathname to global list */
  736. X            strcpy (latest_name, fullpath (drp));
  737. X         addfname (latest_name, save_offset, drp->date, drp->time);
  738. X      }
  739. X      fseek (zoo_file, next_ptr, 0);   /* ..seek to next dir entry */
  740. X   } while (next_ptr != 0L);              /* loop terminates on null ptr */
  741. X}
  742. X
  743. X/*******************/
  744. X/* kill_files() deletes all files in the supplied list of pointers to
  745. Xfilenames */
  746. X
  747. Xint kill_files (flist, pathlength)
  748. Xchar *flist[];                      /* list of ptrs to input fnames */
  749. Xint pathlength;                     /* length of longest pathname */
  750. X{
  751. X   int status = 0;
  752. X   int fptr;
  753. X   prterror ('M', "-----\nErasing added files...\n");
  754. X   for (fptr = 0;  flist[fptr] != NULL; fptr++) {
  755. X      prterror ('m', "%-*s -- ", pathlength, flist[fptr]);
  756. X      if (unlink (flist[fptr]) == 0) {
  757. X         prterror ('M', "erased\n");
  758. X      } else {
  759. X         prterror ('w', "Could not erase %s.\n", flist[fptr]);
  760. X         status = 1;
  761. X      }
  762. X   }
  763. X   return (status);
  764. X}
  765. X
  766. X#ifndef PORTABLE
  767. X/*******************/
  768. Xvoid copyfields (drp, thp)
  769. Xstruct direntry *drp;
  770. Xstruct tiny_header *thp;
  771. X{
  772. X   drp->org_size = thp->org_size;
  773. X   drp->file_crc = thp->file_crc;
  774. X   drp->size_now = thp->size_now;
  775. X   drp->major_ver = thp->major_ver;
  776. X   drp->minor_ver = thp->minor_ver;
  777. X}
  778. X#endif
  779. X
  780. X/*******************/
  781. X/* processes option switches for zooadd() */
  782. Xvoid opts_add (option, zootime, quiet, suppress, move, new, pack,
  783. X          update, add_comment, z_fmt, need_dir, inargs)
  784. Xchar *option;
  785. Xint *zootime, *quiet, *suppress, *move, *new, *pack,
  786. X   *update, *add_comment, *z_fmt, *need_dir, *inargs;
  787. X
  788. X{
  789. X   if (*option == 'T') {
  790. X      (*zootime)++;
  791. X      option++;
  792. X      while (*option) {
  793. X         switch (*option) {
  794. X            case 'q': (*quiet)++; break;
  795. X            default:
  796. X               prterror ('f', inv_option, *option);
  797. X         }
  798. X      option++;
  799. X      }
  800. X   }
  801. X   
  802. X   while (*option) {
  803. X      switch (*option) {
  804. X         case 'a': break;  
  805. X         case 'f': (*suppress)++; break;        /* suppress compression */
  806. X         case 'M': (*move)++; break;            /* delete files after adding them */
  807. X         case 'n': (*new)++; break;             /* add only files not in archive */
  808. X         case 'P': (*pack)++; break;            /* pack after adding */
  809. X         case 'u': (*update)++;   break;        /* add only files already in archive */
  810. X         case 'q': (*quiet)++; break;           /* be quiet */
  811. X         case 'c': (*add_comment)++; break;     /* add comment */
  812. X         case ':': *need_dir = 0; break;        /* don't store directories */
  813. X         case 'I': (*inargs)++; break;            /* get filenames from stdin */
  814. X#ifndef PORTABLE
  815. X         case 'z': (*z_fmt)++; break;           /* look for Z format files */
  816. X#endif
  817. X         default:
  818. X            prterror ('f', inv_option, *option);
  819. X      }
  820. X      option++;
  821. X   } /* end while */
  822. X}  
  823. X
  824. X
  825. X/* 
  826. XStores long filename into direntry.lfname iff it is different from MSDOS
  827. Xfilename.  Also stores directory name if need_dir is true.  Moved out of 
  828. Xzooadd() so zooadd() doesn't get too big for optimization.
  829. X*/
  830. Xvoid storefname (direntry, this_path, need_dir)
  831. Xstruct direntry *direntry;
  832. Xchar *this_path;
  833. Xint need_dir;
  834. X{
  835. X   struct path_st path_st;
  836. X   parse (&path_st, this_path);
  837. X   direntry->lfname[0] = '\0';
  838. X   direntry->namlen = 0;
  839. X   if (strcmp(path_st.lfname,direntry->fname) != 0) {
  840. X         strcpy (direntry->lfname, path_st.lfname); /* full filename */
  841. X         direntry->namlen = strlen(direntry->lfname) + 1;
  842. X   }
  843. X   if (need_dir) {
  844. X      strcpy (direntry->dirname, path_st.dir);   /* directory name */
  845. X      direntry->dirlen = strlen(direntry->dirname) + 1;
  846. X      if (direntry->dirlen == 1) /* don't store trailing null alone */
  847. X         direntry->dirlen = 0;
  848. X   } else {
  849. X      direntry->dirname[0] = '\0';
  850. X      direntry->dirlen = 0;
  851. X   }
  852. X}
  853. X
  854. X/* 
  855. XFunction getsdtin() gets a pathname from standard input, cleans
  856. Xit if necessary by removing any following blanks/tabs and other
  857. Xjunk, and returns it in a static area that is overwritten by each
  858. Xcall.
  859. X*/
  860. Xchar *getstdin()
  861. X{
  862. X    char *chptr;                                    /* temp pointer */
  863. X    static char tempname[PATHSIZE];
  864. X    do {
  865. X        if (fgets (tempname, PATHSIZE, stdin) == NULL)
  866. X            return (NULL);
  867. X        /* remove trailing blank, tab, newline */
  868. X        for (chptr = tempname; *chptr != '\0';  chptr++) {
  869. X            if (
  870. X    /* PURIFY means remove trailing blanks/tabs and all subsequent chars */
  871. X#ifdef PURIFY
  872. X                    *chptr == '\t' || *chptr == ' ' ||
  873. X#endif
  874. X                    *chptr == '\n'                        /* always remove trailing \n */
  875. X                )
  876. X            {
  877. X    
  878. X                *chptr = '\0';
  879. X                break;
  880. X            }
  881. X        }
  882. X    } while (*tempname == '\0');                /* get a nonempty line */
  883. X#ifdef FOLD
  884. X    strlwr (tempname);
  885. X#endif
  886. X    return (tempname);
  887. X}
  888. X
  889. X/* 
  890. XFunction newdir() adds some default information to a directory entry.
  891. XThis will be a new directory entry added to an archive.
  892. X*/
  893. Xvoid newdir (direntry)
  894. Xregister struct direntry *direntry;
  895. X{
  896. X   direntry->zoo_tag = ZOO_TAG;
  897. X   direntry->type = 2;                  /* type is now 2 */
  898. X   direntry->tz = 127;                  /* timezone unknown */
  899. X   direntry->struc = 0;                 /* unstructured file */
  900. X   direntry->system_id = 0;             /* identify UNIX filesystem */
  901. X   direntry->var_dir_len = 
  902. X      (direntry->dirlen > 0 || direntry->namlen > 0 ? 2 : 0) + 
  903. X      direntry->dirlen + direntry->namlen;
  904. X}
  905. SHAR_EOF
  906. fi
  907. if test -f 'zoodel.c'
  908. then
  909.     echo shar: "will not over-write existing file 'zoodel.c'"
  910. else
  911. sed 's/^X//' << \SHAR_EOF > 'zoodel.c'
  912. X#ifndef LINT
  913. Xstatic char sccsid[]="@(#) zoodel.c 1.8 87/05/29 12:56:02";
  914. X#endif /* LINT */
  915. X
  916. X/*
  917. XCopyright (C) 1986, 1987 Rahul Dhesi -- All rights reserved
  918. X*/
  919. X#include "options.h"
  920. X/* Deletes or undeletes entries from an archive.  choice=1 requests
  921. X   deletion and choice=0 requests undeletion. */
  922. X#include "portable.h"
  923. X#include <stdio.h>
  924. X#include "various.h" /* may not be needed */
  925. X#include "zoo.h"
  926. X#include "zoofns.h"
  927. X#include "errors.i"
  928. X
  929. X#ifndef NOSIGNAL
  930. X#include <signal.h>
  931. X#endif
  932. X
  933. Xextern int quiet;
  934. X
  935. Xvoid zoodel (zoo_path, option, choice)
  936. Xchar *zoo_path;
  937. Xchar *option;
  938. Xint choice;
  939. X{
  940. X#ifndef NOSIGNAL
  941. X   int (*oldsignal)();        /* to save previous SIGINT handler */
  942. X#endif
  943. X   int delcount = 0;          /* how many entries we [un]deleted */
  944. X   char matchname[PATHSIZE];  /* will hold full pathname */
  945. X   register FILE *zoo_file;
  946. X   struct zoo_header zoo_header;
  947. X   struct direntry direntry;
  948. X   unsigned int latest_date = 0;      /* so we can set time of archive later */
  949. X   unsigned int latest_time = 0;
  950. X   int pack = 0;              /* pack after deletion? */
  951. X   int file_deleted = 0;      /* any files deleted? */
  952. X   int one = 0;               /* del/undel one file only */
  953. X   int done;                  /* loop control */   
  954. Xwhile (*(++option)) {
  955. X   switch (*option) {
  956. X      case 'P': pack++; break;            /* pack after adding */
  957. X      case 'q': quiet++; break;           /* be quiet */
  958. X      case '1': one++; break;             /* del or undel only one file */
  959. X      default:
  960. X         prterror ('f', inv_option, *option);
  961. X   }
  962. X} /* end while */
  963. X
  964. X   /* Open archive for read/write/binary access.  It must already exist */
  965. X   if ((zoo_file = fopen (zoo_path, FRWSTR)) == NULL) {
  966. X      prterror ('f', could_not_open, zoo_path);
  967. X   }
  968. X   
  969. X   /* read archive header */
  970. X   frd_zooh (&zoo_header, zoo_file);
  971. X   /* fread ((char *) &zoo_header, sizeof(zoo_header), 1, zoo_file); */
  972. X   if ((zoo_header.zoo_start + zoo_header.zoo_minus) != 0L)
  973. X      prterror ('f', failed_consistency);
  974. X   fseek (zoo_file, zoo_header.zoo_start, 0); /* seek to where data begins */
  975. X   
  976. X   done = 0;            /* loop not done yet */
  977. X   /* Go into loop deleting requested entries */
  978. X   while (1) {
  979. X      long this_dir_offset;
  980. X      this_dir_offset = ftell (zoo_file);    /* save pos'n of this dir entry */
  981. X      frd_dir (&direntry, zoo_file);
  982. X      /* fread ((char *) &direntry, sizeof (direntry), 1, zoo_file); */
  983. X      if (direntry.zoo_tag != ZOO_TAG) {
  984. X         prterror ('f', bad_directory);
  985. X      }
  986. X      if (direntry.next == 0L) {                /* END OF CHAIN */
  987. X         break;                                 /* EXIT on end of chain */
  988. X      }
  989. X      
  990. X      /* Now [un]delete this entry if it isn't already [un]deleted and 
  991. X         if filename matches.  WARNING: convention of choice=1 for
  992. X         deleted entry must be same as in direntry definition in zoo.h */
  993. X   
  994. X      /* Test for "done" so if "one" option requested, [un]del only 1 file */
  995. X      /* But we go through the whole archive to adjust archive time */
  996. X
  997. X        strcpy (matchname, fullpath (&direntry));        /* get full pathname */
  998. X
  999. X      if (!done && direntry.deleted != choice && 
  1000. X                                             needed(matchname)) {
  1001. X         prterror ('m', "%-14s -- ", matchname);
  1002. X         delcount++;
  1003. X         direntry.deleted = choice;
  1004. X         if (choice) 
  1005. X            file_deleted++;      /* remember if any files actually deleted */
  1006. X
  1007. X         fseek (zoo_file, this_dir_offset, 0);
  1008. X
  1009. X#ifndef NOSIGNAL
  1010. X         oldsignal = signal (SIGINT, SIG_IGN);  /* disable ^C for write */
  1011. X#endif
  1012. X         if (fwr_dir (&direntry, zoo_file) == -1)
  1013. X         /* if (fwrite ((char *) &direntry, sizeof(direntry), 1, zoo_file) < 1) */
  1014. X            prterror ('f', "Could not write to archive\n");
  1015. X#ifndef NOSIGNAL
  1016. X         signal (SIGINT, oldsignal);
  1017. X#endif
  1018. X         prterror ('M', choice ? "deleted\n" : "undeleted\n");
  1019. X         if (one)
  1020. X            done = 1;            /* if 1 option, done after 1 file */
  1021. X      }
  1022. X
  1023. X      /* remember most recent date and time if entry is not deleted */
  1024. X      if (!direntry.deleted)
  1025. X         if (direntry.date > latest_date ||
  1026. X            (direntry.date == latest_date && direntry.time > latest_time)) {
  1027. X               latest_date = direntry.date;
  1028. X               latest_time = direntry.time;
  1029. X         }
  1030. X      fseek (zoo_file, direntry.next, 0); /* ..seek to next dir entry */
  1031. X   } /* endwhile */
  1032. X
  1033. X   if (!delcount)
  1034. X      printf ("Zoo:  No files matched.\n");
  1035. X   else {
  1036. X#ifdef NIXTIME
  1037. X      fclose (zoo_file);
  1038. X      setutime (zoo_path, latest_date, latest_time);
  1039. X#else
  1040. X      fflush (zoo_file);         /* superstition:  might help time stamp */
  1041. X      settime (fileno(zoo_file), latest_date, latest_time);
  1042. X#endif
  1043. X   }
  1044. X
  1045. X#ifndef NIXTIME
  1046. Xfclose (zoo_file);
  1047. X#endif
  1048. X
  1049. Xif (file_deleted && pack) {   /* pack if files were deleted and user asked */
  1050. X   prterror ('M', "-----\nPacking...");
  1051. X   zoopack (zoo_path, "PP");
  1052. X   prterror ('M', "done\n");
  1053. X}
  1054. X
  1055. X}
  1056. SHAR_EOF
  1057. fi
  1058. if test -f 'zooext.c'
  1059. then
  1060.     echo shar: "will not over-write existing file 'zooext.c'"
  1061. else
  1062. sed 's/^X//' << \SHAR_EOF > 'zooext.c'
  1063. X#ifndef LINT
  1064. Xstatic char sccsid[]="@(#) zooext.c 1.8 87/05/29 12:56:07";
  1065. X#endif /* LINT */
  1066. X
  1067. X/*
  1068. XCopyright (C) 1986, 1987 Rahul Dhesi -- All rights reserved
  1069. X*/
  1070. X#include "options.h"
  1071. X/* Extract file from archive.  Extracts files specified in parameter-list 
  1072. X   from archive zoo_path.  If none specified, extracts all files from 
  1073. X   archive. */
  1074. X
  1075. X#include "zoo.h"
  1076. X#include "parse.h"      /* defines struct for parse() */
  1077. X
  1078. X#include "portable.h"   /* portable I/O definitions */
  1079. X#include "machine.h"    /* machine-specific declarations */
  1080. X
  1081. X#include <stdio.h>
  1082. X#include "various.h"
  1083. X
  1084. X#ifndef NOSIGNAL
  1085. X#include <signal.h>
  1086. X#endif
  1087. X
  1088. X#include "zoofns.h"
  1089. X
  1090. X/* for low-level I/O */
  1091. X#ifdef FLAT
  1092. X#include <types.h>
  1093. X#include <stat.h>
  1094. X#else
  1095. X#include <sys/types.h>
  1096. X#include <sys/stat.h>
  1097. X#endif
  1098. X
  1099. X#ifdef NOFCNTL
  1100. X#include <file.h>
  1101. X#else
  1102. X#include <fcntl.h>
  1103. X#endif
  1104. X
  1105. Xextern int quiet;
  1106. X
  1107. X#include "errors.i"
  1108. X
  1109. X/* Following two are used by ctrl_c() also, hence declared here */
  1110. Xchar extfname[LFNAMESIZE];             /* filename of extracted file */
  1111. Xstatic int this_han;                   /* handle of file to extract */
  1112. X
  1113. Xstatic int tofile;                     /* true if not pipe or null device */
  1114. Xextern unsigned int crccode;
  1115. Xextern char *out_buf_adr;              /* address of output buffer */
  1116. X
  1117. Xvoid zooext(zoo_path, option)
  1118. Xchar *zoo_path, *option;
  1119. X{
  1120. Xchar *whichname;                          /* which name to extract */
  1121. Xchar matchname[PATHSIZE];                 /* for pattern matching only */
  1122. X#ifndef NOSIGNAL
  1123. Xint (*oldsignal)();        /* to save previous SIGINT handler */
  1124. X#endif
  1125. Xint zoo_han;                              /* handle for open archive */
  1126. Xlong next_ptr;                            /* pointer to within archive */
  1127. Xstruct zoo_header zoo_header;             /* header for archive */
  1128. Xint status;                               /* error status */
  1129. Xchar ans[3];                              /* answer to "Overwrite?" */
  1130. Xint error_message = 1;                    /* Whether to give error message */
  1131. Xunsigned long disk_space;                 /* disk space left */
  1132. Xint matched = 0;                          /* Any files matched? */
  1133. Xint overwrite = 0;                        /* force overwrite of files? */
  1134. Xint needdel = 0;                          /* extract deleted files too */
  1135. Xint usepath = 0;                          /* use path for extraction */
  1136. Xint todot = 0;                            /* extract relative to . */
  1137. Xint zootime = 0;                          /* just set archive time */
  1138. Xint badcrc_count = 0;                     /* how many files with bad CRC */
  1139. Xint bad_header = 0;                       /* to avoid spurious messages later */
  1140. Xlong fiz_ofs = 0;                         /* offset where to start */
  1141. Xint pipe = 0;                             /* are we piping output? */
  1142. Xint fast_ext = 0;                         /* fast extract as *.?Z? */
  1143. Xint null_device = 0;                      /* are we sending to null device? */
  1144. Xint alloc_size;                           /* disk allocation unit size */
  1145. Xstruct direntry direntry;                 /* directory entry */
  1146. X
  1147. X#ifdef OOZ
  1148. X   static char extract_ver[] = "A higher version of OOZ is needed to extract ";
  1149. X   static char no_space[] = "Insufficient disk space to extract ";
  1150. X#else
  1151. X   static char extract_ver[] = "Zoo %d.%d is needed to extract %s.\n";
  1152. X   static char no_space[] = "Insufficient disk space to extract %s.\n";
  1153. X#endif
  1154. X
  1155. X#ifndef OOZ
  1156. Xwhile (*option) {
  1157. X   switch (*option) {
  1158. X#ifndef PORTABLE
  1159. X      case 'z': fast_ext++; break;
  1160. X#endif
  1161. X      case 'x':
  1162. X      case 'e': break;
  1163. X      case 'N': null_device++; break;
  1164. X      case 'O': overwrite += 2; break;
  1165. X      case 'o': overwrite++; break;
  1166. X      case 'p': pipe++; break;
  1167. X      case 'd': needdel++; break;
  1168. X      case 'q': quiet++; break;
  1169. X      case '/': usepath++; break;
  1170. X      case '.': todot++; break;
  1171. X      case '@': 
  1172. X         ++option;
  1173. X         fiz_ofs = calc_ofs(option); 
  1174. X         goto no_more;
  1175. X      default:
  1176. X         prterror ('w', option_ignored, *option);
  1177. X         break;
  1178. X   }
  1179. X   option++;
  1180. X}
  1181. X
  1182. Xno_more: /* come from exit in while loop above */
  1183. X
  1184. X
  1185. Xif (overwrite == 1)                 /* must be at least 2 to begin with */
  1186. X   overwrite--;
  1187. X
  1188. Xif (null_device && pipe) {
  1189. X   prterror ('w', option_ignored, 'p');
  1190. X   pipe = 0;
  1191. X}
  1192. X
  1193. Xif (overwrite && pipe)
  1194. X   prterror ('w', option_ignored, 'O');
  1195. X
  1196. Xif (null_device && fast_ext) {
  1197. X   prterror ('w', option_ignored, 'N');
  1198. X   null_device = 0;
  1199. X}
  1200. X
  1201. Xtofile = !pipe && !null_device;     /* sending to actual file */
  1202. X#else
  1203. Xtofile = 1;
  1204. X#endif
  1205. X
  1206. X
  1207. Xzoo_han = OPEN(zoo_path, F_READ);
  1208. X
  1209. Xif (zoo_han == -1)
  1210. X#ifdef OOZ
  1211. X   prterror ('f', could_not_open, zoo_path, ".\n");
  1212. X#else
  1213. X   prterror ('f', could_not_open, zoo_path);
  1214. X#endif
  1215. X
  1216. Xif (fiz_ofs != 0L) {                /* if offset specified, start there */
  1217. X   prterror('m', "Starting at %ld\n", fiz_ofs);
  1218. X   lseek (zoo_han, fiz_ofs, 0);
  1219. X} else {
  1220. X   /* read header */
  1221. X   rd_zooh (&zoo_header, zoo_han);
  1222. X   /* read (zoo_han, (char *) &zoo_header, sizeof(zoo_header)); */
  1223. X   if ((zoo_header.zoo_start + zoo_header.zoo_minus) != 0L) {
  1224. X      prterror ('w', failed_consistency, (char *) NULL, (char *) NULL);
  1225. X      bad_header++;
  1226. X   }
  1227. X   lseek (zoo_han, zoo_header.zoo_start, 0); /* seek to where data begins */
  1228. X}
  1229. X
  1230. X#ifndef PORTABLE
  1231. Xdisk_space = space (0, &alloc_size);         /* remember disk space left */
  1232. X#else
  1233. Xalloc_size = 0;
  1234. Xdisk_space = MAXLONG;              /* infinite disk space */
  1235. X#endif
  1236. X
  1237. X#ifndef OOZ
  1238. X/* Ooz does no piping */
  1239. X/* if piping output we open the output device just once */
  1240. X/* NOTE:  the DOS device "NUL" was causing the system to hang up.
  1241. X   therefore we create our own.  All functions called must recognize
  1242. X   -2 as a null output handle and ignore all output to that */
  1243. Xif (null_device) {                  /* -2 means null device */
  1244. X   this_han = -2;
  1245. X} else if (pipe)
  1246. X   this_han = (int) fileno(stdout);    /* standard output */
  1247. X#endif
  1248. X
  1249. Xwhile (1) {
  1250. X   rd_dir (&direntry, zoo_han);
  1251. X   /* read (zoo_han, (char *) &direntry, sizeof(direntry)); */
  1252. X   if (direntry.zoo_tag != ZOO_TAG) {
  1253. X      long currpos, zoolength;
  1254. X
  1255. X#ifdef OOZ
  1256. X         prterror ('f', invalid_header, (char *) NULL, (char *) NULL);
  1257. X#else
  1258. X         prterror ('F', invalid_header);
  1259. X
  1260. X         /* Note:  if header was bad, there's no point trying to find
  1261. X            how many more bytes aren't processed -- our seek position is
  1262. X            likely very wrong */
  1263. X   
  1264. X         if (!bad_header)
  1265. X            if ((currpos = tell (zoo_han)) != -1L)
  1266. X               if (lseek (zoo_han, 0L, 2) != -1)
  1267. X                  if ((zoolength = tell (zoo_han)) != -1L)
  1268. X                     printf (cant_process, zoolength - currpos);              
  1269. X         exit (1);
  1270. X#endif
  1271. X   }
  1272. X   if (direntry.next == 0L) {                /* END OF CHAIN */
  1273. X      break;                                 /* EXIT on end of chain */
  1274. X   }
  1275. X   next_ptr = direntry.next;                 /* ptr to next dir entry */
  1276. X
  1277. X   whichname = choosefname(&direntry);       /* which filename */
  1278. X   fixfname(whichname);                      /* fix syntax */
  1279. X    strcpy (matchname, fullpath (&direntry));    /* get full pathname */
  1280. X
  1281. X   if (todot && *direntry.dirname == *PATH_CH) {
  1282. X      char tmpstr[PATHSIZE];
  1283. X      strcpy(tmpstr, direntry.dirname);
  1284. X      strcpy(direntry.dirname,CUR_DIR);
  1285. X      strcat(direntry.dirname, tmpstr);
  1286. X   }
  1287. X
  1288. X   /* matchname now holds the full pathname for pattern matching */
  1289. X
  1290. X   if ( ( (needdel && direntry.deleted) ||
  1291. X            (needdel < 2 && !direntry.deleted)
  1292. X        ) && needed(matchname)) {
  1293. X      matched++;           /* update count of files extracted */
  1294. X
  1295. X      if (direntry.major_ver > MAJOR_EXT_VER ||
  1296. X         (direntry.major_ver == MAJOR_EXT_VER && 
  1297. X            direntry.minor_ver > MINOR_EXT_VER)) {
  1298. X
  1299. X#ifdef OOZ
  1300. X            prterror ('e', extract_ver, whichname, ".\n");
  1301. X#else
  1302. X            prterror ('e', extract_ver, direntry.major_ver, 
  1303. X                           direntry.minor_ver, whichname);
  1304. X#endif
  1305. X            goto loop_again;
  1306. X      }
  1307. X
  1308. X      /* 
  1309. X      If extracting to null device, or if user requested extraction
  1310. X      of entire path, include any directory name in filename.
  1311. X      If extraction to current directory requested, and if extfname
  1312. X      begins with path separator, fix it */
  1313. X
  1314. X      strcpy (extfname, whichname);
  1315. X      if ((usepath || null_device) && direntry.dirlen > 0) {
  1316. X         combine(extfname, direntry.dirname, whichname);
  1317. X         if (usepath > 1 && !null_device)
  1318. X            makepath(direntry.dirname);         /* make dir prefix */
  1319. X      }
  1320. X
  1321. X      if (tofile) {
  1322. X         int present = 0;
  1323. X
  1324. X#ifndef OOZ
  1325. X#ifndef PORTABLE
  1326. X         /* 
  1327. X         if Z format (fast) extraction, extension is created as
  1328. X         follows:  for no current extension, new extension is "zzz";
  1329. X         for current extension "a", new extension is "azz";  for 
  1330. X         current extension "ab", new extension is "azb";  and for
  1331. X         current extension "abc", new extension is "azc".
  1332. X         */
  1333. X           
  1334. X         if (fast_ext) {
  1335. X            int length;
  1336. X            struct path_st path_st;
  1337. X            parse (&path_st, extfname);         /* split filename */
  1338. X            strcpy (extfname, path_st.fname);   /* just root filename */
  1339. X            length = strlen (path_st.ext);
  1340. X            strcat (extfname, ".");
  1341. X            if (length == 0)
  1342. X               strcat (extfname, "zzz");        /* no ext -> .zzz */
  1343. X            else if (length == 1) {
  1344. X               strcat (extfname, path_st.ext);
  1345. X               strcat (extfname, "zz");         /* *.?    -> *.?zz */
  1346. X            } else { /* length is 2 or 3 */
  1347. X               if (length == 2)                 /* allow .aa, .ab, etc. */
  1348. X                  path_st.ext[2] = path_st.ext[1];
  1349. X               path_st.ext[1] = 'z';
  1350. X               strcat (extfname, path_st.ext);  /* *.??   -> *.?z? */
  1351. X            }
  1352. X         }
  1353. X#endif   /* ifndef PORTABLE */
  1354. X#endif   /* ifndef OOZ */
  1355. X
  1356. X
  1357. X         if (overwrite) {
  1358. X            this_han = CREATE(extfname, F_RDWR);
  1359. X         } else {
  1360. X            if (exists (extfname)) {
  1361. X               present = 1;
  1362. X               this_han = -1;
  1363. X            } else
  1364. X               this_han = CREATE(extfname, F_RDWR);
  1365. X         }
  1366. X         if (this_han == -1) {
  1367. X            if (present == 1) {      /* if file exists already */
  1368. X               do {
  1369. X
  1370. X#ifdef OOZ
  1371. X                     putstr ("Overwrite "); putstr (extfname);
  1372. X                     putstr (" (Yes/No/All)? ");
  1373. X#else
  1374. X                     printf ("Overwrite %s (Yes/No/All)? ", extfname);
  1375. X#endif
  1376. X                  fflush (stdin);
  1377. X                  fgets (ans, 3, stdin);
  1378. X                  strlwr (ans);
  1379. X               } while (*ans != 'y' && *ans != 'n' && *ans != 'a');
  1380. X   
  1381. X               /* NOTE:  We use CREATE even if we are trying to overwrite
  1382. X                  the file, because a data path utility (Search or Dpath)
  1383. X                  could have fooled us before. */
  1384. X               if (*ans == 'a')
  1385. X                  overwrite++;
  1386. X               if (*ans == 'y' || *ans == 'a') {
  1387. X                  this_han = CREATE(extfname, F_RDWR);
  1388. X                  error_message = 1; /* give error message if open fails */
  1389. X               } else {
  1390. X                  error_message = 0; /* user said 'n', so no error message */
  1391. X               }
  1392. X            } else {
  1393. X               error_message = 1;   /* Real error -- give error message */
  1394. X            }
  1395. X         } /* end if */
  1396. X      } /* end if */
  1397. X
  1398. X      if (this_han == -1) {         /* file couldn't be opened */
  1399. X         if (error_message == 1) {
  1400. X            unlink (extfname);
  1401. X#ifdef OOZ
  1402. X               prterror ('e', could_not_open, extfname, " for output.\n");
  1403. X#else
  1404. X               prterror ('e', "Can't open %s for output.\n", extfname);
  1405. X#endif
  1406. X
  1407. X#ifndef PORTABLE
  1408. X            /* if error was due to full disk, abort */
  1409. X            if (space(0, &alloc_size) < alloc_size)
  1410. X#endif
  1411. X               prterror ('f', disk_full, (char *) NULL, (char *) NULL);
  1412. X
  1413. X         }
  1414. X      } else if (lseek (zoo_han, direntry.offset, 0) == -1L) {
  1415. X         prterror ('e', "Could not seek to file data.\n");
  1416. X         close_han (this_han);
  1417. X      } else {
  1418. X#ifndef PORTABLE
  1419. X         /* check Dos's free disk space if we seem to be running low 
  1420. X            (within 1 cluster of being full) */
  1421. X         if (tofile && disk_space < direntry.org_size + alloc_size) {
  1422. X            disk_space = space (0, &alloc_size);
  1423. X            if (disk_space < alloc_size) {
  1424. X               close_han (this_han);
  1425. X               unlink (extfname);
  1426. X               prterror ('f', disk_full, (char *) NULL, (char *) NULL);
  1427. X            }              
  1428. X         }
  1429. X#endif
  1430. X         if (tofile && disk_space < direntry.org_size) {
  1431. X#ifdef PORTABLE
  1432. X            ;
  1433. X#else
  1434. X#ifdef OOZ
  1435. X               prterror ('e', no_space, extfname, ".\n");
  1436. X#else
  1437. X               prterror ('e', no_space, extfname);
  1438. X#endif
  1439. X
  1440. X            unlink (extfname);               /* delete any created file */
  1441. X#endif   /* portable */
  1442. X
  1443. X         } else { 
  1444. X
  1445. X#ifndef OOZ
  1446. X#ifndef PORTABLE
  1447. X            if (fast_ext) {            /* fast ext -> create header */
  1448. X               void make_tnh();
  1449. X               struct tiny_header tiny_header;
  1450. X               make_tnh(&tiny_header, &direntry);
  1451. X               write (this_han, (char *) &tiny_header, sizeof (tiny_header));
  1452. X
  1453. X               if (direntry.cmt_size != 0) { /* copy comment */
  1454. X                  long save_pos;
  1455. X                  save_pos = tell (zoo_han);
  1456. X                  lseek (zoo_han, direntry.comment, 0);
  1457. X                  getfile (zoo_han, this_han, 
  1458. X                          (long) direntry.cmt_size, 0);
  1459. X                  lseek (zoo_han, save_pos, 0);
  1460. X               }
  1461. X            }
  1462. X#endif /* ifndef PORTABLE */
  1463. X#endif /* ifndef OOZ */
  1464. X
  1465. X            crccode = 0;      /* Initialize CRC before extraction */
  1466. X#ifdef OOZ
  1467. X               putstr (extfname); 
  1468. X               {
  1469. X                  register int i;
  1470. X                  for (i = strlen(direntry.fname); i < 13; i++)
  1471. X                     putstr (" ");
  1472. X                  putstr ("-- ");
  1473. X               }
  1474. X#else
  1475. X               if (!pipe) {
  1476. X#ifdef PORTABLE
  1477. X                  prterror ('m', "%-14s -- ", extfname);
  1478. X#else
  1479. X                  if (fast_ext)
  1480. X                     prterror ('m', "%-12s ==> %-12s -- ", 
  1481. X                        direntry.fname, extfname);
  1482. X                  else
  1483. X                     prterror ('m', "%-12s -- ", extfname);
  1484. X#ifdef COMMENT
  1485. X                  prterror ('m', 
  1486. X                        fast_ext ? "%-12s ==> %-12s -- " : "%-12s -- ",
  1487. X                        direntry.fname, extfname);
  1488. X#endif /* COMMENT */
  1489. X#endif /* PORTABLE */
  1490. X
  1491. X               } else {            /* must be pipe */
  1492. X                  prterror ('M', "\n\n********\n%s\n********\n", direntry.fname);
  1493. X
  1494. X#ifdef COMMENT
  1495. X#ifdef SETMODE
  1496. X                  MODE_BIN(this_han);           /* make std output binary so
  1497. X                                                   ^Z won't cause error */
  1498. X#endif
  1499. X#endif
  1500. X               }
  1501. X#endif /* OOZ */
  1502. X
  1503. X#ifndef NOSIGNAL
  1504. X#ifndef OOZ
  1505. X            if (tofile)
  1506. X#endif /* not OOZ */
  1507. X               {
  1508. X                  oldsignal = signal (SIGINT, SIG_IGN);
  1509. X                  if (oldsignal != SIG_IGN) 
  1510. X                     signal (SIGINT, ctrl_c); /* Trap ^C & erase partial file */
  1511. X               }
  1512. X#endif /* not NOSIGNAL */
  1513. X
  1514. X            if (direntry.packing_method == 0)
  1515. X               /* 4th param 1 means CRC update */
  1516. X               status = getfile (zoo_han, this_han, direntry.size_now, 1);
  1517. X
  1518. X#ifndef OOZ
  1519. X            else if (fast_ext)
  1520. X               /* 4th param 0 means no CRC update */
  1521. X               status = getfile (zoo_han, this_han, direntry.size_now, 0);
  1522. X#endif
  1523. X
  1524. X
  1525. X            else if (direntry.packing_method == 1)
  1526. X               status = lzd (zoo_han, this_han); /* uncompress */
  1527. X            else {
  1528. X#ifdef OOZ
  1529. X               prterror ('e', "File ", whichname,
  1530. X                  ":  impossible packing method.\n", "");
  1531. X#else
  1532. X               prterror ('e', "File %s:  impossible packing method.\n",
  1533. X                  whichname);
  1534. X#endif
  1535. X                  unlink(extfname);
  1536. X                  goto loop_again;
  1537. X            }
  1538. X
  1539. X
  1540. X#ifndef NOSIGNAL
  1541. X#ifndef OOZ
  1542. X            if (tofile)
  1543. X#endif /* not OOZ */
  1544. X               signal (SIGINT, oldsignal);
  1545. X#endif /* not NOSIGNAL */
  1546. X
  1547. X#ifdef COMMENT
  1548. X#ifndef OOZ
  1549. X#ifdef SETMODE
  1550. X            if (pipe)
  1551. X               MODE_TEXT(this_han);          /* restore text mode */
  1552. X#endif
  1553. X#endif
  1554. X#endif
  1555. X   
  1556. X#ifndef OOZ
  1557. X            if (tofile) {
  1558. X#endif
  1559. X               /* set date/time of file being extracted */
  1560. X#ifdef NIXTIME
  1561. X               close_han (this_han);
  1562. X               setutime (extfname, direntry.date, direntry.time);
  1563. X#else
  1564. X               settime (this_han, direntry.date, direntry.time);
  1565. X               close_han (this_han);
  1566. X#endif
  1567. X#ifndef OOZ
  1568. X            }
  1569. X#endif
  1570. X            if (status != 0) {
  1571. X               if (tofile)
  1572. X                  unlink (extfname);
  1573. X               if (status == 1) {
  1574. X                  memerr();
  1575. X               /* To avoid spurious errors due to ^Z being sent to screen,
  1576. X                  we don't check for I/O error if output was piped */
  1577. X               } else if (!pipe && (status == 2 || status == 3)) {
  1578. X#ifdef OOZ
  1579. X                     prterror ('e', no_space, direntry.fname, ".\n");
  1580. X#else
  1581. X                     prterror ('e', no_space, direntry.fname);
  1582. X#endif
  1583. X               }
  1584. X            } else {
  1585. X               /* file extracted, so update disk space.  */
  1586. X               /* we subtract the original size of the file, rounded
  1587. X                  UP to the nearest multiple of the disk allocation
  1588. X                  size. */
  1589. X#ifndef PORTABLE
  1590. X               {
  1591. X                  unsigned long temp;
  1592. X                  temp = (direntry.org_size + alloc_size) / alloc_size;
  1593. X                  disk_space -= temp * alloc_size;
  1594. X               }
  1595. X#endif
  1596. X
  1597. X#ifdef OOZ
  1598. X               if (direntry.file_crc != crccode)
  1599. X                  putstr ("extracted  \007WARNING:  Bad CRC.\n");
  1600. X               else
  1601. X                  putstr ("extracted\n");
  1602. X#else
  1603. X               if (!fast_ext && direntry.file_crc != crccode) {
  1604. X                  badcrc_count++;
  1605. X                  if (!pipe) {
  1606. X                     if (!null_device)
  1607. X                        prterror ('M', "extracted   ");
  1608. X                     prterror ('w', bad_crc, direntry.fname);
  1609. X                  }
  1610. X                  else {   /* duplicate to standard error */
  1611. X                     static char stars[] = "\n******\n";
  1612. X                     putstr (stars);
  1613. X                     prterror ('w', bad_crc, direntry.fname);
  1614. X                     putstr (stars);
  1615. X                     fprintf (stderr, "WARNING:  ");
  1616. X                     fprintf (stderr, bad_crc, direntry.fname);
  1617. X                  }
  1618. X               } else
  1619. X                  if (!pipe)
  1620. X                     prterror ('M', null_device ? "OK\n" : "extracted\n");
  1621. X#endif
  1622. X
  1623. X            } /* end if */
  1624. X         } /* end if */
  1625. X      } /* end if */
  1626. X   } /* end if */
  1627. X
  1628. Xloop_again:
  1629. X   lseek (zoo_han, next_ptr, 0); /* ..seek to next dir entry */
  1630. X} /* end while */
  1631. X
  1632. Xclose (zoo_han);
  1633. Xif (!matched)
  1634. X   putstr (no_match);
  1635. X
  1636. X#ifndef OOZ
  1637. Xif (badcrc_count) {
  1638. X   prterror ('w', "%d File(s) with bad CRC.\n", badcrc_count);
  1639. X   exit (1);
  1640. X} else if (null_device)
  1641. X   prterror ('m', "Archive seems OK.\n");
  1642. X#endif
  1643. X
  1644. X} /* end zooext */
  1645. X
  1646. X/* close_han() */
  1647. X/* closes a handle if and only if we aren't sending output to 
  1648. X   a pipe or to the null device */
  1649. X
  1650. Xvoid close_han (handle)
  1651. Xint handle;
  1652. X{
  1653. X   if (tofile)
  1654. X      close (handle);
  1655. X}
  1656. X
  1657. X/* Ctrl_c() is called if ^C is hit while a file is being extracted.
  1658. X   It closes the files, deletes it, and exits. */
  1659. Xint ctrl_c()
  1660. X{
  1661. X#ifndef NOSIGNAL
  1662. X   signal (SIGINT, SIG_IGN);     /* ignore any more */
  1663. X#endif
  1664. X   close (this_han);
  1665. X   unlink (extfname);
  1666. X   exit (1);
  1667. X}
  1668. X
  1669. X/* make_tnh copies creates a tiny_header */
  1670. Xvoid make_tnh (tiny_header, direntry)
  1671. Xstruct tiny_header *tiny_header;
  1672. Xstruct direntry *direntry;
  1673. X{
  1674. X   tiny_header->tinytag = TINYTAG;
  1675. X   tiny_header->type = 1;
  1676. X   tiny_header->packing_method = direntry->packing_method;
  1677. X   tiny_header->date = direntry->date;
  1678. X   tiny_header->time = direntry->time;
  1679. X   tiny_header->file_crc = direntry->file_crc;
  1680. X   tiny_header->org_size = direntry->org_size;
  1681. X   tiny_header->size_now = direntry->size_now;
  1682. X   tiny_header->major_ver = direntry->major_ver;
  1683. X   tiny_header->minor_ver = direntry->minor_ver;
  1684. X   tiny_header->cmt_size = direntry->cmt_size;
  1685. X   strcpy (tiny_header->fname, direntry->fname);
  1686. X} 
  1687. SHAR_EOF
  1688. fi
  1689. if test -f 'zoofns.h'
  1690. then
  1691.     echo shar: "will not over-write existing file 'zoofns.h'"
  1692. else
  1693. sed 's/^X//' << \SHAR_EOF > 'zoofns.h'
  1694. X/* @(#) zoofns.h 1.7 87/05/03 16:02:33 */
  1695. X
  1696. X/*
  1697. XThe contents of this file are hereby released to the public domain.
  1698. X
  1699. X                           -- Rahul Dhesi 1986/11/14
  1700. X*/
  1701. X
  1702. X
  1703. X/* Defines function declarations for all Zoo functions */
  1704. X
  1705. X#ifdef LINT_ARGS
  1706. Xlong calc_ofs(char *);
  1707. Xchar *addext (char *, char *);
  1708. Xchar *choosefname (struct direntry *);
  1709. Xchar *combine (char[], char *, char *);
  1710. Xchar *emalloc (unsigned int);
  1711. Xchar *erealloc (char *, unsigned int);
  1712. Xchar *findlast (char *, char *);
  1713. Xchar *fixfname (char *);
  1714. Xchar *fullpath (struct direntry *);
  1715. Xchar *getstdin ();
  1716. Xchar *lastptr (char *);
  1717. Xchar *nameptr (char *);
  1718. Xchar *newcat (char *, char *);
  1719. Xchar *memset (char *, int, unsigned);
  1720. Xchar *nextfile (int, char *, int);
  1721. Xint addfile (int, int);
  1722. Xint cfactor (long, long);
  1723. Xint chname (char *, char *);
  1724. Xint cmpnum (unsigned int, unsigned int, unsigned int, unsigned int);
  1725. Xint ctrl_c();
  1726. Xint exists (char *);
  1727. Xint frd_zooh (struct zoo_header *, FILE *);
  1728. Xint frd_dir (struct direntry *, FILE *);
  1729. Xint fwr_dir (struct direntry *, FILE *);
  1730. Xint fwr_zooh (struct zoo_header *, FILE *);
  1731. Xint getfile (int, int, long, int);
  1732. Xint handle_break();
  1733. Xint kill_files (char *[], int);
  1734. Xint lzc (int, int);
  1735. Xint lzd (int, int);
  1736. Xint match_half (char *, char *);
  1737. Xint match (char *, char *);
  1738. Xint readdir (struct direntry *, FILE *, int);
  1739. Xint settime (int, unsigned int, unsigned int);
  1740. Xint strcmpi (char *, char *);
  1741. Xint rd_zooh (struct zoo_header *, int);
  1742. Xint rd_dir (struct direntry *, int);
  1743. Xint wr_zooh (struct zoo_header *, int);
  1744. Xint wr_dir (struct direntry *, int);
  1745. Xlong inlist (char *, unsigned int *, unsigned int *, int);
  1746. Xlong tell (int);
  1747. Xunsigned long space (int, int *);
  1748. Xvoid addbfcrc(char *, int);
  1749. Xvoid addfname (char *, long, unsigned int, unsigned int);
  1750. Xvoid basename (char *, char []);
  1751. Xvoid break_off();
  1752. Xvoid close_han (int);
  1753. Xvoid comment (char *, char *);
  1754. Xvoid extension (char *, char []);
  1755. Xvoid fcbpath (struct dta_t *, char *, char *);
  1756. Xvoid fixslash (char *);
  1757. Xvoid makelist (int, char *[], char *[], int, char *, char *, char *, int *);
  1758. Xvoid memerr();
  1759. Xvoid newdir (struct direntry *);
  1760. Xvoid parse (struct path_st *, char *);
  1761. Xvoid prterror(int, char *, );
  1762. Xvoid rootname (char *, char *);
  1763. Xvoid skip_files (FILE *, unsigned int *, unsigned int *, int *, 
  1764. X                  char [], long *);
  1765. Xvoid writedir (struct direntry *, FILE *);
  1766. Xvoid writenull (int, int);
  1767. Xvoid zooadd(char *, int, char **, char *);
  1768. Xvoid zoodel(char *, char *, int);
  1769. Xvoid zooext(char *, char *);
  1770. Xvoid zoolist(char **, char *, int);
  1771. Xvoid zoopack (char *, char *);
  1772. X
  1773. X#else
  1774. X/* if no LINT_ARGS */
  1775. X
  1776. Xlong calc_ofs();
  1777. Xchar *addext ();
  1778. Xchar *choosefname ();
  1779. Xchar *combine ();
  1780. Xchar *emalloc ();
  1781. Xchar *erealloc ();
  1782. Xchar *findlast ();
  1783. Xchar *fixfname ();
  1784. Xchar *fullpath ();
  1785. Xchar *getstdin ();
  1786. Xchar *lastptr ();
  1787. Xchar *nameptr ();
  1788. Xchar *newcat ();
  1789. Xchar *memset ();
  1790. Xchar *nextfile ();
  1791. Xint addfile ();
  1792. Xint cfactor ();
  1793. Xint chname ();
  1794. Xint cmpnum ();
  1795. Xint ctrl_c();
  1796. Xint exists ();
  1797. Xint frd_zooh ();
  1798. Xint frd_dir ();
  1799. Xint fwr_dir ();
  1800. Xint fwr_zooh ();
  1801. Xint getfile ();
  1802. Xint handle_break();
  1803. Xint kill_files ();
  1804. Xint lzc ();
  1805. Xint lzd ();
  1806. Xint match_half ();
  1807. Xint match ();
  1808. Xint readdir ();
  1809. Xint settime ();
  1810. Xint strcmpi ();
  1811. Xint rd_zooh ();
  1812. Xint rd_dir ();
  1813. Xint wr_zooh ();
  1814. Xint wr_dir ();
  1815. Xlong inlist ();
  1816. Xlong tell ();
  1817. Xunsigned long space ();
  1818. Xvoid addbfcrc();
  1819. Xvoid addfname ();
  1820. Xvoid basename ();
  1821. Xvoid break_off();
  1822. Xvoid close_han ();
  1823. Xvoid comment ();
  1824. Xvoid extension ();
  1825. Xvoid fcbpath ();
  1826. Xvoid fixslash ();
  1827. Xvoid makelist ();
  1828. Xvoid memerr();
  1829. Xvoid newdir ();
  1830. Xvoid parse ();
  1831. Xvoid prterror();
  1832. Xvoid rootname ();
  1833. Xvoid skip_files ();
  1834. Xvoid writedir ();
  1835. Xvoid writenull ();
  1836. Xvoid zooadd();
  1837. Xvoid zoodel();
  1838. Xvoid zooext();
  1839. Xvoid zoolist();
  1840. Xvoid zoopack ();
  1841. X#endif /* end of no LINT_ARGS */
  1842. SHAR_EOF
  1843. fi
  1844. exit 0
  1845. #    End of shell archive
  1846. -- 
  1847. Rahul Dhesi         UUCP:  {ihnp4,seismo}!{iuvax,pur-ee}!bsu-cs!dhesi
  1848.  
  1849. -- 
  1850.  
  1851. Rich $alz
  1852. Cronus Project, BBN Labs            rsalz@bbn.com
  1853. Moderator, comp.sources.unix            sources@uunet.uu.net
  1854.