home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / NEXTSTEP / UNIX / Networking / ncftp-2.4.2-MIHS / src / Util.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-10-16  |  14.9 KB  |  769 lines

  1. /* Util.c */
  2.  
  3. #include "Sys.h"
  4.  
  5. #ifdef HAVE_GETCWD
  6. #    ifndef HAVE_UNISTD_H
  7.         extern char *getcwd();
  8. #    endif
  9. #else
  10. #    ifdef HAVE_GETWD
  11. #        include <sys/param.h>
  12. #        ifndef MAXPATHLEN
  13. #            define MAXPATHLEN 1024
  14. #        endif
  15.         extern char *getwd(char *);
  16. #    endif
  17. #endif
  18.  
  19. #include <errno.h>
  20. #include <ctype.h>
  21.  
  22. #ifdef HAVE_LIMITS_H
  23. #    include <limits.h>
  24. #endif
  25.  
  26. #include "Util.h"
  27. #include "Main.h"
  28. #include "Bookmark.h"
  29. #include "Curses.h"
  30.  
  31. time_t gMailBoxTime;            /* last modified time of mbox */
  32. int gWarnShellBug = 0;
  33. int gMarkTrailingSpace = 0;
  34.  
  35. extern int gLoggedIn, gWinInit;
  36. extern string gOurDirectoryPath;
  37. extern longstring gRemoteCWD;
  38. extern string gActualHostName;
  39. extern long gEventNumber;
  40. extern string gHost;
  41. extern Bookmark gRmtInfo;
  42. extern UserInfo gUserInfo;
  43.  
  44. /* Read a line, and axe the end-of-line. */
  45. char *FGets(char *str, size_t size, FILE *fp)
  46. {
  47.     char *cp, *nlptr;
  48.     
  49.     cp = fgets(str, ((int) size) - 1, fp);
  50.     if (cp != NULL) {
  51.         nlptr = cp + strlen(cp) - 1;
  52.         if (*nlptr == '\n')
  53.             *nlptr = '\0';
  54.     }
  55.     return cp;
  56. }    /* FGets */
  57.  
  58.  
  59.  
  60.  
  61. /* This should only be called if the program wouldn't function
  62.  * usefully without the memory requested.
  63.  */
  64. void OutOfMemory(void)
  65. {
  66.     fprintf(stderr, "Out of memory!\n");
  67.     Exit(kExitOutOfMemory);
  68. }    /* OutOfMemory */
  69.  
  70.  
  71.  
  72. /* A way to strcat to a dynamically allocated area of memory. */
  73. char *PtrCat(char *dst, char *src)
  74. {
  75.     size_t len;
  76.  
  77.     len = strlen(dst) + strlen(src) + 1;
  78.     if ((dst = Realloc(dst, len)) == NULL)
  79.         return (NULL);
  80.     strcat(dst, src);
  81.     return (dst);
  82. }    /* PtrCat */
  83.  
  84.  
  85.  
  86. /* Extends an area of memory, then cats a '/' and a string afterward. */
  87. char *PtrCatSlash(char *dst, char *src)
  88. {
  89.     size_t dlen;
  90.     char *nu;
  91.  
  92.     while (*src == '/')
  93.         ++src;
  94.  
  95.     dlen = strlen(dst);
  96.     if (dst[dlen - 1] != '/') {
  97.         dst = PtrCat(dst, "/");
  98.         if (dst == NULL)
  99.             nu = NULL;
  100.         else
  101.             nu = PtrCat(dst, src);
  102.     } else {
  103.         nu = PtrCat(dst, src);
  104.     }
  105.     return (nu);
  106. }    /* PtrCatSlash */
  107.  
  108.  
  109.  
  110. void *Realloc(void *ptr, size_t siz)
  111. {
  112.     if (ptr == NULL)
  113.         return (void *) malloc(siz);
  114.     return ((void *) realloc(ptr, siz));
  115. }    /* Realloc */
  116.  
  117.  
  118.  
  119.  
  120.  
  121. void MakeStringPrintable(char *dst, unsigned char *src, size_t siz)
  122. {
  123.     int c;
  124.     size_t i;
  125.     int endnl, numsp;
  126.  
  127.     i = 0;
  128.     --siz;    /* Leave room for nul. */
  129.     while ((i < siz) && (*src != '\0')) {
  130.         c = *src++;
  131.         if (isprint(c) || (c == '\n') || (c == '\t')
  132.             /* Needed to view chinese... */
  133.             || (c & 0x80) || (c == 0x1b))
  134.         {
  135.             *dst++ = c;
  136.             ++i;
  137.         } else if (iscntrl(c) && (c != 0x7f)) {
  138.             /* Need room for 2 characters, ^x. */
  139.             if (i < siz - 1) {
  140.                 c = c + '@';
  141.                 *dst++ = '^';
  142.                 *dst++ = c;
  143.                 i += 2;
  144.             }
  145.         } else {
  146.             /* Need room for 5 characters, \xxx.
  147.              * The fifth character will be the \0 that is written by
  148.              * sprintf, but we know we have room for that already since
  149.              * we already accounted for that above.
  150.              */
  151.             if (i < siz - 3) {
  152.                 sprintf(dst, "\\%03o", c);
  153.                 i += 4;
  154.                 dst += 4;
  155.             }
  156.         }
  157.     }
  158.     *dst-- = '\0';
  159.  
  160.     /* See if this line ended with a \n. */
  161.     endnl = 0;
  162.     if (i > 0 && *dst == '\n') {
  163.         endnl = 1;
  164.         --i;
  165.         --dst;
  166.     }
  167.  
  168.     /* The user may want to be aware if there are trailing spaces
  169.      * at the end of a line.
  170.      */
  171.     numsp = 0;
  172.     while (i > 0) {
  173.         c = *dst;
  174.         if (c != ' ')
  175.             break;
  176.         numsp++;
  177.         --i;
  178.         --dst;
  179.     }
  180.  
  181.     /* Mark trailing spaces as \x where x is a space. */
  182.     ++dst;
  183.  
  184.     if (gMarkTrailingSpace) {
  185.         while ((numsp > 0) && (i < siz)) {
  186.             *dst++ = '\\';
  187.             *dst++ = ' ';
  188.             i += 2;
  189.             --numsp;
  190.         }
  191.     }
  192.  
  193.     /* Tack the newline back onto the end of the string, if needed. */
  194.     if (endnl)
  195.         *dst++ = '\n';
  196.  
  197.     *dst = '\0';
  198. }    /* MakeStringPrintable */
  199.  
  200.  
  201.  
  202.  
  203. /* This will abbreviate a string so that it fits into max characters.
  204.  * It will use ellipses as appropriate.  Make sure the string has
  205.  * at least max + 1 characters allocated for it.
  206.  */
  207. void AbbrevStr(char *dst, char *src, size_t max, int mode)
  208. {
  209.     int len;
  210.  
  211.     len = (int) strlen(src);
  212.     if (len > (int) max) {
  213.         if (mode == 0) {
  214.             /* ...Put ellipses at left */
  215.             strcpy(dst, "...");
  216.             Strncat(dst, src + len - (int) max + 3, max + 1);
  217.         } else {
  218.             /* Put ellipses at right... */
  219.             Strncpy(dst, src, max + 1);
  220.             strcpy(dst + max - 3, "...");
  221.         }
  222.     } else {
  223.         Strncpy(dst, src, max + 1);
  224.     }
  225. }    /* AbbrevStr */
  226.  
  227.  
  228.  
  229.  
  230.  
  231. /* Converts any uppercase characters in the string to lowercase.
  232.  * Never would have guessed that, huh?
  233.  */
  234. void StrLCase(char *dst)
  235. {
  236.     register char *cp;
  237.  
  238.     for (cp=dst; *cp != '\0'; cp++)
  239.         if (isupper((int) *cp))
  240.             *cp = (char) tolower(*cp);
  241. }    /* StrLCase */
  242.  
  243.  
  244.  
  245.  
  246. /* Use getcwd/getwd to get the full path of the current local
  247.  * working directory.
  248.  */
  249. char *GetCWD(char *buf, size_t size)
  250. {
  251. #ifdef HAVE_GETCWD
  252.     static char *cwdBuf = NULL;
  253.     static size_t cwdBufSize = 0;
  254.  
  255.     if (cwdBufSize == 0) {
  256.         cwdBufSize = (size_t) 128;
  257.         cwdBuf = (char *) malloc(cwdBufSize);
  258.     }
  259.  
  260.     for (errno = 0; ; ) {
  261.         if (cwdBuf == NULL) {
  262.             Error(kDoPerror, "Not enough free memory to get the local working directory path.\n");
  263.             (void) Strncpy(buf, ".", size);
  264.             return NULL;
  265.         }
  266.  
  267.         if (getcwd(cwdBuf, cwdBufSize) != NULL)
  268.             break;
  269.         if (errno != ERANGE) {
  270.             Error(kDoPerror, "Can't get the local working directory path.\n");
  271.             (void) Strncpy(buf, ".", size);
  272.             return NULL;
  273.         }
  274.         cwdBufSize *= 2;
  275.         cwdBuf = Realloc(cwdBuf, cwdBufSize);
  276.     }
  277.     
  278.     return (Strncpy(buf, cwdBuf, size));
  279. #else
  280. #ifdef HAVE_GETWD
  281.     static char *cwdBuf = NULL;
  282.     char *dp;
  283.     
  284.     /* Due to the way getwd is usually implemented, it's
  285.      * important to have a buffer large enough to hold the
  286.      * whole thing.  getwd usually starts at the end of the
  287.      * buffer, and works backwards, returning you a pointer
  288.      * to the beginning of it when it finishes.
  289.      */
  290.     if (size < MAXPATHLEN) {
  291.         /* Buffer not big enough, so use a temporary one,
  292.          * and then copy the first 'size' bytes of the
  293.          * temporary buffer to your 'buf.'
  294.          */
  295.         if (cwdBuf == NULL) {
  296.             cwdBuf = (char *) malloc((size_t) MAXPATHLEN);
  297.             if (cwdBuf == NULL)
  298.                 OutOfMemory();
  299.         }
  300.         dp = cwdBuf;
  301.     } else {
  302.         /* Buffer is big enough already. */
  303.         dp = buf;
  304.     }
  305.     *dp = '\0';
  306.     if (getwd(dp) == NULL) {
  307.         /* getwd() should write the reason why in the buffer then,
  308.          * according to the man pages.
  309.          */
  310.         Error(kDontPerror, "Can't get the local working directory path. %s\n", dp);
  311.         (void) Strncpy(buf, ".", size);
  312.         return (NULL);
  313.     }
  314.     return (Strncpy(buf, dp, size));
  315.     
  316. #else
  317.     /* Not really a solution, but does anybody not have either of
  318.      * getcwd or getwd?
  319.      */
  320.     Error(kDontPerror, "Can't get the cwd path; no getwd() or getcwd().\n");
  321.     return (Strncpy(buf, ".", size));
  322. #endif
  323. #endif
  324. }   /* GetCWD */
  325.  
  326.  
  327.  
  328.  
  329. char *Path(char *dst, size_t siz, char *parent, char *fname)
  330. {
  331.     (void) Strncpy(dst, parent, siz);
  332.     (void) Strncat(dst, "/", siz);
  333.     return (Strncat(dst, fname, siz));
  334. }    /* Path */
  335.  
  336.  
  337.  
  338.  
  339. char *OurDirectoryPath(char *dst, size_t siz, char *fname)
  340. {
  341.     return (Path(dst, siz, gOurDirectoryPath, fname));
  342. }    /* OurDirectoryPath */
  343.  
  344.  
  345.  
  346.  
  347. int MkDirs(char *path)
  348. {
  349.     longstring mdCmd;
  350.     int result;
  351.     
  352.     result = 0;
  353.     if (access(path, F_OK) < 0) {
  354.         STRNCPY(mdCmd, "mkdir -p ");    /* -p is nice, but not mandatory. */ 
  355.         STRNCAT(mdCmd, path);
  356.         result = system(mdCmd);
  357.     }
  358.     return (result);
  359. }    /* MkDirs */
  360.  
  361.  
  362.  
  363.  
  364. /* Closes the file supplied, if it isn't a std stream. */
  365. int CloseFile(FILE **f)
  366. {
  367.     if (*f != NULL) {
  368.         if ((*f != stdout) && (*f != stdin) && (*f != stderr)) {
  369.             (void) fclose(*f);
  370.             *f = NULL;
  371.             return (1);
  372.         }
  373.         *f = NULL;
  374.     }
  375.     return (0);
  376. }    /* CloseFile */
  377.  
  378.  
  379.  
  380.  
  381. /* Returns non-zero if we are the foreground process, or 0
  382.  * if we are a background process at the time of the call.
  383.  */
  384. int InForeGround(void)
  385. {
  386. #if defined(NO_FGTEST) || !defined(HAVE_TCGETPGRP)
  387.     return (1);
  388. #else
  389. #    ifndef GETPGRP_VOID
  390. #        define GETMYPGRP (getpgrp(getpid()))
  391. #    else
  392. #        define GETMYPGRP (getpgrp())
  393. #    endif
  394.     int result, status;
  395.     static int file = -2;
  396.     static int mode = -2;
  397.  
  398.     result = 1;    
  399.     if (file == -2)
  400.         file = open("/dev/tty", O_RDONLY);
  401.     
  402.     if (file >= 0) {
  403.         status = tcgetpgrp(file);
  404.         if (status >= 0) {
  405.             result = (status == GETMYPGRP);
  406.             if (mode != result) {
  407.                 if (mode == 0) {
  408.                     TraceMsg("In background.\n");
  409.                 } else
  410.                     TraceMsg("In foreground.\n");
  411.             }
  412.             mode = result;
  413.         } else if (mode == -2) {
  414.             TraceMsg("Foreground check failed.\n");
  415.             mode = 0;
  416.         }
  417.     }
  418.     return (result);
  419. #endif
  420. }    /* InForeGround */
  421.  
  422.  
  423.  
  424.  
  425. /* Returns non-zero if it appears the user is still live at the
  426.  * terminal.
  427.  */
  428. int UserLoggedIn(void)
  429. {
  430.     static int inited = 0;
  431.     static int parent_pid, stderr_was_tty;
  432.  
  433.     if (!inited) {
  434.         stderr_was_tty = isatty(2);
  435.         parent_pid = getppid();
  436.         inited++;
  437.     }
  438.     if ((stderr_was_tty && !isatty(2)) || (getppid() != parent_pid))
  439.         return 0;
  440.     return 1;
  441. }    /* UserLoggedIn */
  442.  
  443.  
  444.  
  445.  
  446. int CheckNewMail(void)
  447. {
  448.     struct stat stbuf;
  449.  
  450.     if (*gUserInfo.mail == '\0')
  451.         return 0;
  452.  
  453.     if (stat(gUserInfo.mail, &stbuf) < 0) {
  454.         /* Can't find mail_path so we'll never check it again */
  455.         *gUserInfo.mail = '\0';    
  456.         return 0;
  457.     }
  458.  
  459.     /*
  460.      * Check if the size is non-zero and the access time is less than
  461.      * the modify time -- this indicates unread mail.
  462.      */
  463.     if ((stbuf.st_size != 0) && (stbuf.st_atime <= stbuf.st_mtime)) {
  464.         if (stbuf.st_mtime > gMailBoxTime) {
  465.             (void) PrintF("You have new mail.\n");
  466.             gMailBoxTime = stbuf.st_mtime;
  467.         }
  468.         return 1;
  469.     }
  470.  
  471.     return 0;
  472. }    /* CheckNewMail */
  473.  
  474.  
  475.  
  476.  
  477.  
  478. size_t FlagStrCopy(char *dst, size_t siz, char *src)
  479. {
  480.     time_t now;
  481.     register char *p, *q;
  482.     int    flagType;
  483.     int chType;
  484.     int nextCh;
  485.     int nPercents;
  486.     int extraChar;
  487.     size_t maxSize;
  488.     size_t onScreenLen;
  489.     size_t len;
  490.     string tmpStr;
  491.     char *copy;
  492.  
  493.     nPercents = 0;
  494.     onScreenLen = 0;
  495.     extraChar = 0;
  496.     siz -= 2;        /* Need room for nul, and extra char. */
  497.     maxSize = siz;
  498.  
  499.     for (p = src, q = dst, *q = 0; *p != '\0'; p++) {
  500.         chType = *p;
  501.         switch (chType) {
  502.             case '%':
  503.                 nPercents++;
  504.                 goto copyChar;
  505.             case '@':
  506.                 flagType = *++p;
  507.                 nextCh = p[1];
  508.                 switch (flagType) {
  509.                     case '\0':
  510.                         goto done;
  511.                         break;
  512.                     case 'Z':
  513.                         /* Tell caller not to echo a final newline. */
  514.                         extraChar = '@';
  515.                         break;
  516.                     case 'M':
  517.                         if (CheckNewMail() > 0) {
  518.                             copy = "(Mail)";
  519.                             goto copyVisStr;
  520.                         }
  521.                         goto copyNothing;
  522.  
  523.                     case 'n':
  524.                         if (gLoggedIn) {
  525.                             copy = gRmtInfo.bookmarkName;
  526.                             goto copyVisStr;
  527.                         }
  528.                         goto copyNothing;
  529.                         
  530.                     case 'N':
  531.                         copy = "\n";
  532.                         goto copyVisStr;
  533.                         break;
  534.     
  535.                     /* Probably won't implement these. */
  536.                     case 'P':    /* reset to no bold, no uline, no inverse, etc. */
  537.                         /* copy = "plain...";
  538.                         goto copyInvisStr; */
  539.                         break;
  540.                     case 'B':    /* toggle boldface */
  541.                         break;
  542.                     case 'U':    /* toggle underline */
  543.                         break;
  544.                     case 'R':
  545.                     case 'I':    /* toggle inverse (reverse) video */
  546.                         break;
  547.         
  548.                     case 'D':    /* insert current directory */
  549.                     case 'J':
  550.                         if (gLoggedIn) {
  551.                             if ((flagType == 'J') && (gRmtInfo.isUnix)) {
  552.                                 /* Not the whole path, just the dir name. */
  553.                                 copy = strrchr(gRemoteCWD, '/');
  554.                                 if (copy == NULL)
  555.                                     copy = gRemoteCWD;
  556.                                 else if ((copy != gRemoteCWD) && (copy[1]))
  557.                                     ++copy;
  558.                             } else {
  559.                                 copy = gRemoteCWD;
  560.                             }
  561.                             goto copyVisStr;
  562.                         }
  563.                         goto copyNothing;
  564.         
  565.                     case 'H':    /* insert name of connected host */
  566.                         if (gLoggedIn) {
  567.                             copy = gHost;
  568.                             goto copyVisStr;
  569.                         }
  570.                         goto copyNothing;
  571.         
  572.                     case 'h':    /* insert actual name of connected host */
  573.                         if (gLoggedIn) {
  574.                             copy = gActualHostName;
  575.                             goto copyVisStr;
  576.                         }
  577.                         goto copyNothing;
  578.         
  579.                     case '!':
  580.                     case 'E':    /* insert event number */
  581.                         (void) sprintf(tmpStr, "%ld", gEventNumber);
  582.                         copy = tmpStr;
  583.                         /*FALLTHROUGH*/
  584.         
  585.                     copyVisStr:
  586.                         len = strlen(copy);
  587.                         if (siz > len) {
  588.                             q = strcpy(q, copy) + len;
  589.                             siz -= len;
  590.                             if (q[-1] == '\n') {
  591.                                 onScreenLen = 0;
  592.                             } else
  593.                                 onScreenLen += len;
  594.                         }
  595.                         break;
  596.         
  597.                     copyNothing:
  598.                         if (isspace(nextCh) || (nextCh == ':'))
  599.                             ++p;    /* Don't insert next character. */
  600.                         break;
  601.  
  602.                     default:
  603.                         goto copyChar; /* just copy it; unknown switch */
  604.                 }    /* end flagType */
  605.                 break;
  606.             
  607.             default:
  608.             copyChar:
  609.                 if (siz > 0) {
  610.                     *q++ = *p;
  611.                     --siz;
  612.                     ++onScreenLen;
  613.                 }
  614.                 break;
  615.         }
  616.     }
  617.     
  618. done:
  619.     *q = '\0';
  620.  
  621. #ifdef HAVE_STRFTIME
  622.     if ((nPercents > 0) && ((copy = StrDup(dst)) != NULL)) {
  623.         /* Only strftime if the user requested it (with a %something). */
  624.         (void) time(&now);
  625.         len = strlen(dst);
  626.         onScreenLen += strftime(dst, maxSize, copy, localtime(&now));
  627.         onScreenLen -= len;
  628.         free(copy);
  629.     }
  630. #endif
  631.     if (extraChar != 0)
  632.         dst[strlen(dst) + 1] = extraChar;
  633.     return (onScreenLen);
  634. }    /* FlagStrCopy */
  635.  
  636.  
  637.  
  638.  
  639. void OverflowAdd(long *dst, long plus)
  640. {
  641. #ifdef LONG_MAX
  642.     long x;
  643.  
  644.     x = LONG_MAX - *dst;
  645.     if (x < plus)
  646.         *dst = LONG_MAX;        /* Would overflow! */
  647.     else
  648.         *dst += plus;
  649. #else
  650.     *dst += plus;
  651. #endif
  652. }    /* OverflowAdd */
  653.  
  654.  
  655.  
  656.  
  657. FILE *POpen(char *cmd, char *mode, int saveScreen)
  658. {
  659.     FILE *fp;
  660.     
  661. #if 1
  662.     if ((++gWarnShellBug <= 2) && (gWinInit == 1) && (*mode == 'w') && (CURSES_SHELL_BUG == 1)) {
  663.         EPrintF("Sorry, that operation would crash the program with this OS.\n");
  664.         errno = 0;
  665.         return (NULL);
  666.     }
  667. #else
  668.     if (++gWarnShellBug == 1) {
  669.         EPrintF("Warning: the screen may not update correctly on this OS.\n\n");
  670.         sleep(2);
  671.     }
  672. #endif
  673.     if (saveScreen == 1)
  674.         SaveScreen();
  675.     fp = popen(cmd, mode);
  676.     return fp;
  677. }    /* POpen */
  678.  
  679.  
  680.  
  681.  
  682. #ifndef HAVE_MEMMOVE
  683. /* This code is derived from software contributed to Berkeley by
  684.  * Chris Torek.
  685.  */
  686.  
  687. /*
  688.  * sizeof(word) MUST BE A POWER OF TWO
  689.  * SO THAT wmask BELOW IS ALL ONES
  690.  */
  691. typedef    int word;        /* "word" used for optimal copy speed */
  692.  
  693. #define    wsize    sizeof(word)
  694. #define    wmask    (wsize - 1)
  695.  
  696. /*
  697.  * Copy a block of memory, handling overlap.
  698.  * This is the routine that actually implements
  699.  * (the portable versions of) bcopy, memcpy, and memmove.
  700.  */
  701. void *
  702. MemMove(void *dst0, void *src0, size_t length)
  703. {
  704.     register char *dst = (char *) dst0;
  705.     register const char *src = (char *) src0;
  706.     register size_t t;
  707.  
  708.     if (length == 0 || dst == src)        /* nothing to do */
  709.         return dst;
  710.  
  711.     /*
  712.      * Macros: loop-t-times; and loop-t-times, t>0
  713.      */
  714. #define    TLOOP(s) if (t) TLOOP1(s)
  715. #define    TLOOP1(s) do { s; } while (--t)
  716.  
  717.     if ((unsigned long)dst < (unsigned long)src) {
  718.         /*
  719.          * Copy forward.
  720.          */
  721.         t = (int)src;    /* only need low bits */
  722.         if ((t | (int)dst) & wmask) {
  723.             /*
  724.              * Try to align operands.  This cannot be done
  725.              * unless the low bits match.
  726.              */
  727.             if ((t ^ (int)dst) & wmask || length < wsize)
  728.                 t = length;
  729.             else
  730.                 t = wsize - (t & wmask);
  731.             length -= t;
  732.             TLOOP1(*dst++ = *src++);
  733.         }
  734.         /*
  735.          * Copy whole words, then mop up any trailing bytes.
  736.          */
  737.         t = length / wsize;
  738.         TLOOP(*(word *)dst = *(word *)src; src += wsize; dst += wsize);
  739.         t = length & wmask;
  740.         TLOOP(*dst++ = *src++);
  741.     } else {
  742.         /*
  743.          * Copy backwards.  Otherwise essentially the same.
  744.          * Alignment works as before, except that it takes
  745.          * (t&wmask) bytes to align, not wsize-(t&wmask).
  746.          */
  747.         src += length;
  748.         dst += length;
  749.         t = (int)src;
  750.         if ((t | (int)dst) & wmask) {
  751.             if ((t ^ (int)dst) & wmask || length <= wsize)
  752.                 t = length;
  753.             else
  754.                 t &= wmask;
  755.             length -= t;
  756.             TLOOP1(*--dst = *--src);
  757.         }
  758.         t = length / wsize;
  759.         TLOOP(src -= wsize; dst -= wsize; *(word *)dst = *(word *)src);
  760.         t = length & wmask;
  761.         TLOOP(*--dst = *--src);
  762.     }
  763.  
  764.     return(dst0);
  765. }    /* MemMove */
  766. #endif    /* ! HAVE_MEMMOVE */
  767.  
  768. /* eof */
  769.