home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / c-kermit / ckifio.c < prev    next >
C/C++ Source or Header  |  2020-01-01  |  40KB  |  1,365 lines

  1. char *ckzv = "Amiga file support $Id: ckifio.c,v 1.13 1999/09/12 00:28:28 swalton Exp swalton $";
  2.  
  3. /* C K I F I O  --  Kermit file system support for the Amiga */
  4.  
  5. /*
  6.   Author: Frank da Cruz (SY.FDC@CU20B),
  7.   Columbia University Center for Computing Activities, January 1985.
  8.   Modified for Amiga by Jack J. Rouse, The Software Distillery
  9.   Further modified for C Kermit version 4F(095) by Stephen Walton,
  10.   California State University, Northridge, ecphssrw@afws.csun.edu
  11.  
  12.   Copyright (C) 1985, 1992, Trustees of Columbia University in the City of New
  13.   York.  Permission is granted to any individual or institution to use this
  14.   software as long as it is not sold for profit.  This copyright notice must be
  15.   retained.  This software may not be included in commercial products without
  16.   written permission of Columbia University.
  17.  
  18.  * $Log: ckifio.c,v $
  19.  * Revision 1.13  1999/09/12 00:28:28  swalton
  20.  * Purely administrative checkin of 1.12 due to lost RCS file.
  21.  *
  22.  * Revision 1.12  1998/04/17 04:13:16  swalton
  23.  * Amiga version of isdir() added, so CK_TMPDIR can now be used.
  24.  * chkfn() function replaced with current version from ckufio.c
  25.  *
  26.  * Revision 1.11  1996/11/29 21:56:54  swalton
  27.  * StatToTime() is stubbed out for SAS/C (returns its argument), since,
  28.  * unlike Aztec, the stat() function returns time to the same standard
  29.  * as the time() function.
  30.  *
  31.  * Revision 1.10  1996/11/25 14:58:27  swalton
  32.  * Fixed a couple of includes and changed the "access" element of the file
  33.  * attribute structure to "xaccess".
  34.  *
  35.  * Revision 1.9  94/07/26  16:38:59  swalton
  36.  * Added zfseek() to support RESEND.  Changed spelling of item in file type
  37.  * buffer from passwd to password.
  38.  *
  39.  * Revision 1.8  93/08/03  08:28:44  swalton
  40.  * Changed include of SAS and Aztec-specific include files to Amiga
  41.  * standard (clib/ and pragmas/).
  42.  *
  43.  * Revision 1.7  92/10/30  16:11:42  swalton
  44.  * Added code to call SetCurrentDirName() if and only if ROM version
  45.  * is greater than 37.  Depends on the extern int v37, set in ckitio.c.
  46.  *
  47.  * Revision 1.6  92/01/15  17:14:16  swalton
  48.  * Delete the Aztec StatToTime function, as it is now identical to the
  49.  * Lattice one.
  50.  *
  51.  * Also used Id rather than Header in the RCS ID string.
  52.  *
  53.  * Revision 1.5  91/07/18  16:01:59  swalton
  54.  * zxcmd() fixed to work properly.  I had accidentally copied the first part
  55.  * of the Unix version, which dealt with Kermit sending its received data
  56.  * to a command as its input.  Amiga Kermit doesn't support this, but does
  57.  * support sending the output of a command to a remote Kermit via the
  58.  * pipeopen() routine in ckiutl.c.
  59.  *
  60.  * Revision 1.4  91/05/29  09:08:17  swalton
  61.  * 1.  Changed function definitions to prototype style.  Required adding
  62.  *     a few forward declarations.
  63.  * 2.  Removed includes of stdio.h, stdlib.h, and string.h, as they are
  64.  *     now pulled in by ckcdeb.h, provided we compile with -DCK_ANSILIBS.
  65.  *
  66.  * Revision 1.3  90/11/19  21:46:11  swalton
  67.  * Modifications for compiling with SAS/C Version 5.10, courtesy of
  68.  * Larry Rosenman (ler@lerami.lonestar.org, ler on BIX)
  69.  *
  70.  * Revision 1.2  90/11/07  14:40:57  swalton
  71.  * Version 1.2--released to world as first beta test version simultaneously
  72.  * with release of edit 5A(160).
  73.  *
  74.  * Revision 1.1  90/07/12  07:56:05  swalton
  75.  * Fairly extensive modifications to bring Amiga Kermit up to Version 5A, edit
  76.  * 149.  Most of the changes can be discerned by reading ckasys.doc, the C Kermit
  77.  * interface document and looking for the items flagged *NEW*.
  78.  *
  79.  * Revision 1.0  90/04/30  11:54:31  swalton
  80.  * Initial revision
  81.  *
  82. */
  83.  
  84. /* Includes */
  85.  
  86. #define LONG            /* Prevent LONG definition from coming from
  87.                    ckcdeb.h, as it conflicts with exec/type.h */
  88. #include "ckcdeb.h"        /* Typedefs, formats for debug() */
  89. #undef LONG
  90. #undef ULONG
  91. #undef USHORT
  92. #undef UWORD
  93.  
  94. #include "ckcker.h"
  95. #include "ckcasc.h"
  96. #if AZTEC_C
  97. #include <stat.h>
  98. #endif
  99. #if __SASC
  100. #include <sys/types.h>
  101. #include <sys/stat.h>
  102. #include <proto/dos.h>
  103. #endif
  104. #include <time.h>
  105. #include <libraries/dosextens.h>
  106. #include <exec/memory.h>
  107.  
  108. #include <clib/exec_protos.h>
  109. #include <clib/dos_protos.h>
  110. #include <pragmas/exec_pragmas.h>
  111. #include <pragmas/dos_pragmas.h>
  112.  
  113. #include <fcntl.h>        /* for prototypes for write() and read() */
  114. #define MAXNAMLEN 30
  115. #ifdef AZTEC_C
  116. char *ckzsys = " Amiga (Aztec C)";
  117. #endif
  118. #ifdef __SASC
  119. char *ckzsys = " Amiga (SAS/C)";
  120. #endif
  121.  
  122. /* Definitions of some Amiga system commands */
  123.  
  124. char *DIRCMD = "list ";            /* For directory listing */
  125. char *DIRCM2 = "list ";            /* Also for directory listing. */
  126. char *DELCMD = "delete ";        /* For file deletion */
  127. char *TYPCMD = "type ";            /* For typing a file */
  128. char *PWDCMD = "cd ";            /* For saying where I am */
  129.  
  130. char *SPACMD = "info ";
  131.  
  132. char *SPACM2 = "info ";            /* should be space in specified directory */
  133.  
  134. char *WHOCMD = "status ";        /* Check process status */
  135.  
  136. #define MAXWLD 300
  137.  
  138. /*
  139.   Functions (n is one of the predefined file numbers from ckermi.h):
  140.  
  141.    zopeni(n,name)   -- Opens an existing file for input.
  142.    zopeno(n,name,attr,fcb)  -- Opens a new file for output.
  143.    zclose(n)        -- Closes a file.
  144.    zchin(n,&c)      -- Gets the next character from an input file.
  145.    zsinl(n,s,x)      -- Reads a line from file number n.
  146.    zsout(n,s)       -- Write a null-terminated string to output file, buffered.
  147.    zsoutl(n,s)      -- Like zsout, but appends a line terminator.
  148.    zsoutx(n,s,x)    -- Write x characters to output file, unbuffered.
  149.    zchout(n,c)      -- Add a character to an output file, unbuffered.
  150.    zchki(name)      -- Check if named file exists and is readable, return size.
  151.    zchko(name)      -- Check if named file can be created.
  152.    zchkspa(fn, len) -- Check if there is enough space for file.
  153.    znewn(name,s)    -- Make a new unique file name based on the given name.
  154.    zdelet(name)     -- Delete the named file.
  155.    zxpand(string)   -- Expands the given wildcard string into a list of files.
  156.    znext(string)    -- Returns the next file from the list in "string".
  157.    zxcmd(n,cmd)     -- Execute the command in a lower fork on file number n.
  158.    zclosf(n)        -- Close input file associated with zxcmd()'s lower fork.
  159.    zrtol(n1,n2)     -- Convert remote filename into local form.
  160.    zltor(n1,n2)     -- Convert local filename into remote form.
  161.    zstrip(n1, n2)   -- Find trailing path component of n1 and return pointer
  162.    zchdir(dirnam)   -- Change working directory.
  163.    zhome()          -- Return pointer to home directory name string.
  164.    zkself()         -- Kill self, log out own job (simply exits)
  165.    zsattr(struct zattr *) -- Return attributes for file which is being sent.
  166.    zstime(f, struct zattr *, x) - Set file creation date from attribute packet.
  167.    zrename(old, new) -- Rename a file.
  168.    zshcmd(s,local)  -- Execute a shell command and redirect its output, if
  169.                        necessary (see ckasys.doc)
  170.   */
  171.  
  172. /* Declarations */
  173.  
  174. FILE *fp[ZNFILS] = {             /* File pointers */
  175.     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
  176.  
  177. /* (PWP) external def. of things used in buffered file input and output */
  178. #ifdef DYNAMIC
  179. extern CHAR *zinbuffer, *zoutbuffer;
  180. #else
  181. extern CHAR zinbuffer[], zoutbuffer[];
  182. #endif /* DYNAMIC */
  183. extern CHAR *zinptr, *zoutptr;
  184. extern int zincnt, zoutcnt;
  185.  
  186. static long iflen = -1;            /* Input file length. */
  187.  
  188. static int fcount;            /* Number of files in wild group */
  189. static char  nambuf[MAXNAMLEN+2];    /* Buffer for a filename */
  190.  
  191. char *mtchs[MAXWLD],        /* Matches found for filename */
  192.      **mtchptr;            /* Pointer to current match */
  193. extern short v37;        /* Are we 2.0 or greater? */
  194.  
  195. /* utility functions from ckiutl.c */
  196. extern int existobj();
  197. struct DirHandle    /* fake structure definition */
  198. {
  199.     int _foo_;
  200. };
  201. extern struct DirHandle *opendir();
  202. extern char *readdir();
  203. void closedir();
  204.  
  205. /*
  206.  * Some new time functions.  These are defined up here to make it obvious
  207.  * that they need changing for your compiler.
  208.  */
  209.  
  210. /*
  211.  * The following uses the fact that, on the Amiga, a tm is a long value
  212.  * containing the number of seconds since midnight January 1, 1970.
  213.  * The Amiga's reference time is January 1, 1978 at midnight.
  214.  * The following conversion value is the number of seconds between
  215.  * those two dates.
  216.  */
  217. #define CONVERT (86400L*(2*366 + 6*365))
  218.  
  219. /*
  220.  * TimeToDateStamp accepts a time_t value as returned by, for instance,
  221.  * time() and converts it into an AmigaDos DateStamp.
  222.  */
  223. static void
  224. TimeToDateStamp(time_t tm, struct DateStamp *ds) {
  225.     long seconds = (long) tm - CONVERT;
  226.     ds->ds_Days = seconds / 86400;
  227.     ds->ds_Minute = (seconds - (ds->ds_Days * 86400)) / 60;
  228.     ds->ds_Tick = TICKS_PER_SECOND * (seconds%60);
  229. }
  230.  
  231. static time_t
  232. StatToTime(long mtime) {
  233. #ifdef __SASC
  234.     /*
  235.      * SAS uses the same time convention as Unix for the mtime in
  236.      * a stat struct..
  237.      */
  238.     return((time_t) mtime);
  239. #else
  240.     return((time_t) (mtime + CONVERT));
  241. #endif
  242. }
  243.  
  244. /*  Z K S E L F  --  Kill Self: log out own job, if possible.  */
  245. int
  246. zkself(void) {                /* For "bye", but no guarantee! */
  247.     doexit(GOOD_EXIT, -1);
  248. }
  249.  
  250. /*  Z O P E N I  --  Open an existing file for input. */
  251. int
  252. zopeni(int n, char *name) {
  253.     debug(F111," zopeni",name,n);
  254.     debug(F101,"  fp","",(int) fp[n]);
  255.     if (chkfn(n) != 0) return(0);
  256.     zincnt = 0;
  257.     if (n == ZSYSFN) {            /* Input from a system function? */
  258. /*** Note, this function should not be called with ZSYSFN ***/
  259. /*** Always call zxcmd() directly, and give it the real file number ***/
  260. /*** you want to use.  ***/
  261.         debug(F110,"zopeni called with ZSYSFN, failing!",name,0);
  262.     *nambuf = '\0';            /* No filename. */
  263.     return(0);            /* fail. */
  264. #ifdef COMMENT
  265.     return(zxcmd(n,name));        /* Try to fork the command */
  266. #endif
  267.     }
  268.     if (n == ZSTDIO) {            /* Standard input? */
  269.     if (isatty(0)) {
  270.         ermsg("Terminal input not allowed");
  271.         debug(F110,"zopeni: attempts input from unredirected stdin","",0);
  272.         return(0);
  273.     }
  274.     fp[ZIFILE] = stdin;
  275.     return(1);
  276.     }
  277.     fp[n] = fopen(name,"r");        /* Real file. */
  278.     debug(F111," zopeni", name, (int) fp[n]);
  279.     if (fp[n] == NULL) perror("zopeni");
  280.     return((fp[n] != NULL) ? 1 : 0);
  281. }
  282.  
  283. /*  Z O P E N O  --  Open a new file for output.  */
  284. int
  285. zopeno(int n, char *name, struct zattr *zz, struct filinfo *fcb) {
  286.  
  287.     char *p;        /* Local use pointer */
  288.     if (fcb) {
  289.     debug(F101,"zopeno fcb disp","",fcb->dsp);
  290.     debug(F101,"zopeno fcb type","",fcb->typ);
  291.     debug(F101,"zopeno fcb char","",fcb->cs);
  292.     } else {
  293.     debug(F100,"zopeno fcb is NULL","",0);
  294.     }
  295.     if (n != ZDFILE)
  296.       debug(F111," zopeno",name,n);
  297.     if (chkfn(n) != 0) return(0);
  298.     if ((n == ZCTERM) || (n == ZSTDIO)) {   /* Terminal or standard output */
  299.     fp[ZOFILE] = stdout;
  300.     debug(F101," fp[]=stdout", "", (int) fp[n]);
  301.     zoutcnt = 0;
  302.     zoutptr = zoutbuffer;
  303.     return(1);
  304.     }
  305.     p = "w";                /* Assume write/create mode */
  306.     if (fcb) {                /* If called with an FCB... */
  307.     if (fcb->dsp == XYFZ_A)        /* Does it say Append? */
  308.       p = "a";            /* Yes. */
  309.     }
  310.     fp[n] = fopen(name,p);        /* Open the file */
  311.  
  312.     if (fp[n] == NULL) {
  313.         perror("zopeno can't open");
  314.     } else {
  315.         if (n == ZDFILE) setbuf(fp[n],NULL); /* Debugging file unbuffered */
  316.     }
  317.     zoutcnt = 0;        /* (PWP) reset output buffer */
  318.     zoutptr = zoutbuffer;
  319.     if (n != ZDFILE)
  320.       debug(F101, " fp[n]", "", (int) fp[n]);
  321.     return((fp[n] != NULL) ? 1 : 0);
  322. }
  323.  
  324. /*  Z C L O S E  --  Close the given file.  */
  325.  
  326. /*  Returns 0 if arg out of range, 1 if successful, -1 if close failed.  */
  327. int
  328. zclose(int n) {
  329.     int x, x2;
  330.  
  331.     if (chkfn(n) < 1) return(0);    /* Check range of n */
  332.  
  333.     if ((n == ZOFILE) && (zoutcnt > 0))    /* (PWP) output leftovers */
  334.       x2 = zoutdump();
  335.     else
  336.       x2 = 0;
  337.  
  338.     x = 0;                /* Initialize return code */
  339.     if (fp[ZSYSFN]) {            /* If file is realy a pipe */
  340.         x = zclosf(n);            /* do it specially */
  341.     } else {
  342.         if ((fp[n] != stdout) && (fp[n] != stdin)) x = fclose(fp[n]);
  343.     fp[n] = NULL;
  344.     }
  345.     iflen = -1;                /* Invalidate file length */
  346.     if (x == EOF)            /* if we got a close error */
  347.     return (-1);
  348.     else if (x2 < 0)        /* or an error flushing the last buffer */
  349.     return (-1);        /* then return an error */
  350.     else
  351.     return (1);
  352. }
  353.  
  354. /*  Z C H I N  --  Get a character from the input file.  */
  355.  
  356. /*  Returns -1 if EOF, 0 otherwise with character returned in argument  */
  357. int
  358. zchin(int n, int *c) {
  359.     int a, x;
  360.  
  361.     /* (PWP) Just in case this gets called when it shoudn't */
  362.     if (n == ZIFILE) {
  363.     x = zminchar();
  364.     *c = x;
  365.     return (x);
  366.     }
  367.  
  368.     /* if (chkfn(n) < 1) return(-1); */
  369.     a = getc(fp[n]);
  370.     if (a == EOF) return(-1);
  371.     *c = (CHAR) a & 0377;
  372.     return(0);
  373. }
  374.  
  375. /*  Z S I N L  --  Read a line from a file  */
  376.  
  377. /*
  378.   Writes the line into the address provided by the caller.
  379.   n is the Kermit "channel number".
  380.   Writing terminates when newline is encountered, newline is not copied.
  381.   Writing also terminates upon EOF or if length x is exhausted.
  382.   Returns 0 on success, -1 on EOF or error.
  383. */
  384. int
  385. zsinl(int n, char *s, int x) {
  386.     int z = 0, a;
  387.  
  388.     if (chkfn(n) < 1) {            /* Make sure file is open */
  389.     return(-1);
  390.     }
  391.     while (x--) {
  392.     if (zchin(n,&a) < 0) {        /* Read a character from the file */
  393.         z = -1;
  394.         break;
  395.     }
  396.     if (a == '\n') break;
  397.     *s = a;
  398.     s++;
  399.     }
  400.     *s = '\0';
  401.     return(z);
  402. }
  403.  
  404. /*
  405.  * (PWP) (re)fill the buffered input buffer with data.  All file input
  406.  * should go through this routine, usually by calling the zminchar()
  407.  * macro (in ckcker.h).
  408.  */
  409. int
  410. zinfill(void) {
  411.     zincnt = fread(zinbuffer, sizeof (char), INBUFSIZE, fp[ZIFILE]);
  412.     debug(F101,"zinfill zincnt","",zincnt);
  413.     if (zincnt == 0) return (-1); /* end of file */
  414.     zinptr = zinbuffer;       /* set pointer to beginning, (== &zinbuffer[0]) */
  415.     zincnt--;            /* one less char in buffer */
  416.     return((int)(*zinptr++) & 0377); /* because we return the first */
  417. }
  418.  
  419. /*  Z S O U T  --  Write a string to the given file, buffered.  */
  420. int
  421. zsout(int n, char *s) {
  422.     if (chkfn(n) < 1) return(-1);
  423.     fputs(s,fp[n]);
  424.     return(0);
  425. }
  426.  
  427. /*  Z S O U T L  --  Write string to file, with line terminator, buffered  */
  428. int
  429. zsoutl(int n, char *s) {
  430.     if (chkfn(n) < 1) return(-1);
  431.     fputs(s,fp[n]);
  432.     fputs("\n",fp[n]);
  433.     return(0);
  434. }
  435.  
  436. /*  Z S O U T X  --  Write x characters to file, unbuffered.  */
  437. int
  438. zsoutx(int n, char *s, int x) {
  439.     if (chkfn(n) < 1) return(-1);
  440.     return(write(fileno(fp[n]),s,x));
  441. }
  442.  
  443.  
  444. /*  Z C H O U T  --  Add a character to the given file.  */
  445.  
  446. /*  Should return 0 or greater on success, -1 on failure (e.g. disk full)  */
  447. int
  448. zchout(int n, char c) {
  449.     if (chkfn(n) < 1) return(-1);
  450.     if (n == ZSFILE)
  451.         return(write(fileno(fp[n]),&c,1)); /* Use unbuffered for session log */
  452.     else {                /* Buffered for everything else */
  453.     if (putc(c,fp[n]) == EOF)    /* If true, maybe there was an error */
  454.         return(ferror(fp[n])?-1:0);    /* Check to make sure */
  455.     else                /* Otherwise... */
  456.         return(0);            /* There was no error. */
  457.     }
  458. }
  459.  
  460. /* (PWP) buffered character output routine to speed up file IO */
  461. int
  462. zoutdump(void) {
  463.     int x;
  464.     zoutptr = zoutbuffer;        /* reset buffer pointer in all cases */
  465.     debug(F101,"zoutdump chars","",zoutcnt);
  466.     if (zoutcnt == 0) {            /* nothing to output */
  467.     return(0);
  468.     } else if (zoutcnt < 0) {        /* unexpected negative value */
  469.     zoutcnt = 0;            /* reset output buffer count */
  470.     return(-1);            /* and fail. */
  471.     }
  472.  
  473. /* Frank Prindle suggested that replacing this fwrite() by an fflush() */
  474. /* followed by a write() would improve the efficiency, especially when */
  475. /* writing to stdout.  Subsequent tests showed a 5-fold improvement!   */
  476. /*  if (x = fwrite(zoutbuffer, 1, zoutcnt, fp[ZOFILE])) {              */
  477.  
  478.     fflush(fp[ZOFILE]);
  479.     if (x = write(fileno(fp[ZOFILE]),zoutbuffer,zoutcnt)) {
  480.     debug(F101,"zoutdump fwrite wrote","",x);
  481.     zoutcnt = 0;            /* reset output buffer count */
  482.     return(0);            /* things worked OK */
  483.     } else {
  484.     zoutcnt = 0;            /* reset output buffer count */
  485.     x = ferror(fp[ZOFILE]);        /* get error code */
  486.     debug(F101,"zoutdump fwrite error","",x);
  487.     return(x ? -1 : 0);        /* return failure if error */
  488.     }
  489. }
  490.  
  491. /*  C H K F N  --  Internal function to verify file number is ok  */
  492.  
  493. /*
  494.  Returns:
  495.   -1: File number n is out of range
  496.    0: n is in range, but file is not open
  497.    1: n in range and file is open
  498. */
  499. int
  500. chkfn(int n) {
  501.  
  502.     /* if (n != ZDFILE) debug(F101,"chkfn","",n); */
  503.     if (n < 0 || n >= ZNFILS) {
  504.     if (n != ZDFILE) debug(F101,"chkfn out of range","",n);
  505.     return(-1);
  506.     } else {
  507.     /* if (n != ZDFILE) debug(F101,"chkfn fp[n]","",fp[n]); */
  508.     return((fp[n] == NULL) ? 0 : 1);
  509.     }
  510.  
  511. }
  512.  
  513. /*  Z C H K I  --  Check if input file exists and is readable  */
  514.  
  515. /*
  516.   Returns:
  517.    >= 0 if the file can be read (returns the size).
  518.      -1 if file doesn't exist or can't be accessed,
  519.      -2 if file exists but is not readable (e.g. a directory file).
  520.      -3 if file exists but protected against read access.
  521. */
  522. long
  523. zchki(char *name) {
  524.     long size, readstat();
  525.  
  526.     size = readstat(name);
  527.     debug(F111,"zchki file size",name,(int)size);
  528.     iflen = size;
  529.     strcpy(nambuf, name);        /* Remember file name globally. */
  530.     return(size);
  531. }
  532.  
  533. /*  Z C H K O  --  Check if output file can be created  */
  534.  
  535. /*
  536.  Returns -1 if write permission for the file would be denied, 0 otherwise.
  537. */
  538. int
  539. zchko(char *name) {
  540.     int rc = writestat(name);
  541.  
  542. #ifdef DEBUG
  543.     if (rc < 0)
  544.     debug(F111,"zchko access failed:",name,rc);
  545.     else
  546.     debug(F111,"zchko access ok:",name,rc);
  547. #endif
  548.     return(rc);
  549. }
  550.  
  551. /*  Z D E L E T  --  Delete the named file.  */
  552. int
  553. zdelet(char *name) {
  554.     return(unlink(name));
  555. }
  556.  
  557.  
  558. /*  Z R T O L  --  Convert remote filename into local form  */
  559.  
  560. /*  For AMIGA, this means changing uppercase letters to lowercase.  */
  561.  
  562. void
  563. zrtol(char *name, char *name2) {
  564.     for ( ; *name != '\0'; name++) {
  565.         *name2++ = isupper(*name) ? tolower(*name) : *name;
  566.     }
  567.     *name2 = '\0';
  568.     debug(F110,"zrtol:",name2,0);
  569. }
  570.  
  571. /*  Z S T R I P  --  Strip device & directory name from file specification */
  572.  
  573. /*  Strip pathname from filename "name", return pointer to result in name2 */
  574.  
  575. static char work[100];    /* buffer for use by zstrip and zltor */
  576.  
  577. void
  578. zstrip(char *name, char **name2) {
  579.     char *cp, *pp;
  580.     debug(F110,"zstrip before",name,0);
  581.     pp = work;
  582.     if ((cp = strrchr(name, ':')) == NULL)
  583.         cp = name;
  584.     else
  585.         ++cp;
  586.     for (; *cp != '\0'; cp++) {
  587.         if (*cp == '/')
  588.       pp = work;
  589.     else
  590.       *pp++ = *cp;
  591.     }
  592.     *pp = '\0';                /* Terminate the string */
  593.     *name2 = work;
  594.     debug(F110,"zstrip after",*name2,0);
  595. }
  596.  
  597. /*  Z L T O R  --  Local TO Remote */
  598.  
  599. /*  Convert filename from local format to common (remote) form.  */
  600.  
  601. void
  602. zltor(char *name, char *name2) {
  603.     char *cp, *pp;
  604.     int dc = 0;
  605.  
  606.     debug(F110,"zltor",name,0);
  607.     pp = work;
  608.     if ((cp = strrchr(name, ':')) == NULL)
  609.         cp = name;
  610.     else
  611.         ++cp;
  612.  
  613.     for (; *cp != '\0'; cp++) {    /* strip path name */
  614.         if (*cp == '/') {
  615.         dc = 0;
  616.         pp = work;
  617.     }
  618.     else if (islower(*cp)) *pp++ = toupper(*cp); /* Uppercase letters */
  619.     else if (*cp == '~') *pp++ = 'X';    /* Change tilde to 'X' */
  620.     else if (*cp == '#') *pp++ = 'X';    /* Change number sign to 'X' */
  621.     else if ((*cp == '.') && (++dc > 1)) *pp++ = 'X'; /* & extra dots */
  622.     else *pp++ = *cp;
  623.     }
  624.     *pp = '\0';                /* Tie it off. */
  625.     cp = name2;                /* If nothing before dot, */
  626.     if (*work == '.') *cp++ = 'X';    /* insert 'X' */
  627.     strcpy(cp,work);
  628.     debug(F110," name2",name2,0);
  629. }
  630.  
  631. /*  Z H O M E  --  Return pointer to user's home directory  */
  632.  
  633. /* we return "s:", which is where startup scripts are found */
  634. char *
  635. zhome(void) {
  636.     return("s:");        /* very approximately */
  637. }
  638.  
  639. /*  Z C H D I R  --  Change directory  */
  640. int
  641. zchdir(char *dirnam) {
  642.     if (chdir(dirnam) != 0)        /* failed */
  643.         return 0;
  644.     if (v37)                /* This only if V37 or more */
  645.         if (!SetCurrentDirName(dirnam))
  646.             return 0;
  647.     return 1;
  648. }
  649.  
  650. /*  Z G T D I R  --  Return pointer to user's current directory  */
  651.  
  652. char *
  653. zgtdir(void) {
  654.  
  655. #ifdef MAXPATHLEN
  656. #define CWDBL MAXPATHLEN
  657. #else
  658. #define CWDBL 100
  659. #endif
  660.  
  661.     static char cwdbuf[CWDBL+1];
  662.     char *buf, *getcwd();
  663.     buf = cwdbuf;
  664.     return(getcwd(buf, CWDBL));
  665. }
  666.  
  667. /*  Z X C M D -- Run a system command so its output can be read like a file */
  668. int
  669. zxcmd(int filnum, char *comand) {
  670.     FILE *pipeopen();
  671.     int out;
  672.  
  673.     if (chkfn(filnum) < 0) return(-1);    /* Need a valid Kermit file number. */
  674.     if (filnum == ZSTDIO || filnum == ZCTERM) /* But not one of these. */
  675.       return(0);
  676.  
  677.     out = (filnum == ZIFILE || filnum == ZRFILE) ? 0 : 1 ;
  678.  
  679. /* Output to a command */
  680.  
  681.     if (out) {                /* Need popen() to do this. */
  682.         return -1;            /* Not yet supported. */
  683.     }
  684.  
  685. /* Input from a command */
  686.     else {
  687.     if ((fp[filnum] = pipeopen(comand)) == NULL) return -1;
  688.     fp[ZSYSFN] = fp[filnum];    /* Remember */
  689.     zincnt = 0;            /* (PWP) reset input buffer */
  690.     zinptr = zinbuffer;
  691.     }
  692.     return 1;
  693. }
  694.  
  695. /*  Z C L O S F  - wait for the child fork to terminate and close the pipe. */
  696. int
  697. zclosf(int filnum) {
  698.     pipeclose(fp[filnum]);
  699.     fp[filnum] = fp[ZSYSFN] = NULL;
  700.     return(1);
  701. }
  702.  
  703. /*  Z X P A N D  --  Expand a wildcard string into an array of strings  */
  704. /*
  705.   Returns the number of files that match fn1, with data structures set up
  706.   so that first file (if any) will be returned by the next znext() call.
  707. */
  708. int
  709. zxpand(char *fn) {
  710.     fcount = fgen(fn,mtchs,MAXWLD);    /* Look up the file. */
  711.     if (fcount > 0) {
  712.     mtchptr = mtchs;        /* Save pointer for next. */
  713.     }
  714.     debug(F111,"zxpand",mtchs[0],fcount);
  715.     return(fcount);
  716. }
  717.  
  718.  
  719. /*  Z N E X T  --  Get name of next file from list created by zxpand(). */
  720. /*
  721.  Returns >0 if there's another file, with its name copied into the arg string,
  722.  or 0 if no more files in list.
  723. */
  724. int
  725. znext(char *fn) {
  726.     if (fcount-- > 0) strcpy(fn,*mtchptr++);
  727.     else *fn = '\0';
  728.     debug(F111,"znext",fn,fcount+1);
  729.     return(fcount+1);
  730. }
  731.  
  732. /*  Z C H K S P A -- Check to see if there is enough space for the file. */
  733.  
  734. /*
  735.  * Uses Manx-supplied dospacket() routine. (Source supplied for SAS/C
  736.  *                                            by Larry Rosenman)
  737.  */
  738. int
  739. zchkspa(char *fn, long len) {
  740.     struct MsgPort *MyPort;
  741.     struct InfoData *MyInfo;
  742.     long space;
  743.  
  744.     if ((MyPort = (struct MsgPort *)DeviceProc(fn)) == NULL)
  745.     return -1;
  746.     if ((MyInfo = AllocMem(sizeof(struct InfoData), MEMF_PUBLIC)) == NULL)
  747.     return -1;
  748.     if (dos_packet(MyPort, ACTION_DISK_INFO, ((BPTR) MyInfo) >> 2,
  749.                    0L, 0L, 0L, 0L, 0L) != 0) {
  750.     if (MyInfo->id_UnitNumber == -1)    /* Imperfect check for RAM: */
  751.         space = len + 1;            /* Always enough space */
  752.     else
  753.         space = (MyInfo->id_NumBlocks - MyInfo->id_NumBlocksUsed)*
  754.                     MyInfo->id_BytesPerBlock;
  755.     } else
  756.     space = -1;        /* To mark error return after FreeMem(). */
  757.     FreeMem(MyInfo, sizeof(struct InfoData));
  758.     if (space <= 0)
  759.     return -1;
  760.     else if (len < space)
  761.     return 1;
  762.     else
  763.     return 0;
  764. }
  765.  
  766. /*  Z N E W N  --  Make a new name for the given file  */
  767.  
  768. void
  769. znewn(char *fn,char **s) {
  770.     static char buf[100];
  771.     char *bp;
  772.     int len = 0, d;
  773. #ifdef MAXNAMLEN
  774.     int maxlen = MAXNAMLEN;
  775. #else
  776.     int maxlen = 14;
  777. #endif
  778.  
  779.     bp = buf;
  780.     while (*fn) {            /* Copy name into buf */
  781.     *bp++ = *fn++;
  782.     len++;
  783.     }
  784.     if (len > maxlen-3) bp -= 3;    /* Don't let it get too long */
  785.  
  786.     /*
  787.      * On the Amiga, it takes much less time to determine
  788.      * if a given file exists than to read all the file names in
  789.      * a directory (or even just names with a certain prefix).
  790.      */
  791.     d = 0;
  792.     do {
  793.     sprintf(bp, "~%d", ++d);
  794.     } while (zchki(buf) != -1 && d < 100);
  795.  
  796.     *s = buf;
  797. }
  798.  
  799. /*  Z S A T T R */
  800. /*
  801.  Fills in a Kermit file attribute structure for the file which is to be sent.
  802.  Returns 0 on success with the structure filled in, or -1 on failure.
  803.  If any string member is null, then it should be ignored.
  804.  If any numeric member is -1, then it should be ignored.
  805. */
  806. int
  807. zsattr(struct zattr *xx) {
  808.     long k;
  809.     char *zfcdat();
  810.  
  811.     k = iflen % 1024L;            /* File length in K */
  812.     if (k != 0L) k = 1L;
  813.     xx->lengthk = (iflen / 1024L) + k;
  814.     xx->type.len = 0;            /* File type can't be filled in here */
  815.     xx->type.val = "";
  816.     if (*nambuf) {
  817.     xx->date.val = zfcdat(nambuf);    /* File creation date */
  818.     xx->date.len = strlen(xx->date.val);
  819.     } else {
  820.     xx->date.len = 0;
  821.     xx->date.val = "";
  822.     }
  823.     xx->creator.len = 0;        /* File creator */
  824.     xx->creator.val = "";
  825.     xx->account.len = 0;        /* File account */
  826.     xx->account.val = "";
  827.     xx->area.len = 0;            /* File area */
  828.     xx->area.val = "";
  829.     xx->password.len = 0;            /* Area password */
  830.     xx->password.val = "";
  831.     xx->blksize = -1L;            /* File blocksize */
  832.     xx->xaccess.len = 0;        /* File access */
  833.     xx->xaccess.val = "";
  834.     xx->encoding.len = 0;        /* Transfer syntax */
  835.     xx->encoding.val = 0;
  836.     xx->disp.len = 0;            /* Disposition upon arrival */
  837.     xx->disp.val = "";
  838.     xx->lprotect.len = 0;        /* Local protection */
  839.     xx->lprotect.val = "";
  840.     xx->gprotect.len = 0;        /* Generic protection */
  841.     xx->gprotect.val = "";
  842.     xx->systemid.len = 2;        /* System ID length */
  843.     xx->systemid.val = "L3";        /* Amiga system ID code */
  844.     xx->recfm.len = 0;            /* Record format */
  845.     xx->recfm.val = "";
  846.     xx->sysparam.len = 0;        /* System-dependent parameters */
  847.     xx->sysparam.val = "";
  848.     xx->length = iflen;            /* Length */
  849.     return(0);
  850. }
  851.  
  852. /* Z F C D A T -- Return a string containing the time stamp for a file */
  853.  
  854. char *
  855. zfcdat(char *name) {
  856.  
  857.     struct stat buffer;
  858.     struct tm *time_stamp, *localtime();
  859.     time_t filetime;
  860.     static char datbuf[20];
  861.  
  862.     datbuf[0] = '\0';
  863.     if(stat(name,&buffer) != 0) {
  864.     debug(F110,"zcfdat stat failed",name,0);
  865.     return("");
  866.     }
  867.     filetime = StatToTime(buffer.st_mtime);
  868.     time_stamp = localtime(&filetime);
  869.     if (time_stamp->tm_year < 1900) time_stamp->tm_year += 1900;
  870.     sprintf(datbuf,"%-4.4d%02.2d%02.2d %002.2d:%002.2d:%002.2d",
  871.         time_stamp->tm_year,
  872.         time_stamp->tm_mon + 1,
  873.         time_stamp->tm_mday,
  874.         time_stamp->tm_hour,
  875.         time_stamp->tm_min,
  876.         time_stamp->tm_sec);
  877.     debug(F111,"zcfdat",datbuf,strlen(datbuf));
  878.     return(datbuf);
  879. }
  880.  
  881. /* Z S T I M E  --  Set creation date for incoming file */
  882. /*
  883.  Call with:
  884.  f  = pointer to name of existing file.
  885.  yy = pointer to a Kermit file attribute structure in which yy->date.val
  886.       is a date of the form yyyymmdd hh:mm:ss, e.g. 19900208 13:00:00.
  887.  x  = is a function code: 0 means to set the file's creation date as given.
  888.       1 means compare the given date with the file creation date.
  889.  Returns:
  890.  -1 on any kind of error.
  891.   0 if x is 0 and the file date was set successfully.
  892.   0 if x is 1 and date from attribute structure <= file creation date.
  893.   1 if x is 1 and date from attribute structure > file creation date.
  894. */
  895. int
  896. zstime(char *f, struct zattr *yy, int x) {
  897.  
  898. /*
  899.  * This code takes advantage of the ANSI time functions.  Once UNIX has
  900.  * an ANSI compiler, maybe UNIX can use this one instead...
  901.  */
  902.  
  903.     struct tm InTime;
  904.     time_t CompareTime;
  905.     struct stat MyStat;
  906.  
  907.     int isleapyear, i;
  908.     static int monthdays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
  909.  
  910.     debug(F110,"zstime",f,0);
  911.  
  912.     if (sscanf(yy->date.val, "%4d%2d%2d %2d:%2d:%2d", &InTime.tm_year,
  913.            &InTime.tm_mon, &InTime.tm_mday, &InTime.tm_hour,
  914.            &InTime.tm_min, &InTime.tm_sec) != 6) {
  915.     debug(F111, "Bad creation date ", yy->date.val, yy->date.len);
  916.     return -1;
  917.     }
  918.     InTime.tm_mon--;        /* a struct tm contains months with 0 = Jan */
  919.  
  920.     isleapyear = (( InTime.tm_year % 4 == 0 && InTime.tm_year % 100 !=0) ||
  921.                   InTime.tm_year % 400 == 0);
  922.     InTime.tm_year -= 1900;
  923. /*
  924.  * Find number of days since start-of-year.
  925.  */
  926.     InTime.tm_yday = (isleapyear ? 0 : 1);
  927.     for (i = 0; i <= InTime.tm_mon; i++)
  928. /*    InTime.tm_yday += monthdays[0]; */ /*ler*/
  929.     InTime.tm_yday += monthdays[i];
  930.     InTime.tm_yday += InTime.tm_mday;
  931.     InTime.tm_isdst = 0;        /* No daylight savings on Amiga. */
  932. /*
  933.  * We don't set day-of-week in this code, and simply hope mktime ignores it.
  934.  */
  935.     CompareTime = mktime(&InTime);
  936.     if (x == 1) {            /* Compare time with file */
  937.     if (stat(f, &MyStat) < 0) {
  938.         debug(F110,"zstime: stat failed", f, 0);
  939.         return -1;
  940.     }
  941.     if (StatToTime(MyStat.st_mtime) <= CompareTime)
  942.         return 0;
  943.     else
  944.         return 1;
  945.     } else if (x == 0) {        /* Set file to time */
  946.     struct DateStamp NewTime;
  947.  
  948.     TimeToDateStamp(CompareTime, &NewTime);
  949.     return(touch(f, &NewTime));
  950.     }
  951.     return -1;                /* Illegal value for x */
  952. }
  953. /*
  954.  * Set modification date of file fn to NewTime.
  955.  */
  956. static int
  957. touch(char *fn, struct DateStamp *NewTime) {
  958.     struct MsgPort *task;
  959.     BPTR lock, plock;
  960.     UBYTE *pointer;
  961.  
  962.     if(!(pointer = (UBYTE *)AllocMem(256L,MEMF_PUBLIC)))
  963.     return -1;
  964.     if(!(task=(struct MsgPort *)DeviceProc(fn))) {
  965.     FreeMem((void *) pointer, 256L);
  966.     return;
  967.     }
  968.     if(!(lock = Lock(fn,SHARED_LOCK))) {
  969.     FreeMem((void *) pointer, 256L);
  970.     return -1;
  971.     }
  972.     plock = ParentDir(lock);
  973.     UnLock(lock);
  974.  
  975.     strcpy((char *)(pointer + 1),fn);
  976.     *pointer = strlen(fn);
  977.  
  978.     dos_packet(task, ACTION_SET_DATE, NULL, plock, (ULONG) &pointer[0] >> 2,
  979.     (ULONG) NewTime, 0L, 0L, 0L);
  980.  
  981.     UnLock(plock);
  982.     FreeMem((void *) pointer, 256L);
  983.     return 0;
  984. }
  985. /*
  986.  * Dummy functions for the Amiga.  Sending mail cannot be done;  I haven't
  987.  * decided how to handle print requests yet.
  988.  */
  989. int
  990. zmail(char *p, char *f) {        /* Send file f as mail to address p */
  991.     return(0);
  992. }
  993.  
  994. int
  995. zprint(char *p, char *f) {        /* Print file f with flags p */
  996.     return(0);
  997. }
  998.  
  999. int
  1000. zrename(char *old, char *new) {
  1001.     return(rename(old, new) == 0 ? 0 : -1);
  1002. }
  1003.  
  1004. /* Z S H C M D -- Issue shell command and redirect output, if necessary. */
  1005.  
  1006. /*
  1007.  * This function is to pass the command contained in the string s to the
  1008.  * local command parser.  If the command does not begin with the character
  1009.  * ">", then give the command to the system and display its results on the
  1010.  * screen.  If the command does not begin with ">" and local != 0, then send
  1011.  * the results of the command out the currently open communications device.
  1012.  *
  1013.  * In this version, we simply punt.
  1014.  */
  1015. int
  1016. zshcmd(char *s) {
  1017.     if (*s == '>') s++;
  1018.     return(system(s));
  1019. }
  1020.  
  1021. /* Directory Functions for Unix, written by Jeff Damens, CUCCA, 1984. */
  1022.  
  1023. /*
  1024.  * The path structure is used to represent the name to match.
  1025.  * Each slash-separated segment of the name is kept in one
  1026.  * such structure, and they are linked together, to make
  1027.  * traversing the name easier.
  1028.  */
  1029.  
  1030. struct path {
  1031.               char npart[MAXNAMLEN];    /* name part of path segment */
  1032.               struct path *fwd;        /* forward ptr */
  1033.             };
  1034.  
  1035. #define SSPACE 4000            /* size of string-generating buffer */
  1036.  
  1037. static char sspace[SSPACE];             /* buffer to generate names in */
  1038. static char *freeptr,**resptr;             /* copies of caller's arguments */
  1039. static int remlen;                      /* remaining length in caller's array*/
  1040. static int numfnd;                      /* number of matches found */
  1041.  
  1042. /*
  1043.  * splitpath:
  1044.  *  takes a string and splits the slash-separated portions into
  1045.  *  a list of path structures.  Returns the head of the list.  The
  1046.  *  structures are allocated by malloc, so they must be freed.
  1047.  *  Splitpath is used internally by the filename generator.
  1048.  *
  1049.  * Input: A string.
  1050.  * Returns: A linked list of the slash-separated segments of the input.
  1051.  */
  1052.  
  1053. struct path *
  1054. splitpath(char *p) {
  1055.  struct path *head,*cur,*prv;
  1056.  int i;
  1057.  head = prv = NULL;
  1058.  if (*p == '/') p++;            /* skip leading slash */
  1059.  while (*p != '\0')
  1060.  {
  1061.    cur = (struct path *) malloc(sizeof (struct path));
  1062.    debug(F101,"splitpath malloc","",(cur == NULL ? 0 : 1));
  1063.    if (cur == NULL) fatal("malloc fails in splitpath()");
  1064.    cur -> fwd = NULL;
  1065.    if (head == NULL) head = cur;
  1066.    else prv -> fwd = cur;       /* link into chain */
  1067.    prv = cur;
  1068.    for (i=0; i < MAXNAMLEN && *p != '/' && *p != '\0'; i++)
  1069.      cur -> npart[i] = *p++;
  1070.    cur -> npart[i] = '\0';      /* end this segment */
  1071.    if (i >= MAXNAMLEN) while (*p != '/' && *p != '\0') p++;
  1072.    if (*p == '/') p++;
  1073.  }
  1074.  return(head);
  1075. }
  1076.  
  1077. /*
  1078.  * fgen:
  1079.  *  This is the actual name generator.  It is passed a string,
  1080.  *  possibly containing wildcards, and an array of character pointers.
  1081.  *  It finds all the matching filenames and stores them into the array.
  1082.  *  The returned strings are allocated from a static buffer local to
  1083.  *  this module (so the caller doesn't have to worry about deallocating
  1084.  *  them); this means that successive calls to fgen will wipe out
  1085.  *  the results of previous calls.  This isn't a problem here
  1086.  *  because we process one wildcard string at a time.
  1087.  *
  1088.  * Input: a wildcard string, an array to write names to, the
  1089.  *        length of the array.
  1090.  * Returns: the number of matches.  The array is filled with filenames
  1091.  *          that matched the pattern.  If there wasn't enough room in the
  1092.  *        array, -1 is returned.
  1093.  * By: Jeff Damens, CUCCA, 1984.
  1094.  */
  1095. int
  1096. fgen(char *pat, char *resarry[], int len) {
  1097.  struct path *head;
  1098.  char scratch[100],*sptr;
  1099.  char *tail;
  1100.  void traverse(struct path *pl, char *sofar, char *endcur);
  1101.  
  1102.  if ((tail = strrchr(pat, ':')) == NULL) /* locate unit name */
  1103.   tail = pat;                /* no unit name */
  1104.  else
  1105.   ++tail;                /* eat ':' */
  1106.  while (*tail == '/')            /* eat parent path slashes */
  1107.   ++tail;
  1108.  sptr = scratch;            /* init buffer correctly */
  1109.  while (pat < tail)
  1110.   *sptr++ = *pat++;
  1111.  head = splitpath(pat);
  1112.  numfnd = 0;                            /* none found yet */
  1113.  freeptr = sspace;            /* this is where matches are copied */
  1114.  resptr = resarry;            /* static copies of these so*/
  1115.  remlen = len;                /* recursive calls can alter them */
  1116.  traverse(head,scratch,sptr);        /* go walk the directory tree */
  1117.  while (head != NULL) {
  1118.    struct path *next = head -> fwd;
  1119.    free(head);                /* return the path segments */
  1120.    head = next;
  1121.  }
  1122.  return(numfnd);            /* and return the number of matches */
  1123. }
  1124.  
  1125. /* traverse:
  1126.  *  Walks the directory tree looking for matches to its arguments.
  1127.  *  The algorithm is, briefly:
  1128.  *   If the current pattern segment contains no wildcards, that
  1129.  *   segment is added to what we already have.  If the name so far
  1130.  *   exists, we call ourselves recursively with the next segment
  1131.  *   in the pattern string; otherwise, we just return.
  1132.  *
  1133.  *   If the current pattern segment contains wildcards, we open the name
  1134.  *   we've accumulated so far (assuming it is really a directory), then read
  1135.  *   each filename in it, and, if it matches the wildcard pattern segment, add
  1136.  *   that filename to what we have so far and call ourselves recursively on the
  1137.  *   next segment.
  1138.  *
  1139.  *   Finally, when no more pattern segments remain, we add what's accumulated
  1140.  *   so far to the result array and increment the number of matches.
  1141.  *
  1142.  * Input: a pattern path list (as generated by splitpath), a string
  1143.  *      pointer that points to what we've traversed so far (this
  1144.  *      can be initialized to "/" to start the search at the root
  1145.  *      directory, or to "./" to start the search at the current
  1146.  *      directory), and a string pointer to the end of the string
  1147.  *      in the previous argument.
  1148.  * Returns: nothing.
  1149.  */
  1150. void
  1151. traverse(struct path *pl, char *sofar, char *endcur) {
  1152.  struct DirHandle *fd;
  1153.  char *fname;
  1154.  
  1155.  if (pl == NULL)
  1156.  {
  1157.   *--endcur = '\0';                    /* end string, overwrite trailing / */
  1158.   addresult(sofar);
  1159.   return;
  1160.  }
  1161.  if (!iswild(pl -> npart))
  1162.  {
  1163.   strcpy(endcur,pl -> npart);
  1164.   endcur += strlen(pl -> npart);
  1165.   *endcur = '\0';                         /* end current string */
  1166.   if (existobj(sofar))            /* if current piece exists */
  1167.   {
  1168.       *endcur++ = '/';            /* add slash to end */
  1169.       *endcur = '\0';            /* and end the string */
  1170.       traverse(pl -> fwd,sofar,endcur);
  1171.   }
  1172.   return;
  1173.  }
  1174. /* cont'd... */
  1175.  
  1176. /*...traverse, cont'd */
  1177.  
  1178. /* segment contains wildcards, have to search directory */
  1179.  *endcur = '\0';                            /* end current string */
  1180.  if ((fd = opendir(sofar)) == NULL) return;      /* can't open, forget it */
  1181.  while (fname = readdir(fd))
  1182. {
  1183.   if (match(pl -> npart,fname)) {
  1184.     char *eos;
  1185.     strcpy(endcur,fname);
  1186.     eos = endcur + strlen(fname);
  1187.     *eos = '/';                    /* end this segment */
  1188.     traverse(pl -> fwd,sofar,eos+1);
  1189.   }
  1190. }
  1191.  closedir(fd);
  1192. }
  1193.  
  1194. /*
  1195.  * addresult:
  1196.  *  Adds a result string to the result array.  Increments the number
  1197.  *  of matches found, copies the found string into our string
  1198.  *  buffer, and puts a pointer to the buffer into the caller's result
  1199.  *  array.  Our free buffer pointer is updated.  If there is no
  1200.  *  more room in the caller's array, the number of matches is set to -1.
  1201.  * Input: a result string.
  1202.  * Returns: nothing.
  1203.  */
  1204. int
  1205. addresult(char *str) {
  1206.  int l;
  1207.  if (--remlen < 0) {
  1208.   numfnd = -1;
  1209.   return;
  1210.  }
  1211.  l = strlen(str) + 1;            /* size this will take up */
  1212.  if ((freeptr + l) > &sspace[SSPACE]) {
  1213.     numfnd = -1;            /* do not record if not enough space */
  1214.     return;
  1215.   }
  1216.  strcpy(freeptr,str);
  1217.  *resptr++ = freeptr;
  1218.  freeptr += l;
  1219.  numfnd++;
  1220. }
  1221.  
  1222. int
  1223. iswild(char *str) {
  1224.  char c;
  1225.  while ((c = *str++) != '\0')
  1226.    if (c == '*' || c == '?') return(1);
  1227.  return(0);
  1228. }
  1229.  
  1230. #ifdef OLDMATCH
  1231. /*
  1232.  * match:
  1233.  *  pattern matcher.  Takes a string and a pattern possibly containing
  1234.  *  the wildcard characters '*' and '?'.  Returns true if the pattern
  1235.  *  matches the string, false otherwise.
  1236.  * by: Jeff Damens, CUCCA
  1237.  *
  1238.  * Input: a string and a wildcard pattern.
  1239.  * Returns: 1 if match, 0 if no match.
  1240.  */
  1241. int
  1242. match(char *pattern, char *string) {
  1243.     char *psave,*ssave;            /* back up pointers for failure */
  1244.     psave = ssave = NULL;
  1245.     while (1) {
  1246.     for (;
  1247.          tolower(*pattern) == tolower(*string);
  1248.          pattern++,string++)  /* skip first */
  1249.         if (*string == '\0') return(1);    /* end of strings, succeed */
  1250.     if (*string != '\0' && *pattern == '?') {
  1251.         pattern++;            /* '?', let it match */
  1252.         string++;
  1253.     } else if (*pattern == '*') {    /* '*' ... */
  1254.         psave = ++pattern;        /* remember where we saw it */
  1255.         ssave = string;        /* let it match 0 chars */
  1256.     } else if (ssave != NULL && *ssave != '\0') {    /* if not at end  */
  1257.                       /* ...have seen a star */
  1258.         string = ++ssave;        /* skip 1 char from string */
  1259.         pattern = psave;        /* and back up pattern */
  1260.     } else return(0);        /* otherwise just fail */
  1261.     }
  1262. }
  1263. #else
  1264. /*
  1265.  * match -- match wildcard pattern to string
  1266.  *    allows multiple '*'s and works without backtracking
  1267.  *    upper and lower case considered equivalent
  1268.  *    written by Jack Rouse
  1269.  *    working without backtracking is cute, but is this usually going
  1270.  *       to be the most efficient method?
  1271.  */
  1272. int
  1273. match(char *pattern, char *target) {
  1274.     int link[MAXNAMLEN];        /* list of matches to try in pattern */
  1275.     register int first, last;    /* first and last items in list */
  1276.     register int here, next;    /* current and next list items */
  1277.     char lowch;            /* current target character */
  1278.  
  1279.     /* start out trying to match at first position */
  1280.     first = last = 0;
  1281.     link[0] = -1;
  1282.  
  1283.     /* go through the target */
  1284.     for (; *target; ++target)
  1285.     {
  1286.         /* get lowercase target character */
  1287.         lowch = tolower(*target);
  1288.  
  1289.         /* go through all positions this round and build next round */
  1290.         last = next = -1;
  1291.         for (here = first; here >= 0; here = next)
  1292.         {
  1293.             next = link[here];
  1294.             switch (pattern[here])
  1295.             {
  1296.             case '*':
  1297.                 /* try match at here+1 this round */
  1298.                 /*!!!check needed only if "**" allowed? */
  1299.                 if (next != here + 1)
  1300.                 {
  1301.                     link[here + 1] = next;
  1302.                     next = here + 1;
  1303.                 }
  1304.                 /* retry match at here next round */
  1305.                 break;
  1306.             default:
  1307.                 if (tolower(pattern[here]) != lowch)
  1308.                     continue;
  1309.                 /* matched, fall through */
  1310.             case '?':
  1311.                 /* try match at here+1 next round */
  1312.                 ++here;
  1313.                 break;
  1314.             }
  1315.             /* try match at here value next round */
  1316.             if (last < 0)
  1317.                 first = here;
  1318.             else
  1319.                 link[last] = here;
  1320.             last = here;
  1321.         }
  1322.         /* if no positions left, match failed */
  1323.         if (last == -1) return(0);
  1324.         /* terminate list */
  1325.         link[last] = -1;
  1326.     }
  1327.  
  1328.     /* at end of target, skip empty matches */
  1329.     while (pattern[last] == '*')
  1330.         ++last;
  1331.  
  1332.     return(pattern[last] == '\0');
  1333. }
  1334. #endif
  1335.  
  1336. #ifndef NORESEND
  1337. int
  1338. zfseek(long pos)
  1339. /* zfseek */ {
  1340.     debug(F101,"zfseek","",pos);
  1341.     return(fseek(fp[ZIFILE], pos, 0));
  1342. }
  1343. #endif /* NORESEND */
  1344.  
  1345. int
  1346. isdir(char *filbuf) {
  1347.     BPTR lock;
  1348.     struct FileInfoBlock *fib;
  1349.     int retval = 0;
  1350.  
  1351.     lock = Lock(filbuf, ACCESS_READ);
  1352.     if (lock != NULL) {
  1353.        fib = (struct FileInfoBlock *) AllocDosObject(DOS_FIB, 0);
  1354.        if (Examine(lock, fib) != 0) {
  1355.            if (fib->fib_DirEntryType > 0) {
  1356.                retval = 1;
  1357.        }
  1358.  
  1359.        }
  1360.        FreeDosObject(DOS_FIB, fib);
  1361.        UnLock(lock);
  1362.     }
  1363.     return retval;
  1364. }
  1365.