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