xref: /haiku/src/bin/unzip/fileio.c (revision 899e0ef82b5624ace2ccfa5f5a58c8ebee54aaef)
1 /*
2   Copyright (c) 1990-2002 Info-ZIP.  All rights reserved.
3 
4   See the accompanying file LICENSE, version 2000-Apr-09 or later
5   (the contents of which are also included in unzip.h) for terms of use.
6   If, for some reason, all these files are missing, the Info-ZIP license
7   also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
8 */
9 /*---------------------------------------------------------------------------
10 
11   fileio.c
12 
13   This file contains routines for doing direct but relatively generic input/
14   output, file-related sorts of things, plus some miscellaneous stuff.  Most
15   of the stuff has to do with opening, closing, reading and/or writing files.
16 
17   Contains:  open_input_file()
18              open_outfile()           (not: VMS, AOS/VS, CMSMVS, MACOS, TANDEM)
19              undefer_input()
20              defer_leftover_input()
21              readbuf()
22              readbyte()
23              fillinbuf()
24              seek_zipf()
25              flush()                  (non-VMS)
26              is_vms_varlen_txt()      (non-VMS, VMS_TEXT_CONV only)
27              disk_error()             (non-VMS)
28              UzpMessagePrnt()
29              UzpMessageNull()         (DLL only)
30              UzpInput()
31              UzpMorePause()
32              UzpPassword()            (non-WINDLL)
33              handler()
34              dos_to_unix_time()       (non-VMS, non-VM/CMS, non-MVS)
35              check_for_newer()        (non-VMS, non-OS/2, non-VM/CMS, non-MVS)
36              do_string()
37              makeword()
38              makelong()
39              str2iso()                (CRYPT && NEED_STR2ISO, only)
40              str2oem()                (CRYPT && NEED_STR2OEM, only)
41              memset()                 (ZMEM only)
42              memcpy()                 (ZMEM only)
43              zstrnicmp()              (NO_STRNICMP only)
44              zstat()                  (REGULUS only)
45              plastchar()              (_MBCS only)
46              uzmbschr()               (_MBCS && NEED_UZMBSCHR, only)
47              uzmbsrchr()              (_MBCS && NEED_UZMBSRCHR, only)
48              fLoadFarString()         (SMALL_MEM only)
49              fLoadFarStringSmall()    (SMALL_MEM only)
50              fLoadFarStringSmall2()   (SMALL_MEM only)
51              zfstrcpy()               (SMALL_MEM only)
52 
53   ---------------------------------------------------------------------------*/
54 
55 
56 #define __FILEIO_C      /* identifies this source module */
57 #define UNZIP_INTERNAL
58 #include "unzip.h"
59 #ifdef WINDLL
60 #  include "windll/windll.h"
61 #  include <setjmp.h>
62 #endif
63 #include "crypt.h"
64 #include "ttyio.h"
65 
66 /* setup of codepage conversion for decryption passwords */
67 #if CRYPT
68 #  if (defined(CRYP_USES_ISO2OEM) && !defined(IZ_ISO2OEM_ARRAY))
69 #    define IZ_ISO2OEM_ARRAY            /* pull in iso2oem[] table */
70 #  endif
71 #  if (defined(CRYP_USES_OEM2ISO) && !defined(IZ_OEM2ISO_ARRAY))
72 #    define IZ_OEM2ISO_ARRAY            /* pull in oem2iso[] table */
73 #  endif
74 #endif
75 #include "ebcdic.h"   /* definition/initialization of ebcdic[] */
76 
77 
78 /*
79    Note: Under Windows, the maximum size of the buffer that can be used
80    with any of the *printf calls is 16,384, so win_fprintf was used to
81    feed the fprintf clone no more than 16K chunks at a time. This should
82    be valid for anything up to 64K (and probably beyond, assuming your
83    buffers are that big).
84 */
85 #ifdef WINDLL
86 #  define WriteError(buf,len,strm) \
87    (win_fprintf(pG, strm, (extent)len, (char far *)buf) != (int)(len))
88 #else /* !WINDLL */
89 #  ifdef USE_FWRITE
90 #    define WriteError(buf,len,strm) \
91      ((extent)fwrite((char *)(buf),1,(extent)(len),strm) != (extent)(len))
92 #  else
93 #    define WriteError(buf,len,strm) \
94      ((extent)write(fileno(strm),(char *)(buf),(extent)(len)) != (extent)(len))
95 #  endif
96 #endif /* ?WINDLL */
97 
98 #if (defined(USE_DEFLATE64) && defined(__16BIT__))
99 static int partflush OF((__GPRO__ uch *rawbuf, ulg size, int unshrink));
100 #endif
101 #ifdef VMS_TEXT_CONV
102 static int is_vms_varlen_txt OF((__GPRO__ uch *ef_buf, unsigned ef_len));
103 #endif
104 static int disk_error OF((__GPRO));
105 
106 
107 /****************************/
108 /* Strings used in fileio.c */
109 /****************************/
110 
111 static ZCONST char Far CannotOpenZipfile[] =
112   "error:  cannot open zipfile [ %s ]\n";
113 
114 #if (!defined(VMS) && !defined(AOS_VS) && !defined(CMS_MVS) && !defined(MACOS))
115 #if (!defined(TANDEM))
116 #if (defined(BEO_THS_UNX) || defined(DOS_FLX_NLM_OS2_W32))
117    static ZCONST char Far CannotDeleteOldFile[] =
118      "error:  cannot delete old %s\n";
119 #ifdef UNIXBACKUP
120    static ZCONST char Far CannotRenameOldFile[] =
121      "error:  cannot rename old %s\n";
122    static ZCONST char Far BackupSuffix[] = "~";
123 #endif
124 #endif /* BEO_THS_UNX || DOS_FLX_NLM_OS2_W32 */
125 #ifdef NOVELL_BUG_FAILSAFE
126    static ZCONST char Far NovellBug[] =
127      "error:  %s: stat() says does not exist, but fopen() found anyway\n";
128 #endif
129    static ZCONST char Far CannotCreateFile[] = "error:  cannot create %s\n";
130 #endif /* !TANDEM */
131 #endif /* !VMS && !AOS_VS && !CMS_MVS && !MACOS */
132 
133 static ZCONST char Far ReadError[] = "error:  zipfile read error\n";
134 static ZCONST char Far FilenameTooLongTrunc[] =
135   "warning:  filename too long--truncating.\n";
136 static ZCONST char Far ExtraFieldTooLong[] =
137   "warning:  extra field too long (%d).  Ignoring...\n";
138 
139 #ifdef WINDLL
140    static ZCONST char Far DiskFullQuery[] =
141      "%s:  write error (disk full?).\n";
142 #else
143    static ZCONST char Far DiskFullQuery[] =
144      "%s:  write error (disk full?).  Continue? (y/n/^C) ";
145    static ZCONST char Far ZipfileCorrupt[] =
146      "error:  zipfile probably corrupt (%s)\n";
147 #  ifdef SYMLINKS
148      static ZCONST char Far FileIsSymLink[] =
149        "%s exists and is a symbolic link%s.\n";
150 #  endif
151 #  ifdef MORE
152      static ZCONST char Far MorePrompt[] = "--More--(%lu)";
153 #  endif
154    static ZCONST char Far QuitPrompt[] =
155      "--- Press `Q' to quit, or any other key to continue ---";
156    static ZCONST char Far HidePrompt[] = /* "\r                       \r"; */
157      "\r                                                         \r";
158 #  if CRYPT
159 #    ifdef MACOS
160        /* SPC: are names on MacOS REALLY so much longer than elsewhere ??? */
161        static ZCONST char Far PasswPrompt[] = "[%s]\n %s password: ";
162 #    else
163        static ZCONST char Far PasswPrompt[] = "[%s] %s password: ";
164 #    endif
165      static ZCONST char Far PasswPrompt2[] = "Enter password: ";
166      static ZCONST char Far PasswRetry[] = "password incorrect--reenter: ";
167 #  endif /* CRYPT */
168 #endif /* !WINDLL */
169 
170 
171 
172 
173 
174 /******************************/
175 /* Function open_input_file() */
176 /******************************/
177 
178 int open_input_file(__G)    /* return 1 if open failed */
179     __GDEF
180 {
181     /*
182      *  open the zipfile for reading and in BINARY mode to prevent cr/lf
183      *  translation, which would corrupt the bitstreams
184      */
185 
186 #ifdef VMS
187     G.zipfd = open(G.zipfn, O_RDONLY, 0, "ctx=stm");
188 #else /* !VMS */
189 #ifdef MACOS
190     G.zipfd = open(G.zipfn, 0);
191 #else /* !MACOS */
192 #ifdef CMS_MVS
193     G.zipfd = vmmvs_open_infile(__G);
194 #else /* !CMS_MVS */
195 #ifdef USE_STRM_INPUT
196     G.zipfd = fopen(G.zipfn, FOPR);
197 #else /* !USE_STRM_INPUT */
198 # ifdef O_BINARY
199     G.zipfd = open(G.zipfn, O_RDONLY | O_BINARY);
200 # else
201     G.zipfd = open(G.zipfn, O_RDONLY);
202 # endif
203 #endif /* ?USE_STRM_INPUT */
204 #endif /* ?CMS_MVS */
205 #endif /* ?MACOS */
206 #endif /* ?VMS */
207 
208 #ifdef USE_STRM_INPUT
209     if (G.zipfd == NULL)
210 #else
211     /* if (G.zipfd < 0) */  /* no good for Windows CE port */
212     if (G.zipfd == -1)
213 #endif
214     {
215         Info(slide, 0x401, ((char *)slide, LoadFarString(CannotOpenZipfile),
216           G.zipfn));
217         return 1;
218     }
219     return 0;
220 
221 } /* end function open_input_file() */
222 
223 
224 
225 
226 #if (!defined(VMS) && !defined(AOS_VS) && !defined(CMS_MVS) && !defined(MACOS))
227 #if (!defined(TANDEM))
228 
229 /***************************/
230 /* Function open_outfile() */
231 /***************************/
232 
233 int open_outfile(__G)         /* return 1 if fail */
234     __GDEF
235 {
236 #ifdef DLL
237     if (G.redirect_data)
238         return (redirect_outfile(__G) == FALSE);
239 #endif
240 #ifdef QDOS
241     QFilename(__G__ G.filename);
242 #endif
243 #if (defined(DOS_FLX_NLM_OS2_W32) || defined(BEO_THS_UNX))
244 #ifdef BORLAND_STAT_BUG
245     /* Borland 5.0's stat() barfs if the filename has no extension and the
246      * file doesn't exist. */
247     if (access(G.filename, 0) == -1) {
248         FILE *tmp = fopen(G.filename, "wb+");
249 
250         /* file doesn't exist, so create a dummy file to keep stat() from
251          * failing (will be over-written anyway) */
252         fputc('0', tmp);  /* just to have something in the file */
253         fclose(tmp);
254     }
255 #endif /* BORLAND_STAT_BUG */
256 #ifdef SYMLINKS
257     if (SSTAT(G.filename, &G.statbuf) == 0 || lstat(G.filename,&G.statbuf) == 0)
258 #else
259     if (SSTAT(G.filename, &G.statbuf) == 0)
260 #endif /* ?SYMLINKS */
261     {
262         Trace((stderr, "open_outfile:  stat(%s) returns 0:  file exists\n",
263           FnFilter1(G.filename)));
264 #ifdef UNIXBACKUP
265         if (uO.B_flag) {    /* do backup */
266             char *tname;
267             struct stat tmpstat;
268             int blen, flen, tlen;
269 
270             blen = strlen(BackupSuffix);
271             flen = strlen(G.filename);
272             tlen = flen + blen + 6;    /* includes space for 5 digits */
273             if (tlen >= FILNAMSIZ) {   /* in case name is too long, truncate */
274                 tname = (char *)malloc(FILNAMSIZ);
275                 if (tname == NULL)
276                     return 1;                 /* in case we run out of space */
277                 tlen = FILNAMSIZ - 1 - blen;
278                 strcpy(tname, G.filename);    /* make backup name */
279                 tname[tlen] = '\0';
280                 if (flen > tlen) flen = tlen;
281                 tlen = FILNAMSIZ;
282             } else {
283                 tname = (char *)malloc(tlen);
284                 if (tname == NULL)
285                     return 1;                 /* in case we run out of space */
286                 strcpy(tname, G.filename);    /* make backup name */
287             }
288             strcpy(tname+flen, BackupSuffix);
289 
290             if (IS_OVERWRT_ALL) {
291                 /* If there is a previous backup file, delete it,
292                  * otherwise the following rename operation may fail.
293                  */
294                 if (SSTAT(tname, &tmpstat) == 0)
295                     unlink(tname);
296             } else {
297                 /* Check if backupname exists, and, if it's true, try
298                  * appending numbers of up to 5 digits to the BackupSuffix,
299                  * until an unused name is found.
300                  */
301                 unsigned maxtail, i;
302                 char *numtail = tname + flen + blen;
303 
304                 maxtail = 65535;
305                 switch (tlen - flen - blen - 1) {
306                     case 4: maxtail = 9999; break;
307                     case 3: maxtail = 999; break;
308                     case 2: maxtail = 99; break;
309                     case 1: maxtail = 9; break;
310                     case 0: maxtail = 0; break;
311                 }
312                 /* while filename exists */
313                 for (i = 0; (i <= maxtail) && (SSTAT(tname, &tmpstat) == 0);)
314                     sprintf(numtail,"%u", ++i);
315             }
316 
317             if (rename(G.filename, tname) != 0) {   /* move file */
318                 Info(slide, 0x401, ((char *)slide,
319                   LoadFarString(CannotRenameOldFile), FnFilter1(G.filename)));
320                 free(tname);
321                 return 1;
322             }
323             Trace((stderr, "open_outfile:  %s now renamed into %s\n",
324               FnFilter1(G.filename), FnFilter2(tname)));
325             free(tname);
326         } else
327 #endif /* UNIXBACKUP */
328         {
329 #ifdef DOS_FLX_OS2_W32
330             if (!(G.statbuf.st_mode & S_IWRITE)) {
331                 Trace((stderr,
332                   "open_outfile:  existing file %s is read-only\n",
333                   FnFilter1(G.filename)));
334                 chmod(G.filename, S_IREAD | S_IWRITE);
335                 Trace((stderr, "open_outfile:  %s now writable\n",
336                   FnFilter1(G.filename)));
337             }
338 #endif /* DOS_FLX_OS2_W32 */
339 #ifdef NLM
340             /* Give the file read/write permission (non-POSIX shortcut) */
341             chmod(G.filename, 0);
342 #endif /* NLM */
343             if (unlink(G.filename) != 0) {
344                 Info(slide, 0x401, ((char *)slide,
345                   LoadFarString(CannotDeleteOldFile), FnFilter1(G.filename)));
346                 return 1;
347             }
348             Trace((stderr, "open_outfile:  %s now deleted\n",
349               FnFilter1(G.filename)));
350         }
351     }
352 #endif /* DOS_FLX_NLM_OS2_W32 || BEO_THS_UNX */
353 #ifdef RISCOS
354     if (SWI_OS_File_7(G.filename,0xDEADDEAD,0xDEADDEAD,G.lrec.ucsize)!=NULL) {
355         Info(slide, 1, ((char *)slide, LoadFarString(CannotCreateFile),
356           FnFilter1(G.filename)));
357         return 1;
358     }
359 #endif /* RISCOS */
360 #ifdef TOPS20
361     char *tfilnam;
362 
363     if ((tfilnam = (char *)malloc(2*strlen(G.filename)+1)) == (char *)NULL)
364         return 1;
365     strcpy(tfilnam, G.filename);
366     upper(tfilnam);
367     enquote(tfilnam);
368     if ((G.outfile = fopen(tfilnam, FOPW)) == (FILE *)NULL) {
369         Info(slide, 1, ((char *)slide, LoadFarString(CannotCreateFile),
370           tfilnam));
371         free(tfilnam);
372         return 1;
373     }
374     free(tfilnam);
375 #else /* !TOPS20 */
376 #ifdef MTS
377     if (uO.aflag)
378         G.outfile = fopen(G.filename, FOPWT);
379     else
380         G.outfile = fopen(G.filename, FOPW);
381     if (G.outfile == (FILE *)NULL) {
382         Info(slide, 1, ((char *)slide, LoadFarString(CannotCreateFile),
383           FnFilter1(G.filename)));
384         return 1;
385     }
386 #else /* !MTS */
387 #ifdef DEBUG
388     Info(slide, 1, ((char *)slide,
389       "open_outfile:  doing fopen(%s) for reading\n", FnFilter1(G.filename)));
390     if ((G.outfile = fopen(G.filename, FOPR)) == (FILE *)NULL)
391         Info(slide, 1, ((char *)slide,
392           "open_outfile:  fopen(%s) for reading failed:  does not exist\n",
393           FnFilter1(G.filename)));
394     else {
395         Info(slide, 1, ((char *)slide,
396           "open_outfile:  fopen(%s) for reading succeeded:  file exists\n",
397           FnFilter1(G.filename)));
398         fclose(G.outfile);
399     }
400 #endif /* DEBUG */
401 #ifdef NOVELL_BUG_FAILSAFE
402     if (G.dne && ((G.outfile = fopen(G.filename, FOPR)) != (FILE *)NULL)) {
403         Info(slide, 0x401, ((char *)slide, LoadFarString(NovellBug),
404           FnFilter1(G.filename)));
405         fclose(G.outfile);
406         return 1;   /* with "./" fix in checkdir(), should never reach here */
407     }
408 #endif /* NOVELL_BUG_FAILSAFE */
409     Trace((stderr, "open_outfile:  doing fopen(%s) for writing\n",
410       FnFilter1(G.filename)));
411     if ((G.outfile = fopen(G.filename, FOPW)) == (FILE *)NULL) {
412         Info(slide, 0x401, ((char *)slide, LoadFarString(CannotCreateFile),
413           FnFilter1(G.filename)));
414         return 1;
415     }
416     Trace((stderr, "open_outfile:  fopen(%s) for writing succeeded\n",
417       FnFilter1(G.filename)));
418 #endif /* !MTS */
419 #endif /* !TOPS20 */
420 
421 #ifdef USE_FWRITE
422 #ifdef DOS_NLM_OS2_W32
423     /* 16-bit MSC: buffer size must be strictly LESS than 32K (WSIZE):  bogus */
424     setbuf(G.outfile, (char *)NULL);   /* make output unbuffered */
425 #else /* !DOS_NLM_OS2_W32 */
426 #ifndef RISCOS
427 #ifdef _IOFBF  /* make output fully buffered (works just about like write()) */
428     setvbuf(G.outfile, (char *)slide, _IOFBF, WSIZE);
429 #else
430     setbuf(G.outfile, (char *)slide);
431 #endif
432 #endif /* !RISCOS */
433 #endif /* ?DOS_NLM_OS2_W32 */
434 #endif /* USE_FWRITE */
435 #ifdef OS2_W32
436     /* preallocate the final file size to prevent file fragmentation */
437     SetFileSize(G.outfile, G.pInfo->uncompr_size);
438 #endif
439     return 0;
440 
441 } /* end function open_outfile() */
442 
443 #endif /* !TANDEM */
444 #endif /* !VMS && !AOS_VS && !CMS_MVS && !MACOS */
445 
446 
447 
448 
449 
450 /*
451  * These functions allow NEXTBYTE to function without needing two bounds
452  * checks.  Call defer_leftover_input() if you ever have filled G.inbuf
453  * by some means other than readbyte(), and you then want to start using
454  * NEXTBYTE.  When going back to processing bytes without NEXTBYTE, call
455  * undefer_input().  For example, extract_or_test_member brackets its
456  * central section that does the decompression with these two functions.
457  * If you need to check the number of bytes remaining in the current
458  * file while using NEXTBYTE, check (G.csize + G.incnt), not G.csize.
459  */
460 
461 /****************************/
462 /* function undefer_input() */
463 /****************************/
464 
465 void undefer_input(__G)
466     __GDEF
467 {
468     if (G.incnt > 0)
469         G.csize += G.incnt;
470     if (G.incnt_leftover > 0) {
471         /* We know that "(G.csize < MAXINT)" so we can cast G.csize to int:
472          * This condition was checked when G.incnt_leftover was set > 0 in
473          * defer_leftover_input(), and it is NOT allowed to touch G.csize
474          * before calling undefer_input() when (G.incnt_leftover > 0)
475          * (single exception: see read_byte()'s  "G.csize <= 0" handling) !!
476          */
477         G.incnt = G.incnt_leftover + (int)G.csize;
478         G.inptr = G.inptr_leftover - (int)G.csize;
479         G.incnt_leftover = 0;
480     } else if (G.incnt < 0)
481         G.incnt = 0;
482 } /* end function undefer_input() */
483 
484 
485 
486 
487 
488 /***********************************/
489 /* function defer_leftover_input() */
490 /***********************************/
491 
492 void defer_leftover_input(__G)
493     __GDEF
494 {
495     if ((long)G.incnt > G.csize) {
496         /* (G.csize < MAXINT), we can safely cast it to int !! */
497         if (G.csize < 0L)
498             G.csize = 0L;
499         G.inptr_leftover = G.inptr + (int)G.csize;
500         G.incnt_leftover = G.incnt - (int)G.csize;
501         G.incnt = (int)G.csize;
502     } else
503         G.incnt_leftover = 0;
504     G.csize -= G.incnt;
505 } /* end function defer_leftover_input() */
506 
507 
508 
509 
510 
511 /**********************/
512 /* Function readbuf() */
513 /**********************/
514 
515 unsigned readbuf(__G__ buf, size)   /* return number of bytes read into buf */
516     __GDEF
517     char *buf;
518     register unsigned size;
519 {
520     register unsigned count;
521     unsigned n;
522 
523     n = size;
524     while (size) {
525         if (G.incnt <= 0) {
526             if ((G.incnt = read(G.zipfd, (char *)G.inbuf, INBUFSIZ)) == 0)
527                 return (n-size);
528             else if (G.incnt < 0) {
529                 /* another hack, but no real harm copying same thing twice */
530                 (*G.message)((zvoid *)&G,
531                   (uch *)LoadFarString(ReadError),  /* CANNOT use slide */
532                   (ulg)strlen(LoadFarString(ReadError)), 0x401);
533                 return 0;  /* discarding some data; better than lock-up */
534             }
535             /* buffer ALWAYS starts on a block boundary:  */
536             G.cur_zipfile_bufstart += INBUFSIZ;
537             G.inptr = G.inbuf;
538         }
539         count = MIN(size, (unsigned)G.incnt);
540         memcpy(buf, G.inptr, count);
541         buf += count;
542         G.inptr += count;
543         G.incnt -= count;
544         size -= count;
545     }
546     return n;
547 
548 } /* end function readbuf() */
549 
550 
551 
552 
553 
554 /***********************/
555 /* Function readbyte() */
556 /***********************/
557 
558 int readbyte(__G)   /* refill inbuf and return a byte if available, else EOF */
559     __GDEF
560 {
561     if (G.mem_mode)
562         return EOF;
563     if (G.csize <= 0) {
564         G.csize--;             /* for tests done after exploding */
565         G.incnt = 0;
566         return EOF;
567     }
568     if (G.incnt <= 0) {
569         if ((G.incnt = read(G.zipfd, (char *)G.inbuf, INBUFSIZ)) == 0) {
570             G.incnt = 0;       /* do not allow negative value to affect stuff */
571             return EOF;
572         } else if (G.incnt < 0) {  /* "fail" (abort, retry, ...) returns this */
573             /* another hack, but no real harm copying same thing twice */
574             (*G.message)((zvoid *)&G,
575               (uch *)LoadFarString(ReadError),
576               (ulg)strlen(LoadFarString(ReadError)), 0x401);
577             echon();
578 #ifdef WINDLL
579             longjmp(dll_error_return, 1);
580 #else
581             DESTROYGLOBALS();
582             EXIT(PK_BADERR);    /* totally bailing; better than lock-up */
583 #endif
584         }
585         G.cur_zipfile_bufstart += INBUFSIZ; /* always starts on block bndry */
586         G.inptr = G.inbuf;
587         defer_leftover_input(__G);           /* decrements G.csize */
588     }
589 
590 #if CRYPT
591     if (G.pInfo->encrypted) {
592         uch *p;
593         int n;
594 
595         /* This was previously set to decrypt one byte beyond G.csize, when
596          * incnt reached that far.  GRR said, "but it's required:  why?"  This
597          * was a bug in fillinbuf() -- was it also a bug here?
598          */
599         for (n = G.incnt, p = G.inptr;  n--;  p++)
600             zdecode(*p);
601     }
602 #endif /* CRYPT */
603 
604     --G.incnt;
605     return *G.inptr++;
606 
607 } /* end function readbyte() */
608 
609 
610 
611 
612 
613 #ifdef USE_ZLIB
614 
615 /************************/
616 /* Function fillinbuf() */
617 /************************/
618 
619 int fillinbuf(__G) /* like readbyte() except returns number of bytes in inbuf */
620     __GDEF
621 {
622     if (G.mem_mode ||
623                   (G.incnt = read(G.zipfd, (char *)G.inbuf, INBUFSIZ)) <= 0)
624         return 0;
625     G.cur_zipfile_bufstart += INBUFSIZ;  /* always starts on a block boundary */
626     G.inptr = G.inbuf;
627     defer_leftover_input(__G);           /* decrements G.csize */
628 
629 #if CRYPT
630     if (G.pInfo->encrypted) {
631         uch *p;
632         int n;
633 
634         for (n = G.incnt, p = G.inptr;  n--;  p++)
635             zdecode(*p);
636     }
637 #endif /* CRYPT */
638 
639     return G.incnt;
640 
641 } /* end function fillinbuf() */
642 
643 #endif /* USE_ZLIB */
644 
645 
646 
647 
648 
649 /************************/
650 /* Function seek_zipf() */
651 /************************/
652 
653 int seek_zipf(__G__ abs_offset)
654     __GDEF
655     LONGINT abs_offset;
656 {
657 /*
658  *  Seek to the block boundary of the block which includes abs_offset,
659  *  then read block into input buffer and set pointers appropriately.
660  *  If block is already in the buffer, just set the pointers.  This function
661  *  is used by do_seekable (process.c), extract_or_test_entrylist (extract.c)
662  *  and do_string (fileio.c).  Also, a slightly modified version is embedded
663  *  within extract_or_test_entrylist (extract.c).  readbyte() and readbuf()
664  *  (fileio.c) are compatible.  NOTE THAT abs_offset is intended to be the
665  *  "proper offset" (i.e., if there were no extra bytes prepended);
666  *  cur_zipfile_bufstart contains the corrected offset.
667  *
668  *  Since seek_zipf() is never used during decompression, it is safe to
669  *  use the slide[] buffer for the error message.
670  *
671  * returns PK error codes:
672  *  PK_BADERR if effective offset in zipfile is negative
673  *  PK_EOF if seeking past end of zipfile
674  *  PK_OK when seek was successful
675  */
676     LONGINT request = abs_offset + G.extra_bytes;
677     LONGINT inbuf_offset = request % INBUFSIZ;
678     LONGINT bufstart = request - inbuf_offset;
679 
680     if (request < 0) {
681         Info(slide, 1, ((char *)slide, LoadFarStringSmall(SeekMsg),
682              G.zipfn, LoadFarString(ReportMsg)));
683         return(PK_BADERR);
684     } else if (bufstart != G.cur_zipfile_bufstart) {
685         Trace((stderr,
686           "fpos_zip: abs_offset = %ld, G.extra_bytes = %ld\n",
687           abs_offset, G.extra_bytes));
688 #ifdef USE_STRM_INPUT
689         fseek(G.zipfd, (LONGINT)bufstart, SEEK_SET);
690         G.cur_zipfile_bufstart = ftell(G.zipfd);
691 #else /* !USE_STRM_INPUT */
692         G.cur_zipfile_bufstart = lseek(G.zipfd, (LONGINT)bufstart, SEEK_SET);
693 #endif /* ?USE_STRM_INPUT */
694         Trace((stderr,
695           "       request = %ld, (abs+extra) = %ld, inbuf_offset = %ld\n",
696           request, (abs_offset+G.extra_bytes), inbuf_offset));
697         Trace((stderr, "       bufstart = %ld, cur_zipfile_bufstart = %ld\n",
698           bufstart, G.cur_zipfile_bufstart));
699         if ((G.incnt = read(G.zipfd, (char *)G.inbuf, INBUFSIZ)) <= 0)
700             return(PK_EOF);
701         G.incnt -= (int)inbuf_offset;
702         G.inptr = G.inbuf + (int)inbuf_offset;
703     } else {
704         G.incnt += (G.inptr-G.inbuf) - (int)inbuf_offset;
705         G.inptr = G.inbuf + (int)inbuf_offset;
706     }
707     return(PK_OK);
708 } /* end function seek_zipf() */
709 
710 
711 
712 
713 
714 #ifndef VMS  /* for VMS use code in vms.c */
715 
716 /********************/
717 /* Function flush() */   /* returns PK error codes: */
718 /********************/   /* if cflag => always 0; PK_DISK if write error */
719 
720 int flush(__G__ rawbuf, size, unshrink)
721     __GDEF
722     uch *rawbuf;
723     ulg size;
724     int unshrink;
725 #if (defined(USE_DEFLATE64) && defined(__16BIT__))
726 {
727     int ret;
728 
729     /* On 16-bit systems (MSDOS, OS/2 1.x), the standard C library functions
730      * cannot handle writes of 64k blocks at once.  For these systems, the
731      * blocks to flush are split into pieces of 32k or less.
732      */
733     while (size > 0x8000L) {
734         ret = partflush(__G__ rawbuf, 0x8000L, unshrink);
735         if (ret != PK_OK)
736             return ret;
737         size -= 0x8000L;
738         rawbuf += (unsigned)0x8000;
739     }
740     return partflush(__G__ rawbuf, size, unshrink);
741 } /* end function flush() */
742 
743 
744 /************************/
745 /* Function partflush() */  /* returns PK error codes: */
746 /************************/  /* if cflag => always 0; PK_DISK if write error */
747 
748 static int partflush(__G__ rawbuf, size, unshrink)
749     __GDEF
750     uch *rawbuf;        /* cannot be ZCONST, gets passed to (*G.message)() */
751     ulg size;
752     int unshrink;
753 #endif /* USE_DEFLATE64 && __16BIT__ */
754 {
755     register uch *p;
756     register uch *q;
757     uch *transbuf;
758 #if (defined(SMALL_MEM) || defined(MED_MEM) || defined(VMS_TEXT_CONV))
759     ulg transbufsiz;
760 #endif
761     /* static int didCRlast = FALSE;    moved to globals.h */
762 
763 
764 /*---------------------------------------------------------------------------
765     Compute the CRC first; if testing or if disk is full, that's it.
766   ---------------------------------------------------------------------------*/
767 
768     G.crc32val = crc32(G.crc32val, rawbuf, (extent)size);
769 
770 #ifdef DLL
771     if ((G.statreportcb != NULL) &&
772         (*G.statreportcb)(__G__ UZ_ST_IN_PROGRESS, G.zipfn, G.filename, NULL))
773         return IZ_CTRLC;        /* cancel operation by user request */
774 #endif
775 
776     if (uO.tflag || size == 0L)  /* testing or nothing to write:  all done */
777         return PK_OK;
778 
779     if (G.disk_full)
780         return PK_DISK;         /* disk already full:  ignore rest of file */
781 
782 /*---------------------------------------------------------------------------
783     Write the bytes rawbuf[0..size-1] to the output device, first converting
784     end-of-lines and ASCII/EBCDIC as needed.  If SMALL_MEM or MED_MEM are NOT
785     defined, outbuf is assumed to be at least as large as rawbuf and is not
786     necessarily checked for overflow.
787   ---------------------------------------------------------------------------*/
788 
789     if (!G.pInfo->textmode) {   /* write raw binary data */
790         /* GRR:  note that for standard MS-DOS compilers, size argument to
791          * fwrite() can never be more than 65534, so WriteError macro will
792          * have to be rewritten if size can ever be that large.  For now,
793          * never more than 32K.  Also note that write() returns an int, which
794          * doesn't necessarily limit size to 32767 bytes if write() is used
795          * on 16-bit systems but does make it more of a pain; however, because
796          * at least MSC 5.1 has a lousy implementation of fwrite() (as does
797          * DEC Ultrix cc), write() is used anyway.
798          */
799 #ifdef DLL
800         if (G.redirect_data)
801             writeToMemory(__G__ rawbuf, (extent)size);
802         else
803 #endif
804         if (!uO.cflag && WriteError(rawbuf, size, G.outfile))
805             return disk_error(__G);
806         else if (uO.cflag && (*G.message)((zvoid *)&G, rawbuf, size, 0))
807             return PK_OK;
808     } else {   /* textmode:  aflag is true */
809         if (unshrink) {
810             /* rawbuf = outbuf */
811             transbuf = G.outbuf2;
812 #if (defined(SMALL_MEM) || defined(MED_MEM) || defined(VMS_TEXT_CONV))
813             transbufsiz = TRANSBUFSIZ;
814 #endif
815         } else {
816             /* rawbuf = slide */
817             transbuf = G.outbuf;
818 #if (defined(SMALL_MEM) || defined(MED_MEM) || defined(VMS_TEXT_CONV))
819             transbufsiz = OUTBUFSIZ;
820             Trace((stderr, "\ntransbufsiz = OUTBUFSIZ = %u\n",
821                    (unsigned)OUTBUFSIZ));
822 #endif
823         }
824         if (G.newfile) {
825 #ifdef VMS_TEXT_CONV
826             if (G.pInfo->hostnum == VMS_ && G.extra_field &&
827                 is_vms_varlen_txt(__G__ G.extra_field,
828                                   G.lrec.extra_field_length))
829                 G.VMS_line_state = 0;    /* 0: ready to read line length */
830             else
831                 G.VMS_line_state = -1;   /* -1: don't treat as VMS text */
832 #endif
833             G.didCRlast = FALSE;         /* no previous buffers written */
834             G.newfile = FALSE;
835         }
836 
837 #ifdef VMS_TEXT_CONV
838         if (G.VMS_line_state >= 0)
839         {
840             /* GRR: really want to check for actual VMS extra field, and
841              *      ideally for variable-length record format */
842 /*
843             printf("\n>>>>>> GRR:  file is VMS text and has an extra field\n");
844  */
845 
846             p = rawbuf;
847             q = transbuf;
848             while (p < rawbuf+(unsigned)size) {
849                 switch (G.VMS_line_state) {
850 
851                     /* 0: ready to read line length */
852                     case 0:
853                         G.VMS_line_length = 0;
854                         if (p == rawbuf+(unsigned)size-1) {    /* last char */
855                             G.VMS_line_length = (unsigned)(*p++);
856                             G.VMS_line_state = 1;
857                         } else {
858                             G.VMS_line_length = makeword(p);
859                             p += 2;
860                             G.VMS_line_state = 2;
861                         }
862                         G.VMS_line_pad =
863                                ((G.VMS_line_length & 1) != 0); /* odd */
864                         break;
865 
866                     /* 1: read one byte of length, need second */
867                     case 1:
868                         G.VMS_line_length += ((unsigned)(*p++) << 8);
869                         G.VMS_line_state = 2;
870                         break;
871 
872                     /* 2: ready to read VMS_line_length chars */
873                     case 2:
874                         {
875                             extent remaining = rawbuf+(unsigned)size-p;
876                             extent outroom;
877 
878                             if (G.VMS_line_length < remaining) {
879                                 remaining = G.VMS_line_length;
880                                 G.VMS_line_state = 3;
881                             }
882 
883                             outroom = transbuf+(unsigned)transbufsiz-q;
884                             if (remaining >= outroom) {
885                                 remaining -= outroom;
886                                 for (;outroom > 0; p++, outroom--)
887                                     *q++ = native(*p);
888 #ifdef DLL
889                                 if (G.redirect_data)
890                                     writeToMemory(__G__ transbuf,
891                                       (extent)(q-transbuf));
892                                 else
893 #endif
894                                 if (!uO.cflag && WriteError(transbuf,
895                                     (extent)(q-transbuf), G.outfile))
896                                     return disk_error(__G);
897                                 else if (uO.cflag && (*G.message)((zvoid *)&G,
898                                          transbuf, (ulg)(q-transbuf), 0))
899                                     return PK_OK;
900                                 q = transbuf;
901                                 /* fall through to normal case */
902                             }
903                             G.VMS_line_length -= remaining;
904                             for (;remaining > 0; p++, remaining--)
905                                 *q++ = native(*p);
906                         }
907                         break;
908 
909                     /* 3: ready to PutNativeEOL */
910                     case 3:
911                         if (q > transbuf+(unsigned)transbufsiz-lenEOL) {
912 #ifdef DLL
913                             if (G.redirect_data)
914                                 writeToMemory(__G__ transbuf,
915                                   (extent)(q-transbuf));
916                             else
917 #endif
918                             if (!uO.cflag &&
919                                 WriteError(transbuf, (extent)(q-transbuf),
920                                   G.outfile))
921                                 return disk_error(__G);
922                             else if (uO.cflag && (*G.message)((zvoid *)&G,
923                                      transbuf, (ulg)(q-transbuf), 0))
924                                 return PK_OK;
925                             q = transbuf;
926                         }
927                         PutNativeEOL
928                         G.VMS_line_state = G.VMS_line_pad ? 4 : 0;
929                         break;
930 
931                     /* 4: ready to read pad byte */
932                     case 4:
933                         ++p;
934                         G.VMS_line_state = 0;
935                         break;
936                 }
937             } /* end while */
938 
939         } else
940 #endif /* VMS_TEXT_CONV */
941 
942     /*-----------------------------------------------------------------------
943         Algorithm:  CR/LF => native; lone CR => native; lone LF => native.
944         This routine is only for non-raw-VMS, non-raw-VM/CMS files (i.e.,
945         stream-oriented files, not record-oriented).
946       -----------------------------------------------------------------------*/
947 
948         /* else not VMS text */ {
949             p = rawbuf;
950             if (*p == LF && G.didCRlast)
951                 ++p;
952             G.didCRlast = FALSE;
953             for (q = transbuf;  p < rawbuf+(unsigned)size;  ++p) {
954                 if (*p == CR) {           /* lone CR or CR/LF: treat as EOL  */
955                     PutNativeEOL
956                     if (p == rawbuf+(unsigned)size-1) /* last char in buffer */
957                         G.didCRlast = TRUE;
958                     else if (p[1] == LF)  /* get rid of accompanying LF */
959                         ++p;
960                 } else if (*p == LF)      /* lone LF */
961                     PutNativeEOL
962                 else
963 #ifndef DOS_FLX_OS2_W32
964                 if (*p != CTRLZ)          /* lose all ^Z's */
965 #endif
966                     *q++ = native(*p);
967 
968 #if (defined(SMALL_MEM) || defined(MED_MEM))
969 # if (lenEOL == 1)   /* don't check unshrink:  both buffers small but equal */
970                 if (!unshrink)
971 # endif
972                     /* check for danger of buffer overflow and flush */
973                     if (q > transbuf+(unsigned)transbufsiz-lenEOL) {
974                         Trace((stderr,
975                           "p - rawbuf = %u   q-transbuf = %u   size = %lu\n",
976                           (unsigned)(p-rawbuf), (unsigned)(q-transbuf), size));
977                         if (!uO.cflag && WriteError(transbuf,
978                             (extent)(q-transbuf), G.outfile))
979                             return disk_error(__G);
980                         else if (uO.cflag && (*G.message)((zvoid *)&G,
981                                  transbuf, (ulg)(q-transbuf), 0))
982                             return PK_OK;
983                         q = transbuf;
984                         continue;
985                     }
986 #endif /* SMALL_MEM || MED_MEM */
987             }
988         }
989 
990     /*-----------------------------------------------------------------------
991         Done translating:  write whatever we've got to file (or screen).
992       -----------------------------------------------------------------------*/
993 
994         Trace((stderr, "p - rawbuf = %u   q-transbuf = %u   size = %lu\n",
995           (unsigned)(p-rawbuf), (unsigned)(q-transbuf), size));
996         if (q > transbuf) {
997 #ifdef DLL
998             if (G.redirect_data)
999                 writeToMemory(__G__ transbuf, (extent)(q-transbuf));
1000             else
1001 #endif
1002             if (!uO.cflag && WriteError(transbuf, (extent)(q-transbuf),
1003                 G.outfile))
1004                 return disk_error(__G);
1005             else if (uO.cflag && (*G.message)((zvoid *)&G, transbuf,
1006                 (ulg)(q-transbuf), 0))
1007                 return PK_OK;
1008         }
1009     }
1010 
1011     return PK_OK;
1012 
1013 } /* end function flush() [resp. partflush() for 16-bit Deflate64 support] */
1014 
1015 
1016 
1017 
1018 
1019 #ifdef VMS_TEXT_CONV
1020 
1021 /********************************/
1022 /* Function is_vms_varlen_txt() */
1023 /********************************/
1024 
1025 static int is_vms_varlen_txt(__G__ ef_buf, ef_len)
1026     __GDEF
1027     uch *ef_buf;        /* buffer containing extra field */
1028     unsigned ef_len;    /* total length of extra field */
1029 {
1030     unsigned eb_id;
1031     unsigned eb_len;
1032     uch *eb_data;
1033     unsigned eb_datlen;
1034 #define VMSREC_C_UNDEF  0
1035 #define VMSREC_C_VAR    2
1036     uch vms_rectype = VMSREC_C_UNDEF;
1037     uch vms_fileorg = 0;
1038 
1039 #define VMSPK_ITEMID            0
1040 #define VMSPK_ITEMLEN           2
1041 #define VMSPK_ITEMHEADSZ        4
1042 
1043 #define VMSATR_C_RECATTR        4
1044 #define VMS_FABSIG              0x42414656      /* "VFAB" */
1045 /* offsets of interesting fields in VMS fabdef structure */
1046 #define VMSFAB_B_RFM            31      /* record format byte */
1047 #define VMSFAB_B_ORG            29      /* file organization byte */
1048 
1049     if (ef_len == 0 || ef_buf == NULL)
1050         return FALSE;
1051 
1052     while (ef_len >= EB_HEADSIZE) {
1053         eb_id = makeword(EB_ID + ef_buf);
1054         eb_len = makeword(EB_LEN + ef_buf);
1055 
1056         if (eb_len > (ef_len - EB_HEADSIZE)) {
1057             /* discovered some extra field inconsistency! */
1058             Trace((stderr,
1059               "is_vms_varlen_txt: block length %u > rest ef_size %u\n", eb_len,
1060               ef_len - EB_HEADSIZE));
1061             break;
1062         }
1063 
1064         switch (eb_id) {
1065           case EF_PKVMS:
1066             /* The PKVMS e.f. raw data part consists of:
1067              * a) 4 bytes CRC checksum
1068              * b) list of uncompressed variable-length data items
1069              * Each data item is introduced by a fixed header
1070              *  - 2 bytes data type ID
1071              *  - 2 bytes <size> of data
1072              *  - <size> bytes of actual attribute data
1073              */
1074 
1075             /* get pointer to start of data and its total length */
1076             eb_data = ef_buf+(EB_HEADSIZE+4);
1077             eb_datlen = eb_len-4;
1078 
1079             /* test the CRC checksum */
1080             if (makelong(ef_buf+EB_HEADSIZE) !=
1081                 crc32(CRCVAL_INITIAL, eb_data, (extent)eb_datlen))
1082             {
1083                 Info(slide, 1, ((char *)slide,
1084                   "[Warning: CRC error, discarding PKWARE extra field]\n"));
1085                 /* skip over the data analysis code */
1086                 break;
1087             }
1088 
1089             /* scan through the attribute data items */
1090             while (eb_datlen > 4)
1091             {
1092                 unsigned fldsize = makeword(&eb_data[VMSPK_ITEMLEN]);
1093 
1094                 /* check the item type word */
1095                 switch (makeword(&eb_data[VMSPK_ITEMID])) {
1096                   case VMSATR_C_RECATTR:
1097                     /* we have found the (currently only) interesting
1098                      * data item */
1099                     if (fldsize >= 1) {
1100                         vms_rectype = eb_data[VMSPK_ITEMHEADSZ] & 15;
1101                         vms_fileorg = eb_data[VMSPK_ITEMHEADSZ] >> 4;
1102                     }
1103                     break;
1104                   default:
1105                     break;
1106                 }
1107                 /* skip to next data item */
1108                 eb_datlen -= fldsize + VMSPK_ITEMHEADSZ;
1109                 eb_data += fldsize + VMSPK_ITEMHEADSZ;
1110             }
1111             break;
1112 
1113           case EF_IZVMS:
1114             if (makelong(ef_buf+EB_HEADSIZE) == VMS_FABSIG) {
1115                 if ((eb_data = extract_izvms_block(__G__
1116                                                    ef_buf+EB_HEADSIZE, eb_len,
1117                                                    &eb_datlen, NULL, 0))
1118                     != NULL)
1119                 {
1120                     if (eb_datlen >= VMSFAB_B_RFM+1) {
1121                         vms_rectype = eb_data[VMSFAB_B_RFM] & 15;
1122                         vms_fileorg = eb_data[VMSFAB_B_ORG] >> 4;
1123                     }
1124                     free(eb_data);
1125                 }
1126             }
1127             break;
1128 
1129           default:
1130             break;
1131         }
1132 
1133         /* Skip this extra field block */
1134         ef_buf += (eb_len + EB_HEADSIZE);
1135         ef_len -= (eb_len + EB_HEADSIZE);
1136     }
1137 
1138     return (vms_rectype == VMSREC_C_VAR);
1139 
1140 } /* end function is_vms_varlen_txtfile() */
1141 
1142 #endif /* VMS_TEXT_CONV */
1143 
1144 
1145 
1146 
1147 /*************************/
1148 /* Function disk_error() */
1149 /*************************/
1150 
1151 static int disk_error(__G)
1152     __GDEF
1153 {
1154     /* OK to use slide[] here because this file is finished regardless */
1155     Info(slide, 0x4a1, ((char *)slide, LoadFarString(DiskFullQuery),
1156       FnFilter1(G.filename)));
1157 
1158 #ifndef WINDLL
1159     fgets(G.answerbuf, 9, stdin);
1160     if (*G.answerbuf == 'y')   /* stop writing to this file */
1161         G.disk_full = 1;       /*  (outfile bad?), but new OK */
1162     else
1163 #endif
1164         G.disk_full = 2;       /* no:  exit program */
1165 
1166     return PK_DISK;
1167 
1168 } /* end function disk_error() */
1169 
1170 #endif /* !VMS */
1171 
1172 
1173 
1174 
1175 
1176 /*****************************/
1177 /* Function UzpMessagePrnt() */
1178 /*****************************/
1179 
1180 int UZ_EXP UzpMessagePrnt(pG, buf, size, flag)
1181     zvoid *pG;   /* globals struct:  always passed */
1182     uch *buf;    /* preformatted string to be printed */
1183     ulg size;    /* length of string (may include nulls) */
1184     int flag;    /* flag bits */
1185 {
1186     /* IMPORTANT NOTE:
1187      *    The name of the first parameter of UzpMessagePrnt(), which passes
1188      *    the "Uz_Globs" address, >>> MUST <<< be identical to the string
1189      *    expansion of the __G__ macro in the REENTRANT case (see globals.h).
1190      *    This name identity is mandatory for the LoadFarString() macro
1191      *    (in the SMALL_MEM case) !!!
1192      */
1193     int error;
1194     uch *q=buf, *endbuf=buf+(unsigned)size;
1195 #ifdef MORE
1196     uch *p=buf;
1197 #if (defined(SCREENWIDTH) && defined(SCREENLWRAP))
1198     int islinefeed = FALSE;
1199 #endif
1200 #endif
1201     FILE *outfp;
1202 
1203 
1204 /*---------------------------------------------------------------------------
1205     These tests are here to allow fine-tuning of UnZip's output messages,
1206     but none of them will do anything without setting the appropriate bit
1207     in the flag argument of every Info() statement which is to be turned
1208     *off*.  That is, all messages are currently turned on for all ports.
1209     To turn off *all* messages, use the UzpMessageNull() function instead
1210     of this one.
1211   ---------------------------------------------------------------------------*/
1212 
1213 #if (defined(OS2) && defined(DLL))
1214     if (MSG_NO_DLL2(flag))  /* if OS/2 DLL bit is set, do NOT print this msg */
1215         return 0;
1216 #endif
1217 #ifdef WINDLL
1218     if (MSG_NO_WDLL(flag))
1219         return 0;
1220 #endif
1221 #ifdef WINDLL
1222     if (MSG_NO_WGUI(flag))
1223         return 0;
1224 #endif
1225 /*
1226 #ifdef ACORN_GUI
1227     if (MSG_NO_AGUI(flag))
1228         return 0;
1229 #endif
1230  */
1231 #ifdef DLL                 /* don't display message if data is redirected */
1232     if (((Uz_Globs *)pG)->redirect_data &&
1233         !((Uz_Globs *)pG)->redirect_text)
1234         return 0;
1235 #endif
1236 
1237     if (MSG_STDERR(flag) && !((Uz_Globs *)pG)->UzO.tflag)
1238         outfp = (FILE *)stderr;
1239     else
1240         outfp = (FILE *)stdout;
1241 
1242 #ifdef QUERY_TRNEWLN
1243     /* some systems require termination of query prompts with '\n' to force
1244      * immediate display */
1245     if (MSG_MNEWLN(flag)) {   /* assumes writable buffer (e.g., slide[]) */
1246         *endbuf++ = '\n';     /*  with room for one more char at end of buf */
1247         ++size;               /*  (safe assumption:  only used for four */
1248     }                         /*  short queries in extract.c and fileio.c) */
1249 #endif
1250 
1251     if (MSG_TNEWLN(flag)) {   /* again assumes writable buffer:  fragile... */
1252         if ((!size && !((Uz_Globs *)pG)->sol) ||
1253             (size && (endbuf[-1] != '\n')))
1254         {
1255             *endbuf++ = '\n';
1256             ++size;
1257         }
1258     }
1259 
1260 #ifdef MORE
1261 # ifdef SCREENSIZE
1262     /* room for --More-- and one line of overlap: */
1263 #  if (defined(SCREENWIDTH) && defined(SCREENLWRAP))
1264     SCREENSIZE(&((Uz_Globs *)pG)->height, &((Uz_Globs *)pG)->width);
1265 #  else
1266     SCREENSIZE(&((Uz_Globs *)pG)->height, (int *)NULL);
1267 #  endif
1268     ((Uz_Globs *)pG)->height -= 2;
1269 # else
1270     /* room for --More-- and one line of overlap: */
1271     ((Uz_Globs *)pG)->height = SCREENLINES - 2;
1272 #  if (defined(SCREENWIDTH) && defined(SCREENLWRAP))
1273     ((Uz_Globs *)pG)->width = SCREENWIDTH;
1274 #  endif
1275 # endif
1276 #endif /* MORE */
1277 
1278     if (MSG_LNEWLN(flag) && !((Uz_Globs *)pG)->sol) {
1279         /* not at start of line:  want newline */
1280 #ifdef OS2DLL
1281         if (!((Uz_Globs *)pG)->redirect_text) {
1282 #endif
1283             putc('\n', outfp);
1284             fflush(outfp);
1285 #ifdef MORE
1286             if (((Uz_Globs *)pG)->M_flag)
1287             {
1288 #if (defined(SCREENWIDTH) && defined(SCREENLWRAP))
1289                 ((Uz_Globs *)pG)->chars = 0;
1290 #endif
1291                 ++((Uz_Globs *)pG)->numlines;
1292                 ++((Uz_Globs *)pG)->lines;
1293                 if (((Uz_Globs *)pG)->lines >= ((Uz_Globs *)pG)->height)
1294                     (*((Uz_Globs *)pG)->mpause)((zvoid *)pG,
1295                       LoadFarString(MorePrompt), 1);
1296             }
1297 #endif /* MORE */
1298             if (MSG_STDERR(flag) && ((Uz_Globs *)pG)->UzO.tflag &&
1299                 !isatty(1) && isatty(2))
1300             {
1301                 /* error output from testing redirected:  also send to stderr */
1302                 putc('\n', stderr);
1303                 fflush(stderr);
1304             }
1305 #ifdef OS2DLL
1306         } else
1307            REDIRECTC('\n');
1308 #endif
1309         ((Uz_Globs *)pG)->sol = TRUE;
1310     }
1311 
1312     /* put zipfile name, filename and/or error/warning keywords here */
1313 
1314 #ifdef MORE
1315     if (((Uz_Globs *)pG)->M_flag
1316 #ifdef OS2DLL
1317          && !((Uz_Globs *)pG)->redirect_text
1318 #endif
1319                                                  )
1320     {
1321         while (p < endbuf) {
1322             if (*p == '\n') {
1323 #if (defined(SCREENWIDTH) && defined(SCREENLWRAP))
1324                 islinefeed = TRUE;
1325             } else if (SCREENLWRAP) {
1326                 if (*p == '\r') {
1327                     ((Uz_Globs *)pG)->chars = 0;
1328                 } else {
1329 #  ifdef TABSIZE
1330                     if (*p == '\t')
1331                         ((Uz_Globs *)pG)->chars +=
1332                             (TABSIZE - (((Uz_Globs *)pG)->chars % TABSIZE));
1333                     else
1334 #  endif
1335                         ++((Uz_Globs *)pG)->chars;
1336 
1337                     if (((Uz_Globs *)pG)->chars >= ((Uz_Globs *)pG)->width)
1338                         islinefeed = TRUE;
1339                 }
1340             }
1341             if (islinefeed) {
1342                 islinefeed = FALSE;
1343                 ((Uz_Globs *)pG)->chars = 0;
1344 #endif /* (SCREENWIDTH && SCREEN_LWRAP) */
1345                 ++((Uz_Globs *)pG)->numlines;
1346                 ++((Uz_Globs *)pG)->lines;
1347                 if (((Uz_Globs *)pG)->lines >= ((Uz_Globs *)pG)->height)
1348                 {
1349                     if ((error = WriteError(q, p-q+1, outfp)) != 0)
1350                         return error;
1351                     fflush(outfp);
1352                     ((Uz_Globs *)pG)->sol = TRUE;
1353                     q = p + 1;
1354                     (*((Uz_Globs *)pG)->mpause)((zvoid *)pG,
1355                       LoadFarString(MorePrompt), 1);
1356                 }
1357             }
1358             INCSTR(p);
1359         } /* end while */
1360         size = (ulg)(p - q);   /* remaining text */
1361     }
1362 #endif /* MORE */
1363 
1364     if (size) {
1365 #ifdef OS2DLL
1366         if (!((Uz_Globs *)pG)->redirect_text) {
1367 #endif
1368             if ((error = WriteError(q, size, outfp)) != 0)
1369                 return error;
1370             fflush(outfp);
1371             if (MSG_STDERR(flag) && ((Uz_Globs *)pG)->UzO.tflag &&
1372                 !isatty(1) && isatty(2))
1373             {
1374                 /* error output from testing redirected:  also send to stderr */
1375                 if ((error = WriteError(q, size, stderr)) != 0)
1376                     return error;
1377                 fflush(stderr);
1378             }
1379 #ifdef OS2DLL
1380         } else {                /* GRR:  this is ugly:  hide with macro */
1381             if ((error = REDIRECTPRINT(q, size)) != 0)
1382                 return error;
1383         }
1384 #endif /* OS2DLL */
1385         ((Uz_Globs *)pG)->sol = (endbuf[-1] == '\n');
1386     }
1387     return 0;
1388 
1389 } /* end function UzpMessagePrnt() */
1390 
1391 
1392 
1393 
1394 
1395 #ifdef DLL
1396 
1397 /*****************************/
1398 /* Function UzpMessageNull() */  /* convenience routine for no output at all */
1399 /*****************************/
1400 
1401 int UZ_EXP UzpMessageNull(pG, buf, size, flag)
1402     zvoid *pG;    /* globals struct:  always passed */
1403     uch *buf;     /* preformatted string to be printed */
1404     ulg size;     /* length of string (may include nulls) */
1405     int flag;     /* flag bits */
1406 {
1407     return 0;
1408 
1409 } /* end function UzpMessageNull() */
1410 
1411 #endif /* DLL */
1412 
1413 
1414 
1415 
1416 
1417 /***********************/
1418 /* Function UzpInput() */   /* GRR:  this is a placeholder for now */
1419 /***********************/
1420 
1421 int UZ_EXP UzpInput(pG, buf, size, flag)
1422     zvoid *pG;    /* globals struct:  always passed */
1423     uch *buf;     /* preformatted string to be printed */
1424     int *size;    /* (address of) size of buf and of returned string */
1425     int flag;     /* flag bits (bit 0: no echo) */
1426 {
1427     /* tell picky compilers to shut up about "unused variable" warnings */
1428     pG = pG; buf = buf; flag = flag;
1429 
1430     *size = 0;
1431     return 0;
1432 
1433 } /* end function UzpInput() */
1434 
1435 
1436 
1437 
1438 
1439 #if (!defined(WINDLL) && !defined(MACOS))
1440 
1441 /***************************/
1442 /* Function UzpMorePause() */
1443 /***************************/
1444 
1445 void UZ_EXP UzpMorePause(pG, prompt, flag)
1446     zvoid *pG;            /* globals struct:  always passed */
1447     ZCONST char *prompt;  /* "--More--" prompt */
1448     int flag;             /* 0 = any char OK; 1 = accept only '\n', ' ', q */
1449 {
1450     uch c;
1451 
1452 /*---------------------------------------------------------------------------
1453     Print a prompt and wait for the user to press a key, then erase prompt
1454     if possible.
1455   ---------------------------------------------------------------------------*/
1456 
1457     if (!((Uz_Globs *)pG)->sol)
1458         fprintf(stderr, "\n");
1459     /* numlines may or may not be used: */
1460     fprintf(stderr, prompt, ((Uz_Globs *)pG)->numlines);
1461     fflush(stderr);
1462     if (flag & 1) {
1463         do {
1464             c = (uch)FGETCH(0);
1465         } while (
1466 #ifdef THEOS
1467                  c != 17 &&     /* standard QUIT key */
1468 #endif
1469                  c != '\r' && c != '\n' && c != ' ' && c != 'q' && c != 'Q');
1470     } else
1471         c = (uch)FGETCH(0);
1472 
1473     /* newline was not echoed, so cover up prompt line */
1474     fprintf(stderr, LoadFarString(HidePrompt));
1475     fflush(stderr);
1476 
1477     if (
1478 #ifdef THEOS
1479         (c == 17) ||            /* standard QUIT key */
1480 #endif
1481         (ToLower(c) == 'q')) {
1482         DESTROYGLOBALS();
1483         EXIT(PK_COOL);
1484     }
1485 
1486     ((Uz_Globs *)pG)->sol = TRUE;
1487 
1488 #ifdef MORE
1489     /* space for another screen, enter for another line. */
1490     if ((flag & 1) && c == ' ')
1491         ((Uz_Globs *)pG)->lines = 0;
1492 #endif /* MORE */
1493 
1494 } /* end function UzpMorePause() */
1495 
1496 #endif /* !WINDLL && !MACOS */
1497 
1498 
1499 
1500 
1501 #ifndef WINDLL
1502 
1503 /**************************/
1504 /* Function UzpPassword() */
1505 /**************************/
1506 
1507 int UZ_EXP UzpPassword (pG, rcnt, pwbuf, size, zfn, efn)
1508     zvoid *pG;         /* pointer to UnZip's internal global vars */
1509     int *rcnt;         /* retry counter */
1510     char *pwbuf;       /* buffer for password */
1511     int size;          /* size of password buffer */
1512     ZCONST char *zfn;  /* name of zip archive */
1513     ZCONST char *efn;  /* name of archive entry being processed */
1514 {
1515 #if CRYPT
1516     int r = IZ_PW_ENTERED;
1517     char *m;
1518     char *prompt;
1519 
1520 #ifndef REENTRANT
1521     /* tell picky compilers to shut up about "unused variable" warnings */
1522     pG = pG;
1523 #endif
1524 
1525     if (*rcnt == 0) {           /* First call for current entry */
1526         *rcnt = 2;
1527         if ((prompt = (char *)malloc(2*FILNAMSIZ + 15)) != (char *)NULL) {
1528             sprintf(prompt, LoadFarString(PasswPrompt),
1529                     FnFilter1(zfn), FnFilter2(efn));
1530             m = prompt;
1531         } else
1532             m = (char *)LoadFarString(PasswPrompt2);
1533     } else {                    /* Retry call, previous password was wrong */
1534         (*rcnt)--;
1535         prompt = NULL;
1536         m = (char *)LoadFarString(PasswRetry);
1537     }
1538 
1539     m = getp(__G__ m, pwbuf, size);
1540     if (prompt != (char *)NULL) {
1541         free(prompt);
1542     }
1543     if (m == (char *)NULL) {
1544         r = IZ_PW_ERROR;
1545     }
1546     else if (*pwbuf == '\0') {
1547         r = IZ_PW_CANCELALL;
1548     }
1549     return r;
1550 
1551 #else /* !CRYPT */
1552     /* tell picky compilers to shut up about "unused variable" warnings */
1553     pG = pG; rcnt = rcnt; pwbuf = pwbuf; size = size; zfn = zfn; efn = efn;
1554 
1555     return IZ_PW_ERROR;  /* internal error; function should never get called */
1556 #endif /* ?CRYPT */
1557 
1558 } /* end function UzpPassword() */
1559 
1560 
1561 
1562 
1563 
1564 /**********************/
1565 /* Function handler() */
1566 /**********************/
1567 
1568 void handler(signal)   /* upon interrupt, turn on echo and exit cleanly */
1569     int signal;
1570 {
1571     GETGLOBALS();
1572 
1573 #if !(defined(SIGBUS) || defined(SIGSEGV))      /* add a newline if not at */
1574     (*G.message)((zvoid *)&G, slide, 0L, 0x41); /*  start of line (to stderr; */
1575 #endif                                          /*  slide[] should be safe) */
1576 
1577     echon();
1578 
1579 #ifdef SIGBUS
1580     if (signal == SIGBUS) {
1581         Info(slide, 0x421, ((char *)slide, LoadFarString(ZipfileCorrupt),
1582           "bus error"));
1583         DESTROYGLOBALS();
1584         EXIT(PK_BADERR);
1585     }
1586 #endif /* SIGBUS */
1587 
1588 #ifdef SIGSEGV
1589     if (signal == SIGSEGV) {
1590         Info(slide, 0x421, ((char *)slide, LoadFarString(ZipfileCorrupt),
1591           "segmentation violation"));
1592         DESTROYGLOBALS();
1593         EXIT(PK_BADERR);
1594     }
1595 #endif /* SIGSEGV */
1596 
1597     /* probably ctrl-C */
1598     DESTROYGLOBALS();
1599 #if defined(AMIGA) && defined(__SASC)
1600     _abort();
1601 #endif
1602     EXIT(IZ_CTRLC);       /* was EXIT(0), then EXIT(PK_ERR) */
1603 }
1604 
1605 #endif /* !WINDLL */
1606 
1607 
1608 
1609 
1610 #if (!defined(VMS) && !defined(CMS_MVS))
1611 #if (!defined(OS2) || defined(TIMESTAMP))
1612 
1613 #if (!defined(HAVE_MKTIME) || defined(WIN32))
1614 /* also used in amiga/filedate.c and win32/win32.c */
1615 ZCONST ush ydays[] =
1616     { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
1617 #endif
1618 
1619 /*******************************/
1620 /* Function dos_to_unix_time() */ /* used for freshening/updating/timestamps */
1621 /*******************************/
1622 
1623 time_t dos_to_unix_time(dosdatetime)
1624     ulg dosdatetime;
1625 {
1626     time_t m_time;
1627 
1628 #ifdef HAVE_MKTIME
1629 
1630     ZCONST time_t now = time(NULL);
1631     struct tm *tm;
1632 #   define YRBASE  1900
1633 
1634     tm = localtime(&now);
1635     tm->tm_isdst = -1;          /* let mktime determine if DST is in effect */
1636 
1637     /* dissect date */
1638     tm->tm_year = ((int)(dosdatetime >> 25) & 0x7f) + (1980 - YRBASE);
1639     tm->tm_mon  = ((int)(dosdatetime >> 21) & 0x0f) - 1;
1640     tm->tm_mday = ((int)(dosdatetime >> 16) & 0x1f);
1641 
1642     /* dissect time */
1643     tm->tm_hour = (int)((unsigned)dosdatetime >> 11) & 0x1f;
1644     tm->tm_min  = (int)((unsigned)dosdatetime >> 5) & 0x3f;
1645     tm->tm_sec  = (int)((unsigned)dosdatetime << 1) & 0x3e;
1646 
1647     m_time = mktime(tm);
1648     NATIVE_TO_TIMET(m_time)     /* NOP unless MSC 7.0 or Macintosh */
1649     TTrace((stderr, "  final m_time  =       %lu\n", (ulg)m_time));
1650 
1651 #else /* !HAVE_MKTIME */
1652 
1653     int yr, mo, dy, hh, mm, ss;
1654 #ifdef TOPS20
1655 #   define YRBASE  1900
1656     struct tmx *tmx;
1657     char temp[20];
1658 #else /* !TOPS20 */
1659 #   define YRBASE  1970
1660     int leap;
1661     unsigned days;
1662     struct tm *tm;
1663 #if (!defined(MACOS) && !defined(RISCOS) && !defined(QDOS) && !defined(TANDEM))
1664 #ifdef WIN32
1665     TIME_ZONE_INFORMATION tzinfo;
1666     DWORD res;
1667 #else /* ! WIN32 */
1668 #ifndef BSD4_4   /* GRR:  change to !defined(MODERN) ? */
1669 #if (defined(BSD) || defined(MTS) || defined(__GO32__))
1670     struct timeb tbp;
1671 #else /* !(BSD || MTS || __GO32__) */
1672 #ifdef DECLARE_TIMEZONE
1673     extern time_t timezone;
1674 #endif
1675 #endif /* ?(BSD || MTS || __GO32__) */
1676 #endif /* !BSD4_4 */
1677 #endif /* ?WIN32 */
1678 #endif /* !MACOS && !RISCOS && !QDOS && !TANDEM */
1679 #endif /* ?TOPS20 */
1680 
1681 
1682     /* dissect date */
1683     yr = ((int)(dosdatetime >> 25) & 0x7f) + (1980 - YRBASE);
1684     mo = ((int)(dosdatetime >> 21) & 0x0f) - 1;
1685     dy = ((int)(dosdatetime >> 16) & 0x1f) - 1;
1686 
1687     /* dissect time */
1688     hh = (int)((unsigned)dosdatetime >> 11) & 0x1f;
1689     mm = (int)((unsigned)dosdatetime >> 5) & 0x3f;
1690     ss = (int)((unsigned)dosdatetime & 0x1f) * 2;
1691 
1692 #ifdef TOPS20
1693     tmx = (struct tmx *)malloc(sizeof(struct tmx));
1694     sprintf (temp, "%02d/%02d/%02d %02d:%02d:%02d", mo+1, dy+1, yr, hh, mm, ss);
1695     time_parse(temp, tmx, (char *)0);
1696     m_time = time_make(tmx);
1697     free(tmx);
1698 
1699 #else /* !TOPS20 */
1700 
1701 /*---------------------------------------------------------------------------
1702     Calculate the number of seconds since the epoch, usually 1 January 1970.
1703   ---------------------------------------------------------------------------*/
1704 
1705     /* leap = # of leap yrs from YRBASE up to but not including current year */
1706     leap = ((yr + YRBASE - 1) / 4);   /* leap year base factor */
1707 
1708     /* calculate days from BASE to this year and add expired days this year */
1709     days = (yr * 365) + (leap - 492) + ydays[mo];
1710 
1711     /* if year is a leap year and month is after February, add another day */
1712     if ((mo > 1) && ((yr+YRBASE)%4 == 0) && ((yr+YRBASE) != 2100))
1713         ++days;                 /* OK through 2199 */
1714 
1715     /* convert date & time to seconds relative to 00:00:00, 01/01/YRBASE */
1716     m_time = (time_t)(((unsigned long)days + dy) * 86400L +
1717                       (unsigned long)hh * 3600L +
1718                       (unsigned long)(mm * 60 + ss));
1719       /* - 1;   MS-DOS times always rounded up to nearest even second */
1720     TTrace((stderr, "dos_to_unix_time:\n"));
1721     TTrace((stderr, "  m_time before timezone = %lu\n", (ulg)m_time));
1722 
1723 /*---------------------------------------------------------------------------
1724     Adjust for local standard timezone offset.
1725   ---------------------------------------------------------------------------*/
1726 
1727 #if (!defined(MACOS) && !defined(RISCOS) && !defined(QDOS) && !defined(TANDEM))
1728 #ifdef WIN32
1729     /* account for timezone differences */
1730     res = GetTimeZoneInformation(&tzinfo);
1731     if (res != TIME_ZONE_ID_INVALID)
1732     {
1733     m_time += 60*(tzinfo.Bias);
1734 #else /* !WIN32 */
1735 #if (defined(BSD) || defined(MTS) || defined(__GO32__))
1736 #ifdef BSD4_4
1737     if ( (dosdatetime >= DOSTIME_2038_01_18) &&
1738          (m_time < (time_t)0x70000000L) )
1739         m_time = U_TIME_T_MAX;  /* saturate in case of (unsigned) overflow */
1740     if (m_time < (time_t)0L)    /* a converted DOS time cannot be negative */
1741         m_time = S_TIME_T_MAX;  /*  -> saturate at max signed time_t value */
1742     if ((tm = localtime(&m_time)) != (struct tm *)NULL)
1743         m_time -= tm->tm_gmtoff;                /* sec. EAST of GMT: subtr. */
1744 #else /* !(BSD4_4 */
1745     ftime(&tbp);                                /* get `timezone' */
1746     m_time += tbp.timezone * 60L;               /* seconds WEST of GMT:  add */
1747 #endif /* ?(BSD4_4 || __EMX__) */
1748 #else /* !(BSD || MTS || __GO32__) */
1749     /* tzset was already called at start of process_zipfiles() */
1750     /* tzset(); */              /* set `timezone' variable */
1751 #if (!defined(__BEOS__) && !defined(__HAIKU__))                /* BeOS DR8 has no timezones... */
1752     m_time += timezone;         /* seconds WEST of GMT:  add */
1753 #endif
1754 #endif /* ?(BSD || MTS || __GO32__) */
1755 #endif /* ?WIN32 */
1756     TTrace((stderr, "  m_time after timezone =  %lu\n", (ulg)m_time));
1757 
1758 /*---------------------------------------------------------------------------
1759     Adjust for local daylight savings (summer) time.
1760   ---------------------------------------------------------------------------*/
1761 
1762 #ifndef BSD4_4  /* (DST already added to tm_gmtoff, so skip tm_isdst) */
1763     if ( (dosdatetime >= DOSTIME_2038_01_18) &&
1764          (m_time < (time_t)0x70000000L) )
1765         m_time = U_TIME_T_MAX;  /* saturate in case of (unsigned) overflow */
1766     if (m_time < (time_t)0L)    /* a converted DOS time cannot be negative */
1767         m_time = S_TIME_T_MAX;  /*  -> saturate at max signed time_t value */
1768     TIMET_TO_NATIVE(m_time)     /* NOP unless MSC 7.0 or Macintosh */
1769     if (((tm = localtime((time_t *)&m_time)) != NULL) && tm->tm_isdst)
1770 #ifdef WIN32
1771         m_time += 60L * tzinfo.DaylightBias;    /* adjust with DST bias */
1772     else
1773         m_time += 60L * tzinfo.StandardBias;    /* add StdBias (normally 0) */
1774 #else
1775         m_time -= 60L * 60L;    /* adjust for daylight savings time */
1776 #endif
1777     NATIVE_TO_TIMET(m_time)     /* NOP unless MSC 7.0 or Macintosh */
1778     TTrace((stderr, "  m_time after DST =       %lu\n", (ulg)m_time));
1779 #endif /* !BSD4_4 */
1780 #ifdef WIN32
1781     }
1782 #endif
1783 #endif /* !MACOS && !RISCOS && !QDOS && !TANDEM */
1784 #endif /* ?TOPS20 */
1785 
1786 #endif /* ?HAVE_MKTIME */
1787 
1788     if ( (dosdatetime >= DOSTIME_2038_01_18) &&
1789          (m_time < (time_t)0x70000000L) )
1790         m_time = U_TIME_T_MAX;  /* saturate in case of (unsigned) overflow */
1791     if (m_time < (time_t)0L)    /* a converted DOS time cannot be negative */
1792         m_time = S_TIME_T_MAX;  /*  -> saturate at max signed time_t value */
1793 
1794     return m_time;
1795 
1796 } /* end function dos_to_unix_time() */
1797 
1798 #endif /* !OS2 || TIMESTAMP */
1799 #endif /* !VMS && !CMS_MVS */
1800 
1801 
1802 
1803 #if (!defined(VMS) && !defined(OS2) && !defined(CMS_MVS))
1804 
1805 /******************************/
1806 /* Function check_for_newer() */  /* used for overwriting/freshening/updating */
1807 /******************************/
1808 
1809 int check_for_newer(__G__ filename)  /* return 1 if existing file is newer */
1810     __GDEF                           /*  or equal; 0 if older; -1 if doesn't */
1811     char *filename;                  /*  exist yet */
1812 {
1813     time_t existing, archive;
1814 #ifdef USE_EF_UT_TIME
1815     iztimes z_utime;
1816 #endif
1817 #ifdef AOS_VS
1818     long    dyy, dmm, ddd, dhh, dmin, dss;
1819 
1820 
1821     dyy = (lrec.last_mod_dos_datetime >> 25) + 1980;
1822     dmm = (lrec.last_mod_dos_datetime >> 21) & 0x0f;
1823     ddd = (lrec.last_mod_dos_datetime >> 16) & 0x1f;
1824     dhh = (lrec.last_mod_dos_datetime >> 11) & 0x1f;
1825     dmin = (lrec.last_mod_dos_datetime >> 5) & 0x3f;
1826     dss = (lrec.last_mod_dos_datetime & 0x1f) * 2;
1827 
1828     /* under AOS/VS, file times can only be set at creation time,
1829      * with the info in a special DG format.  Make sure we can create
1830      * it here - we delete it later & re-create it, whether or not
1831      * it exists now.
1832      */
1833     if (!zvs_create(filename, (((ulg)dgdate(dmm, ddd, dyy)) << 16) |
1834         (dhh*1800L + dmin*30L + dss/2L), -1L, -1L, (char *) -1, -1, -1, -1))
1835         return DOES_NOT_EXIST;
1836 #endif /* AOS_VS */
1837 
1838     Trace((stderr, "check_for_newer:  doing stat(%s)\n", FnFilter1(filename)));
1839     if (SSTAT(filename, &G.statbuf)) {
1840         Trace((stderr,
1841           "check_for_newer:  stat(%s) returns %d:  file does not exist\n",
1842           FnFilter1(filename), SSTAT(filename, &G.statbuf)));
1843 #ifdef SYMLINKS
1844         Trace((stderr, "check_for_newer:  doing lstat(%s)\n",
1845           FnFilter1(filename)));
1846         /* GRR OPTION:  could instead do this test ONLY if G.symlnk is true */
1847         if (lstat(filename, &G.statbuf) == 0) {
1848             Trace((stderr,
1849               "check_for_newer:  lstat(%s) returns 0:  symlink does exist\n",
1850               FnFilter1(filename)));
1851             if (QCOND2 && !IS_OVERWRT_ALL)
1852                 Info(slide, 0, ((char *)slide, LoadFarString(FileIsSymLink),
1853                   FnFilter1(filename), " with no real file"));
1854             return EXISTS_AND_OLDER;   /* symlink dates are meaningless */
1855         }
1856 #endif /* SYMLINKS */
1857         return DOES_NOT_EXIST;
1858     }
1859     Trace((stderr, "check_for_newer:  stat(%s) returns 0:  file exists\n",
1860       FnFilter1(filename)));
1861 
1862 #ifdef SYMLINKS
1863     /* GRR OPTION:  could instead do this test ONLY if G.symlnk is true */
1864     if (lstat(filename, &G.statbuf) == 0 && S_ISLNK(G.statbuf.st_mode)) {
1865         Trace((stderr, "check_for_newer:  %s is a symbolic link\n",
1866           FnFilter1(filename)));
1867         if (QCOND2 && !IS_OVERWRT_ALL)
1868             Info(slide, 0, ((char *)slide, LoadFarString(FileIsSymLink),
1869               FnFilter1(filename), ""));
1870         return EXISTS_AND_OLDER;   /* symlink dates are meaningless */
1871     }
1872 #endif /* SYMLINKS */
1873 
1874     NATIVE_TO_TIMET(G.statbuf.st_mtime)   /* NOP unless MSC 7.0 or Macintosh */
1875 
1876 #ifdef USE_EF_UT_TIME
1877     /* The `Unix extra field mtime' should be used for comparison with the
1878      * time stamp of the existing file >>>ONLY<<< when the EF info is also
1879      * used to set the modification time of the extracted file.
1880      */
1881     if (G.extra_field &&
1882 #ifdef IZ_CHECK_TZ
1883         G.tz_is_valid &&
1884 #endif
1885         (ef_scan_for_izux(G.extra_field, G.lrec.extra_field_length, 0,
1886                           G.lrec.last_mod_dos_datetime, &z_utime, NULL)
1887          & EB_UT_FL_MTIME))
1888     {
1889         TTrace((stderr, "check_for_newer:  using Unix extra field mtime\n"));
1890         existing = G.statbuf.st_mtime;
1891         archive  = z_utime.mtime;
1892     } else {
1893         /* round up existing filetime to nearest 2 seconds for comparison,
1894          * but saturate in case of arithmetic overflow
1895          */
1896         existing = ((G.statbuf.st_mtime & 1) &&
1897                     (G.statbuf.st_mtime + 1 > G.statbuf.st_mtime)) ?
1898                    G.statbuf.st_mtime + 1 : G.statbuf.st_mtime;
1899         archive  = dos_to_unix_time(G.lrec.last_mod_dos_datetime);
1900     }
1901 #else /* !USE_EF_UT_TIME */
1902     /* round up existing filetime to nearest 2 seconds for comparison,
1903      * but saturate in case of arithmetic overflow
1904      */
1905     existing = ((G.statbuf.st_mtime & 1) &&
1906                 (G.statbuf.st_mtime + 1 > G.statbuf.st_mtime)) ?
1907                G.statbuf.st_mtime + 1 : G.statbuf.st_mtime;
1908     archive  = dos_to_unix_time(G.lrec.last_mod_dos_datetime);
1909 #endif /* ?USE_EF_UT_TIME */
1910 
1911     TTrace((stderr, "check_for_newer:  existing %lu, archive %lu, e-a %ld\n",
1912       (ulg)existing, (ulg)archive, (long)(existing-archive)));
1913 
1914     return (existing >= archive);
1915 
1916 } /* end function check_for_newer() */
1917 
1918 #endif /* !VMS && !OS2 && !CMS_MVS */
1919 
1920 
1921 
1922 
1923 
1924 /************************/
1925 /* Function do_string() */
1926 /************************/
1927 
1928 int do_string(__G__ length, option)   /* return PK-type error code */
1929     __GDEF
1930     unsigned int length;        /* without prototype, ush converted to this */
1931     int option;
1932 {
1933     unsigned comment_bytes_left;
1934     unsigned int block_len;
1935     int error=PK_OK;
1936 #ifdef AMIGA
1937     char tmp_fnote[2 * AMIGA_FILENOTELEN];   /* extra room for squozen chars */
1938 #endif
1939 
1940 
1941 /*---------------------------------------------------------------------------
1942     This function processes arbitrary-length (well, usually) strings.  Four
1943     major options are allowed:  SKIP, wherein the string is skipped (pretty
1944     logical, eh?); DISPLAY, wherein the string is printed to standard output
1945     after undergoing any necessary or unnecessary character conversions;
1946     DS_FN, wherein the string is put into the filename[] array after under-
1947     going appropriate conversions (including case-conversion, if that is
1948     indicated: see the global variable pInfo->lcflag); and EXTRA_FIELD,
1949     wherein the `string' is assumed to be an extra field and is copied to
1950     the (freshly malloced) buffer G.extra_field.  The third option should
1951     be OK since filename is dimensioned at 1025, but we check anyway.
1952 
1953     The string, by the way, is assumed to start at the current file-pointer
1954     position; its length is given by 'length'.  So start off by checking the
1955     length of the string:  if zero, we're already done.
1956   ---------------------------------------------------------------------------*/
1957 
1958     if (!length)
1959         return PK_COOL;
1960 
1961     switch (option) {
1962 
1963 #if (defined(SFX) && defined(CHEAP_SFX_AUTORUN))
1964     /*
1965      * Special case: See if the comment begins with an autorun command line.
1966      * Save that and display (or skip) the remainder.
1967      */
1968 
1969     case CHECK_AUTORUN:
1970     case CHECK_AUTORUN_Q:
1971         comment_bytes_left = length;
1972         if (length >= 10)
1973         {
1974             block_len = readbuf(__G__ (char *)G.outbuf, 10);
1975             if (block_len == 0)
1976                 return PK_EOF;
1977             comment_bytes_left -= block_len;
1978             G.outbuf[block_len] = '\0';
1979             if (!strcmp((char *)G.outbuf, "$AUTORUN$>")) {
1980                 char *eol;
1981                 length -= 10;
1982                 block_len = readbuf(__G__ G.autorun_command,
1983                                     MIN(length, sizeof(G.autorun_command)-1));
1984                 if (block_len == 0)
1985                     return PK_EOF;
1986                 comment_bytes_left -= block_len;
1987                 G.autorun_command[block_len] = '\0';
1988                 A_TO_N(G.autorun_command);
1989                 eol = strchr(G.autorun_command, '\n');
1990                 if (!eol)
1991                     eol = G.autorun_command + strlen(G.autorun_command) - 1;
1992                 length -= eol + 1 - G.autorun_command;
1993                 while (eol >= G.autorun_command && isspace(*eol))
1994                     *eol-- = '\0';
1995 #ifdef WIN32
1996                 /* Win9x console always uses OEM character coding, and
1997                    WinNT console is set to OEM charset by default, too */
1998                 INTERN_TO_OEM(G.autorun_command, G.autorun_command);
1999 #endif /* WIN32 */
2000             }
2001         }
2002         if (option == CHECK_AUTORUN_Q)  /* don't display the remainder */
2003             length = 0;
2004         /* seek to beginning of remaining part of comment -- rewind if */
2005         /* displaying entire comment, or skip to end if discarding it  */
2006         seek_zipf(__G__ G.cur_zipfile_bufstart - G.extra_bytes +
2007                   (G.inptr - G.inbuf) + comment_bytes_left - length);
2008         if (!length)
2009             break;
2010         /*  FALL THROUGH...  */
2011 #endif /* SFX && CHEAP_SFX_AUTORUN */
2012 
2013     /*
2014      * First normal case:  print string on standard output.  First set loop
2015      * variables, then loop through the comment in chunks of OUTBUFSIZ bytes,
2016      * converting formats and printing as we go.  The second half of the
2017      * loop conditional was added because the file might be truncated, in
2018      * which case comment_bytes_left will remain at some non-zero value for
2019      * all time.  outbuf and slide are used as scratch buffers because they
2020      * are available (we should be either before or in between any file pro-
2021      * cessing).
2022      */
2023 
2024     case DISPLAY:
2025     case DISPL_8:
2026         comment_bytes_left = length;
2027         block_len = OUTBUFSIZ;       /* for the while statement, first time */
2028         while (comment_bytes_left > 0 && block_len > 0) {
2029             register uch *p = G.outbuf;
2030             register uch *q = G.outbuf;
2031 
2032             if ((block_len = readbuf(__G__ (char *)G.outbuf,
2033                    MIN((unsigned)OUTBUFSIZ, comment_bytes_left))) == 0)
2034                 return PK_EOF;
2035             comment_bytes_left -= block_len;
2036 
2037             /* this is why we allocated an extra byte for outbuf:  terminate
2038              *  with zero (ASCIIZ) */
2039             G.outbuf[block_len] = '\0';
2040 
2041             /* remove all ASCII carriage returns from comment before printing
2042              * (since used before A_TO_N(), check for CR instead of '\r')
2043              */
2044             while (*p) {
2045                 while (*p == CR)
2046                     ++p;
2047                 *q++ = *p++;
2048             }
2049             /* could check whether (p - outbuf) == block_len here */
2050             *q = '\0';
2051 
2052             if (option == DISPL_8) {
2053                 /* translate the text coded in the entry's host-dependent
2054                    "extended ASCII" charset into the compiler's (system's)
2055                    internal text code page */
2056                 Ext_ASCII_TO_Native((char *)G.outbuf, G.pInfo->hostnum,
2057                                     G.pInfo->hostver, G.pInfo->HasUxAtt,
2058                                     FALSE);
2059 #ifdef WINDLL
2060                 /* translate to ANSI (RTL internal codepage may be OEM) */
2061                 INTERN_TO_ISO((char *)G.outbuf, (char *)G.outbuf);
2062 #else /* !WINDLL */
2063 #ifdef WIN32
2064                 /* Win9x console always uses OEM character coding, and
2065                    WinNT console is set to OEM charset by default, too */
2066                 INTERN_TO_OEM((char *)G.outbuf, (char *)G.outbuf);
2067 #endif /* WIN32 */
2068 #endif /* ?WINDLL */
2069             } else {
2070                 A_TO_N(G.outbuf);   /* translate string to native */
2071             }
2072 
2073 #ifdef WINDLL
2074             /* ran out of local mem -- had to cheat */
2075             win_fprintf((zvoid *)&G, stdout, length, (char *)G.outbuf);
2076             win_fprintf((zvoid *)&G, stdout, 2, (char *)"\n\n");
2077 #else /* !WINDLL */
2078 #ifdef NOANSIFILT       /* GRR:  can ANSI be used with EBCDIC? */
2079             (*G.message)((zvoid *)&G, G.outbuf, (ulg)(q-G.outbuf), 0);
2080 #else /* ASCII, filter out ANSI escape sequences and handle ^S (pause) */
2081             p = G.outbuf - 1;
2082             q = slide;
2083             while (*++p) {
2084                 int pause = FALSE;
2085 
2086                 if (*p == 0x1B) {          /* ASCII escape char */
2087                     *q++ = '^';
2088                     *q++ = '[';
2089                 } else if (*p == 0x13) {   /* ASCII ^S (pause) */
2090                     pause = TRUE;
2091                     if (p[1] == LF)        /* ASCII LF */
2092                         *q++ = *++p;
2093                     else if (p[1] == CR && p[2] == LF) {  /* ASCII CR LF */
2094                         *q++ = *++p;
2095                         *q++ = *++p;
2096                     }
2097                 } else
2098                     *q++ = *p;
2099                 if ((unsigned)(q-slide) > WSIZE-3 || pause) {   /* flush */
2100                     (*G.message)((zvoid *)&G, slide, (ulg)(q-slide), 0);
2101                     q = slide;
2102                     if (pause && G.extract_flag) /* don't pause for list/test */
2103                         (*G.mpause)((zvoid *)&G, LoadFarString(QuitPrompt), 0);
2104                 }
2105             }
2106             (*G.message)((zvoid *)&G, slide, (ulg)(q-slide), 0);
2107 #endif /* ?NOANSIFILT */
2108 #endif /* ?WINDLL */
2109         }
2110         /* add '\n' if not at start of line */
2111         (*G.message)((zvoid *)&G, slide, 0L, 0x40);
2112         break;
2113 
2114     /*
2115      * Second case:  read string into filename[] array.  The filename should
2116      * never ever be longer than FILNAMSIZ-1 (1024), but for now we'll check,
2117      * just to be sure.
2118      */
2119 
2120     case DS_FN:
2121     case DS_FN_L:
2122         if (length >= FILNAMSIZ) {
2123             Info(slide, 0x401, ((char *)slide,
2124               LoadFarString(FilenameTooLongTrunc)));
2125             error = PK_WARN;
2126             /* remember excess length in block_len */
2127             block_len = length - (FILNAMSIZ - 1);
2128             length = FILNAMSIZ - 1;
2129         } else
2130             /* no excess size */
2131             block_len = 0;
2132         if (readbuf(__G__ G.filename, length) == 0)
2133             return PK_EOF;
2134         G.filename[length] = '\0';      /* terminate w/zero:  ASCIIZ */
2135 
2136         /* translate the Zip entry filename coded in host-dependent "extended
2137            ASCII" into the compiler's (system's) internal text code page */
2138         Ext_ASCII_TO_Native(G.filename, G.pInfo->hostnum, G.pInfo->hostver,
2139                             G.pInfo->HasUxAtt, (option == DS_FN_L));
2140 
2141         if (G.pInfo->lcflag)      /* replace with lowercase filename */
2142             STRLOWER(G.filename, G.filename);
2143 
2144         if (G.pInfo->vollabel && length > 8 && G.filename[8] == '.') {
2145             char *p = G.filename+8;
2146             while (*p++)
2147                 p[-1] = *p;  /* disk label, and 8th char is dot:  remove dot */
2148         }
2149 
2150         if (!block_len)         /* no overflow, we're done here */
2151             break;
2152 
2153         /*
2154          * We truncated the filename, so print what's left and then fall
2155          * through to the SKIP routine.
2156          */
2157         Info(slide, 0x401, ((char *)slide, "[ %s ]\n", FnFilter1(G.filename)));
2158         length = block_len;     /* SKIP the excess bytes... */
2159         /*  FALL THROUGH...  */
2160 
2161     /*
2162      * Third case:  skip string, adjusting readbuf's internal variables
2163      * as necessary (and possibly skipping to and reading a new block of
2164      * data).
2165      */
2166 
2167     case SKIP:
2168         /* cur_zipfile_bufstart already takes account of extra_bytes, so don't
2169          * correct for it twice: */
2170         seek_zipf(__G__ G.cur_zipfile_bufstart - G.extra_bytes +
2171                   (G.inptr-G.inbuf) + length);
2172         break;
2173 
2174     /*
2175      * Fourth case:  assume we're at the start of an "extra field"; malloc
2176      * storage for it and read data into the allocated space.
2177      */
2178 
2179     case EXTRA_FIELD:
2180         if (G.extra_field != (uch *)NULL)
2181             free(G.extra_field);
2182         if ((G.extra_field = (uch *)malloc(length)) == (uch *)NULL) {
2183             Info(slide, 0x401, ((char *)slide, LoadFarString(ExtraFieldTooLong),
2184               length));
2185             /* cur_zipfile_bufstart already takes account of extra_bytes,
2186              * so don't correct for it twice: */
2187             seek_zipf(__G__ G.cur_zipfile_bufstart - G.extra_bytes +
2188                       (G.inptr-G.inbuf) + length);
2189         } else
2190             if (readbuf(__G__ (char *)G.extra_field, length) == 0)
2191                 return PK_EOF;
2192         break;
2193 
2194 #ifdef AMIGA
2195     /*
2196      * Fifth case, for the Amiga only:  take the comment that would ordinarily
2197      * be skipped over, and turn it into a 79 character string that will be
2198      * attached to the file as a "filenote" after it is extracted.
2199      */
2200 
2201     case FILENOTE:
2202         if ((block_len = readbuf(__G__ tmp_fnote, (unsigned)
2203                                  MIN(length, 2 * AMIGA_FILENOTELEN - 1))) == 0)
2204             return PK_EOF;
2205         if ((length -= block_len) > 0)  /* treat remainder as in case SKIP: */
2206             seek_zipf(__G__ G.cur_zipfile_bufstart - G.extra_bytes
2207                       + (G.inptr - G.inbuf) + length);
2208         /* convert multi-line text into single line with no ctl-chars: */
2209         tmp_fnote[block_len] = '\0';
2210         while ((short int) --block_len >= 0)
2211             if ((unsigned) tmp_fnote[block_len] < ' ')
2212                 if (tmp_fnote[block_len+1] == ' ')     /* no excess */
2213                     strcpy(tmp_fnote+block_len, tmp_fnote+block_len+1);
2214                 else
2215                     tmp_fnote[block_len] = ' ';
2216         tmp_fnote[AMIGA_FILENOTELEN - 1] = '\0';
2217         if (G.filenotes[G.filenote_slot])
2218             free(G.filenotes[G.filenote_slot]);     /* should not happen */
2219         G.filenotes[G.filenote_slot] = NULL;
2220         if (tmp_fnote[0]) {
2221             if (!(G.filenotes[G.filenote_slot] = malloc(strlen(tmp_fnote)+1)))
2222                 return PK_MEM;
2223             strcpy(G.filenotes[G.filenote_slot], tmp_fnote);
2224         }
2225         break;
2226 #endif /* AMIGA */
2227 
2228     } /* end switch (option) */
2229 
2230     return error;
2231 
2232 } /* end function do_string() */
2233 
2234 
2235 
2236 
2237 
2238 /***********************/
2239 /* Function makeword() */
2240 /***********************/
2241 
2242 ush makeword(b)
2243     ZCONST uch *b;
2244 {
2245     /*
2246      * Convert Intel style 'short' integer to non-Intel non-16-bit
2247      * host format.  This routine also takes care of byte-ordering.
2248      */
2249     return (ush)((b[1] << 8) | b[0]);
2250 }
2251 
2252 
2253 
2254 
2255 
2256 /***********************/
2257 /* Function makelong() */
2258 /***********************/
2259 
2260 ulg makelong(sig)
2261     ZCONST uch *sig;
2262 {
2263     /*
2264      * Convert intel style 'long' variable to non-Intel non-16-bit
2265      * host format.  This routine also takes care of byte-ordering.
2266      */
2267     return (((ulg)sig[3]) << 24)
2268         + (((ulg)sig[2]) << 16)
2269         + (((ulg)sig[1]) << 8)
2270         + ((ulg)sig[0]);
2271 }
2272 
2273 
2274 
2275 #if CRYPT
2276 
2277 #ifdef NEED_STR2ISO
2278 /**********************/
2279 /* Function str2iso() */
2280 /**********************/
2281 
2282 char *str2iso(dst, src)
2283     char *dst;                          /* destination buffer */
2284     register ZCONST char *src;          /* source string */
2285 {
2286 #ifdef INTERN_TO_ISO
2287     INTERN_TO_ISO(src, dst);
2288 #else
2289     register uch c;
2290     register char *dstp = dst;
2291 
2292     do {
2293         c = (uch)foreign(*src++);
2294         *dstp++ = (char)ASCII2ISO(c);
2295     } while (c != '\0');
2296 #endif
2297 
2298     return dst;
2299 }
2300 #endif /* NEED_STR2ISO */
2301 
2302 
2303 #ifdef NEED_STR2OEM
2304 /**********************/
2305 /* Function str2oem() */
2306 /**********************/
2307 
2308 char *str2oem(dst, src)
2309     char *dst;                          /* destination buffer */
2310     register ZCONST char *src;          /* source string */
2311 {
2312 #ifdef INTERN_TO_OEM
2313     INTERN_TO_OEM(src, dst);
2314 #else
2315     register uch c;
2316     register char *dstp = dst;
2317 
2318     do {
2319         c = (uch)foreign(*src++);
2320         *dstp++ = (char)ASCII2OEM(c);
2321     } while (c != '\0');
2322 #endif
2323 
2324     return dst;
2325 }
2326 #endif /* NEED_STR2OEM */
2327 
2328 #endif /* CRYPT */
2329 
2330 
2331 #ifdef ZMEM  /* memset/memcmp/memcpy for systems without either them or */
2332              /* bzero/bcmp/bcopy */
2333              /* (no known systems as of 960211) */
2334 
2335 /*********************/
2336 /* Function memset() */
2337 /*********************/
2338 
2339 zvoid *memset(buf, init, len)
2340     register zvoid *buf;        /* buffer location */
2341     register int init;          /* initializer character */
2342     register unsigned int len;  /* length of the buffer */
2343 {
2344     zvoid *start;
2345 
2346     start = buf;
2347     while (len--)
2348         *((char *)buf++) = (char)init;
2349     return start;
2350 }
2351 
2352 
2353 
2354 /*********************/
2355 /* Function memcmp() */
2356 /*********************/
2357 
2358 int memcmp(b1, b2, len)
2359     register ZCONST zvoid *b1;
2360     register ZCONST zvoid *b2;
2361     register unsigned int len;
2362 {
2363     register int c;
2364 
2365     if (len > 0) do {
2366         if ((c = (int)(*((ZCONST unsigned char *)b1)++) -
2367                  (int)(*((ZCONST unsigned char *)b2)++)) != 0)
2368            return c;
2369     } while (--len > 0)
2370     return 0;
2371 }
2372 
2373 
2374 
2375 /*********************/
2376 /* Function memcpy() */
2377 /*********************/
2378 
2379 zvoid *memcpy(dst, src, len)
2380     register zvoid *dst;
2381     register ZCONST zvoid *src;
2382     register unsigned int len;
2383 {
2384     zvoid *start;
2385 
2386     start = dst;
2387     while (len-- > 0)
2388         *((char *)dst)++ = *((ZCONST char *)src)++;
2389     return start;
2390 }
2391 
2392 #endif /* ZMEM */
2393 
2394 
2395 
2396 
2397 #ifdef NO_STRNICMP
2398 
2399 /************************/
2400 /* Function zstrnicmp() */
2401 /************************/
2402 
2403 int zstrnicmp(s1, s2, n)
2404     register ZCONST char *s1, *s2;
2405     register unsigned n;
2406 {
2407     for (; n > 0;  --n, ++s1, ++s2) {
2408 
2409         if (ToLower(*s1) != ToLower(*s2))
2410             /* test includes early termination of one string */
2411             return (ToLower(*s1) < ToLower(*s2))? -1 : 1;
2412 
2413         if (*s1 == '\0')   /* both strings terminate early */
2414             return 0;
2415     }
2416     return 0;
2417 }
2418 
2419 #endif /* NO_STRNICMP */
2420 
2421 
2422 
2423 
2424 #ifdef REGULUS  /* returns the inode number on success(!)...argh argh argh */
2425 #  undef stat
2426 
2427 /********************/
2428 /* Function zstat() */
2429 /********************/
2430 
2431 int zstat(p, s)
2432     ZCONST char *p;
2433     struct stat *s;
2434 {
2435     return (stat((char *)p,s) >= 0? 0 : (-1));
2436 }
2437 
2438 #endif /* REGULUS */
2439 
2440 
2441 
2442 
2443 #ifdef _MBCS
2444 
2445 /* DBCS support for Info-ZIP's zip  (mainly for japanese (-: )
2446  * by Yoshioka Tsuneo (QWF00133@nifty.ne.jp,tsuneo-y@is.aist-nara.ac.jp)
2447  * This code is public domain!   Date: 1998/12/20
2448  */
2449 
2450 /************************/
2451 /* Function plastchar() */
2452 /************************/
2453 
2454 char *plastchar(ptr, len)
2455     ZCONST char *ptr;
2456     extent len;
2457 {
2458     unsigned clen;
2459     ZCONST char *oldptr = ptr;
2460     while(*ptr != '\0' && len > 0){
2461         oldptr = ptr;
2462         clen = CLEN(ptr);
2463         ptr += clen;
2464         len -= clen;
2465     }
2466     return (char *)oldptr;
2467 }
2468 
2469 
2470 #ifdef NEED_UZMBSCHR
2471 /***********************/
2472 /* Function uzmbschr() */
2473 /***********************/
2474 
2475 unsigned char *uzmbschr(str, c)
2476     ZCONST unsigned char *str;
2477     unsigned int c;
2478 {
2479     while(*str != '\0'){
2480         if (*str == c) {return (unsigned char *)str;}
2481         INCSTR(str);
2482     }
2483     return NULL;
2484 }
2485 #endif /* NEED_UZMBSCHR */
2486 
2487 
2488 #ifdef NEED_UZMBSRCHR
2489 /************************/
2490 /* Function uzmbsrchr() */
2491 /************************/
2492 
2493 unsigned char *uzmbsrchr(str, c)
2494     ZCONST unsigned char *str;
2495     unsigned int c;
2496 {
2497     unsigned char *match = NULL;
2498     while(*str != '\0'){
2499         if (*str == c) {match = (unsigned char *)str;}
2500         INCSTR(str);
2501     }
2502     return match;
2503 }
2504 #endif /* NEED_UZMBSRCHR */
2505 #endif /* _MBCS */
2506 
2507 
2508 
2509 
2510 
2511 #ifdef SMALL_MEM
2512 
2513 /*******************************/
2514 /*  Function fLoadFarString()  */   /* (and friends...) */
2515 /*******************************/
2516 
2517 char *fLoadFarString(__GPRO__ const char Far *sz)
2518 {
2519     (void)zfstrcpy(G.rgchBigBuffer, sz);
2520     return G.rgchBigBuffer;
2521 }
2522 
2523 char *fLoadFarStringSmall(__GPRO__ const char Far *sz)
2524 {
2525     (void)zfstrcpy(G.rgchSmallBuffer, sz);
2526     return G.rgchSmallBuffer;
2527 }
2528 
2529 char *fLoadFarStringSmall2(__GPRO__ const char Far *sz)
2530 {
2531     (void)zfstrcpy(G.rgchSmallBuffer2, sz);
2532     return G.rgchSmallBuffer2;
2533 }
2534 
2535 
2536 
2537 
2538 #if (!defined(_MSC_VER) || (_MSC_VER < 600))
2539 /*************************/
2540 /*  Function zfstrcpy()  */   /* portable clone of _fstrcpy() */
2541 /*************************/
2542 
2543 char Far * Far zfstrcpy(char Far *s1, const char Far *s2)
2544 {
2545     char Far *p = s1;
2546 
2547     while ((*s1++ = *s2++) != '\0');
2548     return p;
2549 }
2550 #endif /* !_MSC_VER || (_MSC_VER < 600) */
2551 
2552 #endif /* SMALL_MEM */
2553