home *** CD-ROM | disk | FTP | other *** search
/ ftp.ncftp.com / ftp.ncftp.com.zip / ftp.ncftp.com / ncftp / ncftp-1.9.5.tar.gz / ncftp-1.9.5.tar / ncftp-1.9.5 / util.c < prev    next >
C/C++ Source or Header  |  1995-10-01  |  19KB  |  923 lines

  1. /* Util.c */
  2.  
  3. /*  $RCSfile: util.c,v $
  4.  *  $Revision: 14020.13 $
  5.  *  $Date: 93/05/23 09:38:13 $
  6.  */
  7.  
  8. #include "sys.h"
  9.  
  10. #include <errno.h>
  11. #include <ctype.h>
  12. #include <pwd.h>
  13.  
  14. #ifndef NO_VARARGS
  15. #    ifdef NO_STDARGH
  16. #        include <varargs.h>
  17. #    else
  18. #        include <stdarg.h>
  19. #    endif
  20. #endif
  21.  
  22. #ifdef READLINE
  23. #    include <readline/readline.h>
  24. #endif /* READLINE */
  25.  
  26. #ifdef GETLINE
  27. #    include <getline.h>
  28. #endif
  29.  
  30. #include "util.h"
  31. #include "cmds.h"
  32. #include "main.h"
  33. #include "ftp.h"
  34. #include "ftprc.h"
  35. #include "defaults.h"
  36. #include "copyright.h"
  37.  
  38. /* Util.c globals */
  39. int                    Opterr = 1;            /* if error message should be printed */
  40. int                    Optind = 1;            /* index into parent argv vector */
  41. int                    Optopt;                /* character checked for validity */
  42. char                *Optarg;            /* argument associated with option */
  43. char                *Optplace = EMSG;    /* saved position in an arg */
  44.  
  45. /* Util.c externs */
  46. extern int            toatty, fromatty;
  47. extern int            verbose, doingInitMacro;
  48. extern string        prompt2;
  49. extern char            *line, *margv[];
  50. extern int            margc;
  51. extern int            debug, mprompt, activemcmd;
  52. extern string        progname;
  53. extern struct cmd    cmdtab[];
  54. extern struct userinfo uinfo;
  55.  
  56. #ifndef NO_VARARGS
  57. /*VARARGS*/
  58. #ifdef NO_STDARGH
  59. void dbprintf(va_alist)
  60.     va_dcl
  61. #else
  62. void dbprintf(char *fmt0, ...)
  63. #endif
  64. {
  65.     va_list ap;
  66.     char *fmt;
  67.  
  68. #ifdef NO_STDARGH
  69.     va_start(ap);
  70.     fmt = va_arg(ap, char *);
  71. #else
  72.     va_start(ap, fmt0);
  73.     fmt = fmt0;
  74. #endif
  75.  
  76.     if (debug) {
  77.         (void) fprintf(DB_STREAM, "#DB# ");
  78.         (void) vfprintf(DB_STREAM, fmt, ap);
  79.         (void) fflush(DB_STREAM);
  80.     }
  81.     va_end(ap);
  82. }    /* dbprintf */
  83.  
  84. #endif    /* have varargs */
  85.  
  86.  
  87.  
  88.  
  89. /*
  90.  * Concatenate src on the end of dst.  The resulting string will have at most
  91.  * n-1 characters, not counting the NUL terminator which is always appended
  92.  * unlike strncat.  The other big difference is that strncpy uses n as the
  93.  * max number of characters _appended_, while this routine uses n to limit
  94.  * the overall length of dst.
  95.  */
  96. char *_Strncat(char *dst, char *src, register size_t n)
  97. {
  98.     register size_t i;
  99.     register char *d, *s;
  100.  
  101.     if (n != 0 && ((i = strlen(dst)) < (n - 1))) {
  102.         d = dst + i;
  103.         s = src;
  104.         /* If they specified a maximum of n characters, use n - 1 chars to
  105.          * hold the copy, and the last character in the array as a NUL.
  106.          * This is the difference between the regular strncpy routine.
  107.          * strncpy doesn't guarantee that your new string will have a
  108.          * NUL terminator, but this routine does.
  109.          */
  110.         for (++i; i<n; i++) {
  111.             if ((*d++ = *s++) == 0) {
  112.                 /* Pad with zeros. */
  113.                 for (; i<n; i++)
  114.                     *d++ = 0;
  115.                 return dst;
  116.             }
  117.         }
  118.         /* If we get here, then we have a full string, with n - 1 characters,
  119.          * so now we NUL terminate it and go home.
  120.          */
  121.         *d = 0;
  122.     }
  123.     return (dst);
  124. }    /* _Strncat */
  125.  
  126.  
  127. /*
  128.  * Copy src to dst, truncating or null-padding to always copy n-1 bytes.
  129.  * Return dst.
  130.  */
  131. char *_Strncpy(char *dst, char *src, register size_t n)
  132. {
  133.     register char *d;
  134.     register char *s;
  135.     register size_t i;
  136.  
  137.     d = dst;
  138.     *d = 0;
  139.     if (n != 0) {
  140.         s = src;
  141.         /* If they specified a maximum of n characters, use n - 1 chars to
  142.          * hold the copy, and the last character in the array as a NUL.
  143.          * This is the difference between the regular strncpy routine.
  144.          * strncpy doesn't guarantee that your new string will have a
  145.          * NUL terminator, but this routine does.
  146.          */
  147.         for (i=1; i<n; i++) {
  148.             if ((*d++ = *s++) == 0) {
  149.                 /* Pad with zeros. */
  150.                 for (; i<n; i++)
  151.                     *d++ = 0;
  152.                 return dst;
  153.             }
  154.         }
  155.         /* If we get here, then we have a full string, with n - 1 characters,
  156.          * so now we NUL terminate it and go home.
  157.          */
  158.         *d = 0;
  159.     }
  160.     return (dst);
  161. }    /* _Strncpy */
  162.  
  163.  
  164.  
  165. /* Converts any uppercase characters in the string to lowercase.
  166.  * Never would have guessed that, huh?
  167.  */
  168. void StrLCase(char *dst)
  169. {
  170.     register char *cp;
  171.  
  172.     for (cp=dst; *cp != '\0'; cp++)
  173.         if (isupper((int) *cp))
  174.             *cp = (char) tolower(*cp);
  175. }
  176.  
  177.  
  178.  
  179.  
  180. char *Strpcpy(char *dst, char *src)
  181. {
  182.     while ((*dst++ = *src++) != '\0')
  183.         ;
  184.     return (--dst);    /* return current value of dst, NOT original value! */
  185. }    /* Strpcpy */
  186.  
  187.  
  188.  
  189. /*
  190.  * malloc's a copy of oldstr.
  191.  */
  192. char *NewString(char *oldstr)
  193. {
  194.     size_t howLong;
  195.     char *newstr;
  196.  
  197.     howLong = strlen(oldstr);
  198.     if ((newstr = malloc(howLong + 1)) != NULL)
  199.         (void) strcpy(newstr, oldstr);
  200.     return newstr;
  201. }    /* NewString */
  202.  
  203.  
  204.  
  205.  
  206.  
  207. void Getopt_Reset(void)
  208. {
  209.     Optind = 1;
  210.     Optplace = "";
  211. }    /* Getopt_Reset */
  212.  
  213. static char *NextOption(char *ostr)
  214. {
  215.     if ((Optopt = (int) *Optplace++) == (int) ':')
  216.         return 0;
  217.     return index(ostr, Optopt);
  218. }
  219.  
  220. int Getopt(int nargc, char **nargv, char *ostr)
  221. {
  222.     register char *oli;                   /* Option letter list index */
  223.  
  224.     if (!*Optplace) {                       /* update scanning pointer */
  225.         if (Optind >= nargc || *(Optplace = nargv[Optind]) != '-')
  226.             return (EOF);
  227.         if (Optplace[1] && *++Optplace == '-') {    /* found "--" */
  228.             ++Optind;
  229.             return (EOF);
  230.         }
  231.     }                                   /* Option letter okay? */
  232.     oli = NextOption(ostr);
  233.     if (oli == NULL) {
  234.         if (!*Optplace)
  235.             ++Optind;
  236.         if (Opterr) {
  237.             (void) fprintf(stderr, "%s%s%c\n", *nargv, ": illegal option -- ", Optopt);
  238.             return(BADCH);
  239.         }
  240.     }
  241.     if (*++oli != ':') {               /* don't need argument */
  242.         Optarg = NULL;
  243.         if (!*Optplace)
  244.             ++Optind;
  245.     } else {                           /* need an argument */
  246.         if (*Optplace)                       /* no white space */
  247.             Optarg = Optplace;
  248.         else if (nargc <= ++Optind) {  /* no arg */
  249.             Optplace = EMSG;
  250.             if (Opterr) {
  251.                 (void) fprintf(stderr, "%s%s%c\n", *nargv, ": option requires an argument -- ", Optopt);
  252.                 return(BADCH);
  253.             }
  254.         } else                           /* white space */
  255.             Optarg = nargv[Optind];
  256.         Optplace = EMSG;
  257.         ++Optind;
  258.     }
  259.     return (Optopt);                   /* dump back Option letter */
  260. }                                       /* Getopt */
  261.  
  262.  
  263.  
  264.  
  265.  
  266. /*
  267.  * Converts an ls date, in either the "Feb  4  1992" or "Jan 16 13:42"
  268.  * format to a time_t.
  269.  */
  270. unsigned long UnLSDate(char *dstr)
  271. {
  272. #ifdef NO_MKTIME
  273.     return (MDTM_UNKNOWN);
  274. #else
  275.     char *cp = dstr;
  276.     int mon, day, year, hr, min;
  277.     time_t now, mt;
  278.     unsigned long result = MDTM_UNKNOWN;
  279.     struct tm ut, *t;
  280.  
  281.     switch (*cp++) {
  282.         case 'A':
  283.             mon = (*cp == 'u') ? 7 : 3;
  284.             break;
  285.         case 'D':
  286.             mon = 11;
  287.             break;
  288.         case 'F':
  289.             mon = 1;
  290.             break;
  291.         default:                       /* shut up un-init warning */
  292.         case 'J':
  293.             if (*cp++ == 'u')
  294.                 mon = (*cp == 'l') ? 6 : 5;
  295.             else
  296.                 mon = 0;
  297.             break;
  298.         case 'M':
  299.             mon = (*++cp == 'r') ? 2 : 4;
  300.             break;
  301.         case 'N':
  302.             mon = 10;
  303.             break;
  304.         case 'O':
  305.             mon = 9;
  306.             break;
  307.         case 'S':
  308.             mon = 8;
  309.     }
  310.     cp = dstr + 4;
  311.     day = 0;
  312.     if (*cp != ' ')
  313.         day = 10 * (*cp - '0');
  314.     cp++;
  315.     day += *cp++ - '0';
  316.     min = 0;
  317.     
  318.     (void) time(&now);
  319.     t = localtime(&now);
  320.  
  321.     if (*++cp != ' ') {
  322.         /* It's a time, XX:YY, not a year. */
  323.         cp[2] = ' ';
  324.         (void) sscanf(cp, "%d %d", &hr, &min);
  325.         cp[2] = ':';
  326.         year = t->tm_year;
  327.         if (mon > t->tm_mon)
  328.             --year;
  329.     } else {
  330.         hr = min = 0;
  331.         (void) sscanf(cp, "%d", &year);
  332.         year -= 1900;
  333.     }
  334.     /* Copy the whole structure of the 'tm' pointed to by t, so it will
  335.      * also set all fields we don't specify explicitly to be the same as
  336.      * they were in t.  That way we copy non-standard fields such as
  337.      * tm_gmtoff, if it exists or not.
  338.      */
  339.     ut = *t;
  340.     ut.tm_sec = 1;
  341.     ut.tm_min = min;
  342.     ut.tm_hour = hr;
  343.     ut.tm_mday = day;
  344.     ut.tm_mon = mon;
  345.     ut.tm_year = year;
  346.     ut.tm_wday = ut.tm_yday = 0;
  347.     mt = mktime(&ut);
  348.     if (mt != (time_t) -1)
  349.         result = (unsigned long) mt;
  350.     return (result);
  351. #endif    /* NO_MKTIME */
  352. }    /* UnLSDate */
  353.  
  354.  
  355.  
  356. /*
  357.  * Converts a MDTM date, like "213 19930602204445\n"
  358.  * format to a time_t.
  359.  */
  360. unsigned long UnMDTMDate(char *dstr)
  361. {
  362. #ifdef NO_MKTIME
  363.     return (MDTM_UNKNOWN);
  364. #else
  365.     struct tm ut;
  366.     time_t mt;
  367.     unsigned long result = MDTM_UNKNOWN;
  368.  
  369.     /* Clear out the whole structure, along with any non-standard fields. */
  370.     bzero((char *)&ut, sizeof (struct tm));
  371.  
  372.     if (sscanf(dstr, "%*s %04d%02d%02d%02d%02d%02d",
  373.         &ut.tm_year,
  374.         &ut.tm_mon,
  375.         &ut.tm_mday,
  376.         &ut.tm_hour,
  377.         &ut.tm_min,
  378.         &ut.tm_sec) == 6)
  379.     {    
  380.         --ut.tm_mon;
  381.         ut.tm_year -= 1900;
  382.         mt = mktime(&ut);
  383.         if (mt != (time_t) -1)
  384.             result = (unsigned long) mt;
  385.     }
  386.     return result;
  387. #endif    /* NO_MKTIME */
  388. }    /* UnMDTMDate */
  389.  
  390.  
  391.  
  392. void Perror(
  393. #ifdef DB_ERRS
  394.             char *fromProc
  395.             ,
  396. #ifdef __LINE__
  397.             int lineNum,
  398. #endif
  399. #endif
  400.             char *msg
  401.             )
  402. {
  403.     extern int errno;
  404.  
  405.     if (NOT_VQUIET) {
  406. #ifdef sun
  407.     /*
  408.      * There is a problem in the SunOS headers when compiling with an ANSI
  409.      * compiler.  The problem is that there are macros in the form of
  410.      * #define MAC(x) 'x', and this will always be the character x instead
  411.      * of whatever parameter was passed to MAC.  If we get these errors, it
  412.      * usually means that you are trying to compile with gcc when you haven't
  413.      * run the 'fixincludes' script that fixes these macros.  We will ignore
  414.      * the error, but it means that the echo() function won't work correctly,
  415.      * and you will see your password echo.
  416.      */
  417.         if (errno == ENOTTY)
  418.             return;
  419. #endif
  420.         (void) fprintf(stderr, "NcFTP");
  421. #ifdef DB_ERRS
  422.         if (fromProc != NULL)
  423.             (void) fprintf(stderr, "/%s", fromProc);
  424. #ifdef __LINE__
  425.         (void) fprintf(stderr, "/%d", lineNum);
  426. #endif
  427. #endif
  428.         (void) fprintf(stderr, ": ");
  429.         if (msg != NULL)
  430.             (void) fprintf(stderr, "%s (%d): ", msg, errno);
  431.         perror(NULL);
  432.     }
  433. }    /* Perror */
  434.  
  435.  
  436.  
  437.  
  438. size_t RemoveTrailingNewline(char *cp, int *stripped)
  439. {
  440.     size_t len;
  441.     int nBytesStripped = 0;
  442.  
  443.     if (cp != NULL) {
  444.         cp += (len = strlen(cp)) - 1;
  445.         if (*cp == '\n') {
  446.             *cp-- = 0;    /* get rid of the newline. */
  447.             nBytesStripped++;
  448.         }
  449.         if (*cp == '\r') { /* no returns either, please. */
  450.             *cp = 0;
  451.             nBytesStripped++;
  452.         }
  453.         if (stripped != NULL)
  454.             *stripped = nBytesStripped;
  455.         return len;
  456.     }
  457.     return (size_t)0;
  458. }    /* RemoveTrailingNewline */
  459.  
  460.  
  461.  
  462. #ifdef GETLINE
  463. extern size_t epromptlen;
  464.  
  465. /*
  466.  * The Getline library doesn't detect the ANSI escape sequences, so the
  467.  * library would think that a string is longer than actually appears on
  468.  * screen.  This function lets Getline work properly.  This function is
  469.  * intended to fix that problem for the main command prompt only.  If any
  470.  * other prompts want to use ANSI escapes, a (costly) function would have
  471.  * to scan the prompt for all escape sequences.
  472.  */
  473. /*ARGSUSED*/
  474. static size_t MainPromptLen(char *pr)
  475. {
  476.     return (int)epromptlen;
  477. }
  478. #endif
  479.  
  480. static char *StdioGets(char *promptstr, char *sline, size_t size)
  481. {
  482.     char *cp;
  483.  
  484.     if (fromatty) {
  485.         /* It's okay to print a prompt if we are redirecting stdout,
  486.          * as long as stdin is still a tty.  Otherwise, don't print
  487.          * a prompt at all if stdin is redirected.
  488.          */
  489. #ifdef CURSES
  490.         tcap_put(promptstr);
  491. #else
  492.         (void) fputs(promptstr, stdout);
  493. #endif
  494.     }
  495.     sline[0] = 0;
  496.     (void) fflush(stdout);    /* for svr4 */
  497.     cp = fgets(sline, (int)(size - 2), stdin);
  498.     (void) RemoveTrailingNewline(sline, NULL);
  499.     return cp;
  500. }    /* StdioGets */
  501.  
  502.  
  503. /* Given a prompt string, a destination string, and it's size, return feedback
  504.  * from the user in the destination string, with any trailing newlines
  505.  * stripped.  Returns NULL if EOF encountered.
  506.  */
  507. char *Gets(char *promptstr, char *sline, size_t size)
  508. {
  509.     char *cp, ch;
  510.     string plines;
  511. #ifdef GETLINE
  512.     int ismainprompt = (promptstr == prompt2);
  513. #endif
  514.  
  515.     if (!fromatty || !toatty) {
  516.         /* Don't worry about a cmdline/history editor if you redirected a
  517.          * file at me.
  518.          */
  519.         return (StdioGets(promptstr, sline, size));
  520.     }
  521.  
  522.     sline[0] = 0;    /* Clear it, in case of an error later. */
  523.  
  524.     /*
  525.      * The prompt string may actually be several lines if the user put a
  526.      * newline in it with the @N option.  In this case we only want to print
  527.      * the very last line, so the command-line editors won't screw up.  So
  528.      * now we print all the lines except the last line.
  529.      */
  530.     cp = rindex(promptstr, '\n');
  531.     if (cp != NULL) {
  532.         ch = *++cp;
  533.         *cp = 0;
  534.         (void) Strncpy(plines, promptstr);
  535.         *cp = ch;
  536.         promptstr = cp;
  537. #ifdef CURSES
  538.         tcap_put(plines);
  539. #else
  540.         (void) fputs(plines, stdout);
  541. #endif
  542.     }
  543.  
  544. #ifdef READLINE
  545.     if ((cp = readline(promptstr)) != NULL) {
  546.         (void) _Strncpy(sline, cp, size);
  547.         free(cp);
  548.         (void) RemoveTrailingNewline(cp = sline, NULL);
  549.         if (*cp != 0)    /* Don't add blank lines to history buffer. */
  550.             add_history(cp);
  551.     }
  552. #else    /* READLINE */
  553.  
  554. #ifdef GETLINE
  555.     if (toatty) {
  556.         if (ismainprompt)
  557.             gl_strwidth(MainPromptLen);
  558.         if ((cp = getline(promptstr)) != NULL) {
  559.             if (*cp == '\0')    /* You hit ^D. */
  560.                 return NULL;
  561.             cp = _Strncpy(sline, cp, size);
  562.             (void) RemoveTrailingNewline(cp, NULL);
  563.             if (*cp != '\0') {    /* Don't add blank lines to history buffer. */
  564.                 gl_histadd(cp);
  565.             }
  566.         }
  567.         /* Hope your strlen is declared as returning a size_t. */
  568.         gl_strwidth(strlen);
  569.     } else {
  570.         cp = StdioGets(promptstr, sline, size);
  571.     }
  572. #else /* !GETLINE */
  573.     cp = StdioGets(promptstr, sline, size);
  574. #endif /* !GETLINE */
  575. #endif /* !READLINE */
  576.     return cp;
  577. }    /* Gets */
  578.  
  579.  
  580.  
  581.  
  582. char **re_makeargv(char *promptstr, int *argc)
  583. {
  584.     size_t sz;
  585.  
  586.     (void) strcat(line, " ");
  587.     sz = strlen(line);
  588.     (void) Gets(promptstr, &line[sz], (size_t) (CMDLINELEN - sz)) ;
  589.     (void) makeargv();
  590.     *argc = margc;
  591.     return (margv);
  592. }    /* re_makeargv */
  593.  
  594.  
  595.  
  596. #ifndef HAS_GETCWD
  597. extern char *getwd(char *);
  598. #endif
  599.  
  600. char *get_cwd(char *buf, int size)
  601. {
  602. #ifdef HAS_GETCWD
  603. #    ifdef NO_UNISTDH
  604. #        ifdef GETCWDSIZET
  605.             extern char *getcwd(char *, size_t);
  606. #        else
  607.             extern char *getcwd(char *, int);
  608. #        endif
  609. #    endif
  610.     return (getcwd(buf, size - 1));
  611. #else
  612. #ifndef MAXPATHLEN
  613. #    define MAXPATHLEN (1024)
  614. #endif
  615.     static char *cwdbuf = NULL;
  616.  
  617.     if (cwdbuf == NULL) {
  618.         cwdbuf = (char *)malloc((size_t) MAXPATHLEN);
  619.         if (cwdbuf == NULL)
  620.             fatal("out of memory for getwd buffer.");
  621.     }
  622.         getwd(cwdbuf);
  623.         return (_Strncpy(buf, cwdbuf, (size_t)size));
  624. #endif
  625. }   /* get_cwd */
  626.  
  627.  
  628.  
  629. int tmp_name(char *str)
  630. {
  631.     (void) strcpy(str, "/tmp/ncftpXXXXXX");
  632.     return (!mktemp(str));
  633. }    /* tmp_name */
  634.  
  635.  
  636.  
  637.  
  638. char *onoff(int boolf)
  639. {
  640.     return (boolf ? "on" : "off");
  641. }   /* onoff */
  642.  
  643.  
  644.  
  645.  
  646. int StrToBool(char *s)
  647. {
  648.     int c;
  649.     int result;
  650.  
  651.     c = tolower(*s);
  652.     result = 0;
  653.     switch (c) {
  654.         case 'f':           /* false */
  655.         case 'n':            /* no */
  656.             break;
  657.         case 'o':           /* test for "off" and "on" */
  658.             c = tolower(s[1]);
  659.             if (c == 'f')
  660.                 break;
  661.             /* fall through */
  662.         case 't':           /* true */
  663.         case 'y':            /* yes */
  664.             result = 1;
  665.             break;
  666.         default:            /* 1, 0, -1, other number? */
  667.             if (atoi(s) != 0)
  668.                 result = 1;
  669.     }
  670.     return result;
  671. }   /* StrToBool */
  672.  
  673.  
  674.  
  675.  
  676. int confirm(char *cmd, char *file)
  677. {
  678.     string str, pr;
  679.  
  680.     if (!fromatty || (activemcmd && !mprompt) || (doingInitMacro))
  681.         return 1;
  682.     (void) sprintf(pr, "%s %s? ", cmd, file);
  683.     (void) Gets(pr, str, sizeof(str));
  684.     return (*str != 'n' && *str != 'N');
  685. }    /* confirm */
  686.  
  687.  
  688.  
  689. void fatal(char *msg)
  690. {
  691.     (void) fprintf(stderr, "%s: %s\n", progname, msg);
  692.     close_up_shop();
  693.     exit(1);
  694. }    /* fatal */
  695.  
  696.  
  697.  
  698.  
  699. int UserLoggedIn(void)
  700. {
  701.     static int inited = 0;
  702.     static int parent_pid, stderr_was_tty;
  703.  
  704.     if (!inited) {
  705.         stderr_was_tty = isatty(2);
  706.         parent_pid = getppid();
  707.         inited++;
  708.     }
  709.     if ((stderr_was_tty && !isatty(2)) || (getppid() != parent_pid))
  710.         return 0;
  711.     return 1;
  712. }    /* UserLoggedIn */
  713.  
  714.  
  715.  
  716.  
  717. struct cmd *getcmd(char *name)
  718. {
  719.     struct cmd *c, *found;
  720.     int nmatches;
  721.     size_t len;
  722.     char *p;
  723.  
  724.     found = (struct cmd *)0;
  725.     if (name != NULL) {
  726.         len = strlen(name);
  727.         nmatches = 0;
  728.         for (c = cmdtab; (p = c->c_name) != NULL; c++) {
  729.             if (strcmp(name, p) == 0) {
  730.                 /* Exact match. */
  731.                 found = c;
  732.                 goto xx;
  733.             }
  734.             if (c->c_handler == unimpl)
  735.                 continue;
  736.             if (strncmp(name, p, len) == 0) {
  737.                 if (++nmatches > 1) {
  738.                     found = ((struct cmd *) -1);    
  739.                     goto xx;
  740.                 }                
  741.                 found = c;
  742.             } else if (found != NULL)
  743.                 break;
  744.         }
  745.     }
  746. xx:
  747.     return (found);
  748. }    /* getcmd */
  749.  
  750.  
  751.  
  752.  
  753. void cmd_help(struct cmd *c)
  754. {
  755.     (void) printf("%s: %s.\n",
  756.         c->c_name,
  757.         c->c_help
  758.     );
  759. }    /* cmd_help */
  760.  
  761.  
  762.  
  763.  
  764. void cmd_usage(struct cmd *c)
  765. {
  766.     if (c->c_usage != NULL)
  767.         (void) printf("Usage: %s%s\n",
  768.             c->c_name,
  769.             c->c_usage
  770.         );
  771. }    /* cmd_usage */
  772.  
  773.  
  774.  
  775.  
  776. /*
  777.  * A simple function that translates most pathnames with ~, ~user, or
  778.  * environment variables as the first item.  It won't do paths with env vars
  779.  * or ~s in the middle of the path, but those are extremely rare.
  780.  */
  781. char *LocalPath(char *path)
  782. {
  783.     longstring orig;
  784.     struct passwd *pw;
  785.     char *firstent;
  786.     char *cp, *dp, *rest;
  787.  
  788.     (void) Strncpy(orig, path);
  789.     firstent = orig;
  790.     if ((cp = index(orig, '/')) != NULL) {
  791.         if (cp == orig) {
  792.             /* If we got here, the path is actually a full path name,
  793.              * with the first character as a slash, so just leave it
  794.              * alone.
  795.              */
  796.             return (path);
  797.         }
  798.         /* Otherwise we can look at the first word of the path, and
  799.          * try to expand it, like $HOME/ or ~/, or it is a relative path, 
  800.          * which is okay since we won't really do anything with it.
  801.          */
  802.         *cp = 0;
  803.         rest = cp + 1;
  804.         /* 'firstent' now contains the first 'word' in the path. */
  805.     } else {
  806.         /* Path was just a single word, or it is a full path, like:
  807.          * /usr/tmp/zz, so firstent is just the entire given "path."
  808.          */
  809.         rest = NULL;
  810.     }
  811.     if (orig[0] == '~') {
  812.         if (orig[1] == 0) {
  813.             firstent = uinfo.homedir;
  814.         } else {
  815.             pw = getpwnam(orig + 1);
  816.             if (pw != NULL)
  817.                 firstent = pw->pw_dir;
  818.         }
  819.     } else if (orig[0] == '$') {
  820.         cp = orig + 1;
  821.         dp = orig + strlen(orig) - 1;
  822.         if ((*cp == '(' && *dp == ')') || (*cp == '{' && *dp == '}')) {
  823.             cp++;
  824.             *dp = 0;
  825.         }
  826.         firstent = getenv(cp);
  827.         if (firstent == NULL) {
  828.             (void) fprintf(stderr, "%s: no such environment variable.\n", cp);
  829.             firstent = "badEnvVar";
  830.         }
  831.     }
  832.     if (rest == NULL)
  833.         (void) strcpy(path, firstent);
  834.     else 
  835.         (void) sprintf(path, "%s/%s", firstent, rest);
  836.     return (path);
  837. }    /* LocalPath */
  838.  
  839.  
  840.  
  841. /*
  842.  * A special case, where invisible dot-files that would normally appear in
  843.  * your home directory will appear instead as visible files in your $DOTDIR
  844.  * directory if you have one.
  845.  */
  846.  
  847. #define LCMP(b) (strncmp(path, (b), (o = sizeof(b) - 1)) == 0)
  848.  
  849. char *LocalDotPath(char *path)
  850. {
  851.     size_t o;
  852.     longstring s, s2;
  853.     char *cp = getenv("DOTDIR");
  854.  
  855.     if (cp == NULL) {
  856.         goto aa;
  857.     } else {
  858.         if (*cp != '/' && *cp != '~') {
  859.             /* then maybe they mean relative to $HOME. */
  860.             (void) sprintf(s2, "%s/%s", uinfo.homedir, cp);
  861.             cp = s2;
  862.         }
  863.         if (LCMP("~/.") ||
  864.             LCMP("$HOME/.") ||
  865.             LCMP("$home/.") ||
  866.             LCMP("$(HOME)/.") ||
  867.             LCMP("${HOME}/.")
  868.         ) {
  869.             (void) Strncpy(s, path);
  870.             (void) sprintf(path, "%s/%s", cp, s + o);
  871.             cp = path;
  872.         } else {
  873. aa:            cp = LocalPath(path);
  874.         }
  875.     }
  876.     return cp;
  877. }    /* LocalDotPath */
  878.  
  879. #ifdef NO_STRSTR
  880.  
  881. /*
  882.  *  The Elm Mail System  -  $Revision: 5.1 $   $State: Exp $
  883.  *
  884.  *            Copyright (c) 1988-1992 USENET Community Trust
  885.  *            Copyright (c) 1986,1987 Dave Taylor
  886.  */
  887.  
  888. char *strstr(s1, s2)
  889. char *s1, *s2;
  890. {
  891.     int len;
  892.     char *ptr;
  893.     char *tmpptr;
  894.  
  895.     ptr = NULL;
  896.     len = strlen(s2);
  897.  
  898.     if ( len <= strlen(s1)) {
  899.         tmpptr = s1;
  900.         while ((ptr = index(tmpptr, (int)*s2)) != NULL) {
  901.             if (strncmp(ptr, s2, len) == 0) {
  902.                 break;
  903.             }
  904.             tmpptr = ptr+1;
  905.         }
  906.     }
  907.     return (ptr);
  908. }
  909.  
  910. #endif
  911.  
  912.  
  913. #ifdef NO_RENAME
  914. int rename(oldname, newname)
  915. const char *oldname, *newname;
  916. {
  917.     return (link(oldname, newname) == 0 ? unlink(oldname) : -1);
  918. }
  919. #endif /*NO_RENAME*/
  920.  
  921.  
  922. /* eof Util.c */
  923.