home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / unzip52.zip / list.c < prev    next >
C/C++ Source or Header  |  1996-04-27  |  25KB  |  662 lines

  1. /*---------------------------------------------------------------------------
  2.  
  3.   list.c
  4.  
  5.   This file contains the non-ZipInfo-specific listing routines for UnZip.
  6.  
  7.   Contains:  list_files()
  8.              ratio()
  9.              fnprint()
  10.  
  11.   ---------------------------------------------------------------------------*/
  12.  
  13.  
  14. #define UNZIP_INTERNAL
  15. #include "unzip.h"
  16. #ifdef MSWIN
  17. #  include <windows.h>
  18. #  include "wingui\wizunzip.h"
  19. #endif
  20.  
  21.  
  22. /* Headers also referenced in UpdateListBox() in updatelb.c (Windows version) */
  23.  
  24. #ifdef OS2_EAS
  25.    char Far HeadersS[]  = " Length    EAs   ACLs    Date    Time    Name";
  26.    char Far HeadersS1[] = " ------    ---   ----    ----    ----    ----";
  27. #else
  28.    char Far HeadersS[]  = " Length    Date    Time    Name";
  29.    char Far HeadersS1[] = " ------    ----    ----    ----";
  30. #endif
  31.  
  32. char Far HeadersL[]  =
  33.   " Length  Method   Size  Ratio   Date    Time   CRC-32     Name";
  34. char Far HeadersL1[] =
  35.   " ------  ------   ----  -----   ----    ----   ------     ----";
  36.  
  37. char Far *Headers[][2] = { {HeadersS, HeadersS1}, {HeadersL, HeadersL1} };
  38.  
  39. static char Far CompFactorStr[] = "%c%d%%";
  40. static char Far CompFactor100[] = "100%%";
  41. #ifdef MSWIN
  42.    static char Far LongHdrStats[] =
  43.      "%7lu  %-7s%7lu %4s  %02u-%02u-%02u  %02u:%02u  %08lx  %c%s";
  44.    static char Far LongFileTrailer[] =
  45.      "%7lu         %7lu %4s                              %u file%s";
  46.    static char Far ShortHdrStats[] = "%7lu  %02u-%02u-%02u  %02u:%02u  %c%s";
  47.    static char Far ShortFileTrailer[] = "%7lu                    %u file%s";
  48. #else /* !MSWIN */
  49.    static char Far CaseConversion[] = "%s (\"^\" ==> case\n%s   conversion)\n";
  50.    static char Far LongHdrStats[] =
  51.      "%7lu  %-7s%7lu %4s  %02u-%02u-%02u  %02u:%02u  %08lx  %c";
  52.    static char Far LongFileTrailer[] =
  53.      " ------          ------  ---                         \
  54.      -------\n%7lu         %7lu %4s                              %u file%s\n";
  55. #ifdef OS2_EAS
  56.    static char Far ShortHdrStats[] = "%7lu %6lu %6lu  %02u-%02u-%02u  %02u:%02u  %c";
  57.    static char Far ShortFileTrailer[] = " ------  -----  -----        \
  58.             -------\n%7lu %6lu %6lu                    %u file%s\n";
  59.    static char Far OS2ExtAttrTrailer[] =
  60.       "%ld file%s %ld bytes of OS/2 extended attributes attached.\n";
  61.    static char Far OS2ACLTrailer[] =
  62.       "%ld file%s %ld bytes of access control lists attached.\n";
  63. #else
  64.    static char Far ShortHdrStats[] = "%7lu  %02u-%02u-%02u  %02u:%02u  %c";
  65.    static char Far ShortFileTrailer[] =
  66.      " ------                    -------\n%7lu                    %u file%s\n";
  67. #endif
  68. #endif /* ?MSWIN */
  69.  
  70.  
  71.  
  72.  
  73.  
  74. /*************************/
  75. /* Function list_files() */
  76. /*************************/
  77.  
  78. int list_files(__G)    /* return PK-type error code */
  79.     __GDEF
  80. {
  81.     char sgn, cfactorstr[10];
  82.     int do_this_file=FALSE, cfactor, error, error_in_archive=PK_COOL;
  83.     int longhdr=(G.vflag>1), date_format;
  84.     unsigned methnum;
  85. #ifdef USE_EF_UX_TIME
  86.     ztimbuf z_utime;
  87. #endif
  88.     ush j, yr, mo, dy, hh, mm, members=0;
  89.     ulg csiz, tot_csize=0L, tot_ucsize=0L;
  90. #ifdef OS2_EAS
  91.     ulg ea_size, tot_easize=0L, tot_eafiles=0L;
  92.     ulg acl_size, tot_aclsize=0L, tot_aclfiles=0L;
  93. #endif
  94. #ifdef MSWIN
  95.     PSTR psLBEntry;  /* list box entry */
  96. #endif
  97.     min_info info;
  98.     char methbuf[8];
  99.     static char dtype[]="NXFS";   /* see zi_short() */
  100.     static char Far method[NUM_METHODS+1][8] =
  101.         {"Stored", "Shrunk", "Reduce1", "Reduce2", "Reduce3", "Reduce4",
  102.          "Implode", "Token", "Defl:#", "Unk:###"};
  103.  
  104.  
  105.  
  106. /*---------------------------------------------------------------------------
  107.     Unlike extract_or_test_files(), this routine confines itself to the cen-
  108.     tral directory.  Thus its structure is somewhat simpler, since we can do
  109.     just a single loop through the entire directory, listing files as we go.
  110.  
  111.     So to start off, print the heading line and then begin main loop through
  112.     the central directory.  The results will look vaguely like the following:
  113.  
  114.   Length  Method   Size  Ratio   Date    Time   CRC-32     Name ("^" ==> case
  115.   ------  ------   ----  -----   ----    ----   ------     ----   conversion)
  116.    44004  Implode  13041  71%  11-02-89  19:34  8b4207f7   Makefile.UNIX
  117.     3438  Shrunk    2209  36%  09-15-90  14:07  a2394fd8  ^dos-file.ext
  118.   ---------------------------------------------------------------------------*/
  119.  
  120.     G.pInfo = &info;
  121.     date_format = DATE_FORMAT;
  122.  
  123. #ifndef MSWIN
  124.     if (G.qflag < 2)
  125.         if (G.L_flag)
  126.             Info(slide, 0, ((char *)slide, LoadFarString(CaseConversion),
  127.               LoadFarStringSmall(Headers[longhdr][0]),
  128.               LoadFarStringSmall2(Headers[longhdr][1])));
  129.         else
  130.             Info(slide, 0, ((char *)slide, "%s\n%s\n",
  131.                LoadFarString(Headers[longhdr][0]),
  132.                LoadFarStringSmall(Headers[longhdr][1])));
  133. #endif /* !MSWIN */
  134.  
  135.     for (j = 0; j < G.ecrec.total_entries_central_dir; ++j) {
  136.  
  137.         if (readbuf(__G__ G.sig, 4) == 0)
  138.             return PK_EOF;
  139.         if (strncmp(G.sig, G.central_hdr_sig, 4)) {  /* just to make sure */
  140.             Info(slide, 0x401, ((char *)slide, LoadFarString(CentSigMsg), j));
  141.             Info(slide, 0x401, ((char *)slide, LoadFarString(ReportMsg)));
  142.             return PK_BADERR;
  143.         }
  144.         /* process_cdir_file_hdr() sets pInfo->lcflag: */
  145.         if ((error = process_cdir_file_hdr(__G)) != PK_COOL)
  146.             return error;       /* only PK_EOF defined */
  147.  
  148.         /*
  149.          * We could DISPLAY the filename instead of storing (and possibly trun-
  150.          * cating, in the case of a very long name) and printing it, but that
  151.          * has the disadvantage of not allowing case conversion--and it's nice
  152.          * to be able to see in the listing precisely how you have to type each
  153.          * filename in order for unzip to consider it a match.  Speaking of
  154.          * which, if member names were specified on the command line, check in
  155.          * with match() to see if the current file is one of them, and make a
  156.          * note of it if it is.
  157.          */
  158.  
  159.         if ((error = do_string(__G__ G.crec.filename_length, DS_FN)) !=
  160.              PK_COOL)   /*  ^--(uses pInfo->lcflag) */
  161.         {
  162.             error_in_archive = error;
  163.             if (error > PK_WARN)   /* fatal:  can't continue */
  164.                 return error;
  165.         }
  166.         if (G.extra_field != (uch *)NULL) {
  167.             free(G.extra_field);
  168.             G.extra_field = (uch *)NULL;
  169.         }
  170.         if ((error = do_string(__G__ G.crec.extra_field_length, EXTRA_FIELD))
  171.             != 0)
  172.         {
  173.             error_in_archive = error;
  174.             if (error > PK_WARN)      /* fatal */
  175.                 return error;
  176.         }
  177.         if (!G.process_all_files) {   /* check if specified on command line */
  178.             char **pfn = G.pfnames-1;
  179.  
  180.             do_this_file = FALSE;
  181.             while (*++pfn)
  182.                 if (match(G.filename, *pfn, G.C_flag)) {
  183.                     do_this_file = TRUE;
  184.                     break;       /* found match, so stop looping */
  185.                 }
  186.             if (do_this_file) {  /* check if this is an excluded file */
  187.                 char **pxn = G.pxnames-1;
  188.  
  189.                 while (*++pxn)
  190.                     if (match(G.filename, *pxn, G.C_flag)) {
  191.                         do_this_file = FALSE;  /* ^-- ignore case in match */
  192.                         break;
  193.                     }
  194.             }
  195.         }
  196.         /*
  197.          * If current file was specified on command line, or if no names were
  198.          * specified, do the listing for this file.  Otherwise, get rid of the
  199.          * file comment and go back for the next file.
  200.          */
  201.  
  202.         if (G.process_all_files || do_this_file) {
  203.  
  204. #ifdef OS2API  /* OS2DLL */
  205.             /* this is used by UzpFileTree() to allow easy processing of lists
  206.              * of zip directory contents */
  207.             if (G.processExternally)
  208.                 if ((G.processExternally)(G.filename, &G.crec))
  209.                     break;
  210.                 else
  211.                     continue;
  212. #endif
  213. #ifdef OS2_EAS
  214.             {
  215.                 uch *ef_ptr = G.extra_field;
  216.                 int ef_size, ef_len = G.crec.extra_field_length;
  217.                 ea_size = acl_size = 0;
  218.  
  219.                 while (ef_len >= EB_HEADSIZE) {
  220.                     ef_size = makeword(&ef_ptr[EB_LEN]);
  221.                     switch (makeword(&ef_ptr[EB_ID])) {
  222.                         case EF_OS2:
  223.                             ea_size = makelong(&ef_ptr[EB_HEADSIZE]);
  224.                             break;
  225.                         case EF_ACL:
  226.                             acl_size = makelong(&ef_ptr[EB_HEADSIZE]);
  227.                             break;
  228.                     }
  229.                     ef_ptr += (ef_size + EB_HEADSIZE);
  230.                     ef_len -= (ef_size + EB_HEADSIZE);
  231.                 }
  232.             }
  233. #endif
  234. #ifdef USE_EF_UX_TIME
  235.             if (G.extra_field &&
  236.                 ef_scan_for_izux(G.extra_field, G.crec.extra_field_length,
  237.                                  &z_utime, NULL) > 0) {
  238.                 struct tm *t = localtime(&(z_utime.modtime));
  239.                 switch (date_format) {
  240.                     case DF_YMD:
  241.                         mo = (ush)(t->tm_year);
  242.                         dy = (ush)(t->tm_mon + 1);
  243.                         yr = (ush)(t->tm_mday);
  244.                         break;
  245.                     case DF_DMY:
  246.                         mo = (ush)(t->tm_mday);
  247.                         dy = (ush)(t->tm_mon + 1);
  248.                         yr = (ush)(t->tm_year);
  249.                         break;
  250.                     default:
  251.                         mo = (ush)(t->tm_mon + 1);
  252.                         dy = (ush)(t->tm_mday);
  253.                         yr = (ush)(t->tm_year);
  254.                 }
  255.                 hh = (ush)(t->tm_hour);
  256.                 mm = (ush)(t->tm_min);
  257.             } else
  258. #endif /* USE_EF_UX_TIME */
  259.             {
  260.                 yr = (ush)((((G.crec.last_mod_file_date >> 9) & 0x7f) + 80) %
  261.                            (unsigned)100);
  262.                 mo = (ush)((G.crec.last_mod_file_date >> 5) & 0x0f);
  263.                 dy = (ush)(G.crec.last_mod_file_date & 0x1f);
  264.  
  265.                 /* permute date so it displays according to nat'l convention */
  266.                 switch (date_format) {
  267.                     case DF_YMD:
  268.                         hh = mo; mo = yr; yr = dy; dy = hh;
  269.                         break;
  270.                     case DF_DMY:
  271.                         hh = mo; mo = dy; dy = hh;
  272.                 }
  273.  
  274.                 hh = (ush)((G.crec.last_mod_file_time >> 11) & 0x1f);
  275.                 mm = (ush)((G.crec.last_mod_file_time >> 5) & 0x3f);
  276.             }
  277.  
  278.             csiz = G.crec.csize;
  279.             if (G.crec.general_purpose_bit_flag & 1)
  280.                 csiz -= 12;   /* if encrypted, don't count encryption header */
  281.             if ((cfactor = ratio(G.crec.ucsize, csiz)) < 0) {
  282.                 sgn = '-';
  283.                 cfactor = (-cfactor + 5) / 10;
  284.             } else {
  285.                 sgn = ' ';
  286.                 cfactor = (cfactor + 5) / 10;
  287.             }
  288.             if (cfactor == 100)
  289.                 sprintf(cfactorstr, LoadFarString(CompFactor100));
  290.             else
  291.                 sprintf(cfactorstr, LoadFarString(CompFactorStr), sgn, cfactor);
  292.  
  293.             methnum = MIN(G.crec.compression_method, NUM_METHODS);
  294.             zfstrcpy(methbuf, method[methnum]);
  295.             if (methnum == DEFLATED) {
  296.                 methbuf[5] = dtype[(G.crec.general_purpose_bit_flag>>1) & 3];
  297.             } else if (methnum >= NUM_METHODS) {
  298.                 sprintf(&methbuf[4], "%03u", G.crec.compression_method);
  299.             }
  300.  
  301. #if 0       /* GRR/Euro:  add this? */
  302. #if defined(DOS_OS2_W32) || defined(UNIX)
  303.             for (p = G.filename;  *p;  ++p)
  304.                 if (!isprint(*p))
  305.                     *p = '?';  /* change non-printable chars to '?' */
  306. #endif /* DOS_OS2_W32 || UNIX */
  307. #endif /* 0 */
  308.  
  309. #ifdef MSWIN
  310. #ifdef NEED_EARLY_REDRAW
  311.             /* turn on listbox redrawing just before adding last line */
  312.             if (j == (G.ecrec.total_entries_central_dir-1))
  313.                 (void)SendMessage(hWndList, WM_SETREDRAW, TRUE, 0L);
  314. #endif /* NEED_EARLY_REDRAW */
  315.             psLBEntry =
  316.               (PSTR)GlobalAlloc(GMEM_FIXED, FILNAMSIZ+LONG_FORM_FNAME_INX);
  317.             /* GRR:  does OemToAnsi filter out escape and CR characters? */
  318.             OemToAnsi(G.filename, G.filename);  /* translate to ANSI */
  319.             if (longhdr) {
  320.                 wsprintf(psLBEntry, LoadFarString(LongHdrStats),
  321.                   G.crec.ucsize, (LPSTR)methbuf, csiz, cfactorstr,
  322.                   mo, dy, yr, hh, mm, G.crec.crc32,
  323.                   (G.pInfo->lcflag? '^':' '), (LPSTR)G.filename);
  324.                 SendMessage(hWndList, LB_ADDSTRING, 0,
  325.                   (LONG)(LPSTR)psLBEntry);
  326.             } else {
  327.                 wsprintf(psLBEntry, LoadFarString(ShortHdrStats),
  328.                   G.crec.ucsize, mo, dy, yr, hh, mm,
  329.                   (G.pInfo->lcflag? '^':' '), (LPSTR)G.filename);
  330.                 SendMessage(hWndList, LB_ADDSTRING, 0,
  331.                   (LONG)(LPSTR)psLBEntry);
  332.             }
  333.             GlobalFree((HANDLE)psLBEntry);
  334. #else /* !MSWIN */
  335.             if (longhdr)
  336.                 Info(slide, 0, ((char *)slide, LoadFarString(LongHdrStats),
  337.                   G.crec.ucsize, methbuf, csiz, cfactorstr, mo, dy,
  338.                   yr, hh, mm, G.crec.crc32, (G.pInfo->lcflag? '^':' ')));
  339.             else
  340. #ifdef OS2_EAS
  341.                 Info(slide, 0, ((char *)slide, LoadFarString(ShortHdrStats),
  342.                   G.crec.ucsize, ea_size, acl_size,
  343.                   mo, dy, yr, hh, mm, (G.pInfo->lcflag? '^':' ')));
  344. #else
  345.                 Info(slide, 0, ((char *)slide, LoadFarString(ShortHdrStats),
  346.                   G.crec.ucsize,
  347.                   mo, dy, yr, hh, mm, (G.pInfo->lcflag? '^':' ')));
  348. #endif
  349.             fnprint(__G);
  350. #ifdef WINDLL
  351.             /* if this is the Windows 3.1 DLL, fill in our linked list with
  352.              * the filenames (GRR:  also useful for OS/2 and other DLLs?) */
  353.             {
  354.                 /* pointer to current ScFileList, used to move down chain;
  355.                  * start at beginning of chain */
  356.                 struct ScFileList *pCurFileList = G.WinDLL.pGlobalZipFileList;
  357.  
  358.                 /* move down the chain until we reach the end */
  359.                 while (pCurFileList->Next != NULL)
  360.                     pCurFileList = pCurFileList->Next;
  361.  
  362.                 /* if this is not the very first time through... */
  363.                 if (!(pCurFileList == G.WinDLL.pGlobalZipFileList &&
  364.                       pCurFileList->Name == NULL))
  365.                 {
  366.                     /* now that we are pointing at the last item in the chain,
  367.                      * allocate space for a new one and add it */
  368.                     pCurFileList->Next =
  369.                       (struct ScFileList *)malloc(sizeof(struct ScFileList));
  370.                     /* set the items in the next entry to NULL to mark end */
  371.                     pCurFileList->Next->Name = NULL;
  372.                     pCurFileList->Next->Next = NULL;
  373.  
  374.                     /* move up to the entry we just created */
  375.                     pCurFileList = pCurFileList->Next;
  376.                 }
  377.  
  378.                 /* allocate space for the name and copy the filename into it */
  379.                 pCurFileList->Name = (char *)malloc(strlen(G.filename)+1);
  380.                 strcpy(pCurFileList->Name, G.filename);
  381.             }
  382. #endif /* WINDLL */
  383. #endif /* ?MSWIN */
  384.  
  385.             if ((error = do_string(__G__ G.crec.file_comment_length,
  386.                                    QCOND? DISPLAY : SKIP)) != 0)
  387.             {
  388.                 error_in_archive = error;  /* might be just warning */
  389.                 if (error > PK_WARN)       /* fatal */
  390.                     return error;
  391.             }
  392.             tot_ucsize += G.crec.ucsize;
  393.             tot_csize += csiz;
  394.             ++members;
  395. #ifdef OS2_EAS
  396.             if (ea_size) {
  397.                 tot_easize += ea_size;
  398.                 ++tot_eafiles;
  399.             }
  400.             if (acl_size) {
  401.                 tot_aclsize += acl_size;
  402.                 ++tot_aclfiles;
  403.             }
  404. #endif
  405.         } else {        /* not listing this file */
  406.             SKIP_(G.crec.file_comment_length)
  407.         }
  408.     } /* end for-loop (j: files in central directory) */
  409.  
  410. /*---------------------------------------------------------------------------
  411.     Print footer line and totals (compressed size, uncompressed size, number
  412.     of members in zipfile).
  413.   ---------------------------------------------------------------------------*/
  414.  
  415.     if (G.qflag < 2) {
  416.         if ((cfactor = ratio(tot_ucsize, tot_csize)) < 0) {
  417.             sgn = '-';
  418.             cfactor = (-cfactor + 5) / 10;
  419.         } else {
  420.             sgn = ' ';
  421.             cfactor = (cfactor + 5) / 10;
  422.         }
  423.         if (cfactor == 100)
  424.             sprintf(cfactorstr, LoadFarString(CompFactor100));
  425.         else
  426.             sprintf(cfactorstr, LoadFarString(CompFactorStr), sgn, cfactor);
  427. #ifdef MSWIN
  428.         /* Display just the totals since the dashed lines get displayed
  429.          * in UpdateListBox(). Get just enough space to display total. */
  430.         if (longhdr)
  431.             wsprintf(lpumb->szTotalsLine,LoadFarString(LongFileTrailer),
  432.               tot_ucsize, tot_csize, cfactorstr, members, members == 1? "":"s");
  433.         else
  434.             wsprintf(lpumb->szTotalsLine, LoadFarString(ShortFileTrailer),
  435.               tot_ucsize, members, members == 1? "" : "s");
  436. #else /* !MSWIN */
  437.         if (longhdr) {
  438.             Info(slide, 0, ((char *)slide, LoadFarString(LongFileTrailer),
  439.               tot_ucsize, tot_csize, cfactorstr, members, members==1? "":"s"));
  440. #ifdef OS2_EAS
  441.             if (tot_easize || tot_aclsize)
  442.                 Info(slide, 0, ((char *)slide, "\n"));
  443.             if (tot_eafiles && tot_easize)
  444.                 Info(slide, 0, ((char *)slide, LoadFarString(OS2ExtAttrTrailer),
  445.                   tot_eafiles, tot_eafiles == 1? " has" : "s have a total of",
  446.                   tot_easize));
  447.             if (tot_aclfiles && tot_aclsize)
  448.                 Info(slide, 0, ((char *)slide, LoadFarString(OS2ACLTrailer),
  449.                   tot_aclfiles, tot_aclfiles == 1? " has" : "s have a total of",
  450.                   tot_aclsize));
  451. #endif /* OS2_EAs */
  452.         } else
  453. #ifdef OS2_EAS
  454.             Info(slide, 0, ((char *)slide, LoadFarString(ShortFileTrailer),
  455.               tot_ucsize, tot_easize, tot_aclsize, members, members == 1?
  456.               "" : "s"));
  457. #else
  458.             Info(slide, 0, ((char *)slide, LoadFarString(ShortFileTrailer),
  459.               tot_ucsize, members, members == 1? "" : "s"));
  460. #endif /* OS2_EAs */
  461. #endif /* ?MSWIN */
  462.     }
  463. /*---------------------------------------------------------------------------
  464.     Double check that we're back at the end-of-central-directory record.
  465.   ---------------------------------------------------------------------------*/
  466.  
  467.     if (readbuf(__G__ G.sig, 4) == 0)
  468.         return PK_EOF;
  469.     if (strncmp(G.sig, G.end_central_sig, 4)) {     /* just to make sure again */
  470.         Info(slide, 0x401, ((char *)slide, LoadFarString(EndSigMsg)));
  471.         error_in_archive = PK_WARN;
  472.     }
  473.     if (members == 0 && error_in_archive <= PK_WARN)
  474.         error_in_archive = PK_FIND;
  475.  
  476.     return error_in_archive;
  477.  
  478. } /* end function list_files() */
  479.  
  480.  
  481.  
  482.  
  483.  
  484. #ifdef TIMESTAMP
  485.  
  486. /*************************/
  487. /* Function time_stamp() */
  488. /*************************/
  489.  
  490. int time_stamp(__G)    /* return PK-type error code */
  491.     __GDEF
  492. {
  493.     int do_this_file=FALSE, error, error_in_archive=PK_COOL;
  494. #if (defined(USE_EF_UX_TIME) || defined(UNIX))
  495.     ztimbuf z_utime;
  496. #endif
  497.     time_t last_modtime=0L;   /* assuming no zipfile data older than 1970 */
  498.     ush j, members=0;
  499.     min_info info;
  500.  
  501.  
  502. /*---------------------------------------------------------------------------
  503.     Unlike extract_or_test_files() but like list_files(), this function works
  504.     on information in the central directory alone.  Thus we have a single,
  505.     large loop through the entire directory, searching for the latest time
  506.     stamp.
  507.   ---------------------------------------------------------------------------*/
  508.  
  509.     G.pInfo = &info;
  510.  
  511.     for (j = 0; j < G.ecrec.total_entries_central_dir; ++j) {
  512.  
  513.         if (readbuf(__G__ G.sig, 4) == 0)
  514.             return PK_EOF;
  515.         if (strncmp(G.sig, G.central_hdr_sig, 4)) {  /* just to make sure */
  516.             Info(slide, 0x401, ((char *)slide, LoadFarString(CentSigMsg), j));
  517.             Info(slide, 0x401, ((char *)slide, LoadFarString(ReportMsg)));
  518.             return PK_BADERR;
  519.         }
  520.         /* process_cdir_file_hdr() sets pInfo->lcflag: */
  521.         if ((error = process_cdir_file_hdr(__G)) != PK_COOL)
  522.             return error;       /* only PK_EOF defined */
  523.         if ((error = do_string(__G__ G.crec.filename_length, DS_FN)) != PK_OK)
  524.         {        /*  ^-- (uses pInfo->lcflag) */
  525.             error_in_archive = error;
  526.             if (error > PK_WARN)   /* fatal:  can't continue */
  527.                 return error;
  528.         }
  529.         if (G.extra_field != (uch *)NULL) {
  530.             free(G.extra_field);
  531.             G.extra_field = (uch *)NULL;
  532.         }
  533.         if ((error = do_string(__G__ G.crec.extra_field_length, EXTRA_FIELD))
  534.             != 0)
  535.         {
  536.             error_in_archive = error;
  537.             if (error > PK_WARN)      /* fatal */
  538.                 return error;
  539.         }
  540.         if (!G.process_all_files) {   /* check if specified on command line */
  541.             char **pfn = G.pfnames-1;
  542.  
  543.             do_this_file = FALSE;
  544.             while (*++pfn)
  545.                 if (match(G.filename, *pfn, G.C_flag)) {
  546.                     do_this_file = TRUE;
  547.                     break;       /* found match, so stop looping */
  548.                 }
  549.             if (do_this_file) {  /* check if this is an excluded file */
  550.                 char **pxn = G.pxnames-1;
  551.  
  552.                 while (*++pxn)
  553.                     if (match(G.filename, *pxn, G.C_flag)) {
  554.                         do_this_file = FALSE;  /* ^-- ignore case in match */
  555.                         break;
  556.                     }
  557.             }
  558.         }
  559.  
  560.         /* If current file was specified on command line, or if no names were
  561.          * specified, check the time for this file.  Either way, get rid of the
  562.          * file comment and go back for the next file.
  563.          */
  564.         if (G.process_all_files || do_this_file) {
  565. #ifdef USE_EF_UX_TIME
  566.             if (G.extra_field && ef_scan_for_izux(G.extra_field,
  567.                 G.crec.extra_field_length, &z_utime, NULL) > 0)
  568.             {
  569.                 if (last_modtime < z_utime.modtime)
  570.                     last_modtime = z_utime.modtime;
  571.             } else
  572. #endif /* USE_EF_UX_TIME */
  573.             {
  574.                 time_t modtime = dos_to_unix_time(G.crec.last_mod_file_date,
  575.                                                   G.crec.last_mod_file_time);
  576.  
  577.                 if (last_modtime < modtime)
  578.                     last_modtime = modtime;
  579.             }
  580.             ++members;
  581.         }
  582.         SKIP_(G.crec.file_comment_length)
  583.  
  584.     } /* end for-loop (j: files in central directory) */
  585.  
  586. /*---------------------------------------------------------------------------
  587.     Set the modification (and access) time on the zipfile, assuming we have
  588.     a modification time to set.
  589.   ---------------------------------------------------------------------------*/
  590.  
  591.     if (members > 0) {
  592.         z_utime.modtime = z_utime.actime = last_modtime;
  593.         if (utime(G.zipfn, &z_utime))
  594.             Info(slide, 0x201, ((char *)slide,
  595.               "warning:  can't set time for %s\n", G.zipfn));
  596.     }
  597.  
  598. /*---------------------------------------------------------------------------
  599.     Double check that we're back at the end-of-central-directory record.
  600.   ---------------------------------------------------------------------------*/
  601.  
  602.     if (readbuf(__G__ G.sig, 4) == 0)
  603.         return PK_EOF;
  604.     if (strncmp(G.sig, G.end_central_sig, 4)) {     /* just to make sure again */
  605.         Info(slide, 0x401, ((char *)slide, LoadFarString(EndSigMsg)));
  606.         error_in_archive = PK_WARN;
  607.     }
  608.     if (members == 0 && error_in_archive <= PK_WARN)
  609.         error_in_archive = PK_FIND;
  610.  
  611.     return error_in_archive;
  612.  
  613. } /* end function time_stamp() */
  614.  
  615. #endif /* TIMESTAMP */
  616.  
  617.  
  618.  
  619.  
  620.  
  621. /********************/
  622. /* Function ratio() */    /* also used by ZipInfo routines */
  623. /********************/
  624.  
  625. int ratio(uc, c)
  626.     ulg uc, c;
  627. {
  628.     ulg denom;
  629.  
  630.     if (uc == 0)
  631.         return 0;
  632.     if (uc > 2000000L) {    /* risk signed overflow if multiply numerator */
  633.         denom = uc / 1000L;
  634.         return ((uc >= c) ?
  635.             (int) ((uc-c + (denom>>1)) / denom) :
  636.           -((int) ((c-uc + (denom>>1)) / denom)));
  637.     } else {             /* ^^^^^^^^ rounding */
  638.         denom = uc;
  639.         return ((uc >= c) ?
  640.             (int) ((1000L*(uc-c) + (denom>>1)) / denom) :
  641.           -((int) ((1000L*(c-uc) + (denom>>1)) / denom)));
  642.     }                            /* ^^^^^^^^ rounding */
  643. }
  644.  
  645.  
  646.  
  647.  
  648.  
  649. /************************/
  650. /*  Function fnprint()  */    /* also used by ZipInfo routines */
  651. /************************/
  652.  
  653. void fnprint(__G)    /* print filename (after filtering) and newline */
  654.     __GDEF
  655. {
  656.     char *name = fnfilter(G.filename, slide);
  657.  
  658.     (*G.message)((zvoid *)&G, (uch *)name, (ulg)strlen(name), 0);
  659.     (*G.message)((zvoid *)&G, (uch *)"\n", 1L, 0);
  660.  
  661. } /* end function fnprint() */
  662.