home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 11 Util / 11-Util.zip / MMV-32.ZIP / MMV.C < prev    next >
C/C++ Source or Header  |  1992-10-30  |  48KB  |  2,175 lines

  1. /* 
  2.       Heavily modified by Kai Uwe Rommel for OS/2. This mostly means
  3.     removal of code not needed for OS/2 to get a cleaner source
  4.     and system dependent additions.
  5.     It can no longer be compiled for the original platforms from
  6.     this modified source code.
  7. */
  8.  
  9. /*
  10.     mmv 1.01b
  11.     Copyright (c) 1990 Vladimir Lanin.
  12.     This program may be freely used and copied on a non-commercial basis.
  13.     The author assumes no responsibility for any damage or data loss that 
  14.     may result from the use of this program.
  15.  
  16.     Author may be reached at:
  17.  
  18.     lanin@csd4.cs.nyu.edu
  19.  
  20.     Vladimir Lanin
  21.     330 Wadsworth Ave, Apt 6F,
  22.     New York, NY 10040
  23.  
  24.     Many thanks to those who have to contributed to the design
  25.     and/or coding of this program:
  26.  
  27.     Tom Albrecht:    initial Sys V adaptation, consultation, and testing
  28.     Carl Mascott:    V7 adaptation
  29.     Mark Lewis:    -n flag idea, consultation.
  30.     Dave Bernhold:    upper/lowercase conversion idea.
  31.     Paul Stodghill:    copy option, argv[0] checking.
  32.     Frank Fiamingo:    consultation and testing.
  33.     Tom Jordahl:    bug reports and testing.
  34.     John Lukas, Hugh Redelmeyer, Barry Nelson, John Sauter,
  35.     Phil Dench, John Nelson:
  36.             bug reports.
  37. */
  38.  
  39.  
  40. static char USAGE[] = "Usage: \
  41. %s [-m|x|r|c|o|a|l|s] [-h] [-d|p] [-g|t] [-v|n] [from to]\n\
  42. \n\
  43. Use =[l|u]N in the ``to'' pattern to get the [lowercase|uppercase of the]\n\
  44. string matched by the N'th ``from'' pattern wildcard.\n";
  45.  
  46. #include <stdio.h>
  47. #include <ctype.h>
  48. #include <string.h>
  49. #include <stdlib.h>
  50. #include <sys/types.h>
  51. #include <sys/stat.h>
  52. #include <io.h>
  53. #include <fcntl.h>
  54. #include <signal.h>
  55.  
  56. #define INCL_NOPM
  57. #include <os2.h>
  58.  
  59. #define ESC '\''
  60. #define SLASH '\\'
  61. #define OTHERSLASH '/'
  62.  
  63. typedef int DIRID;
  64. typedef int DEVID;
  65.  
  66. #define MAXPATH _MAX_PATH
  67. static char TTY[] = "con";
  68.  
  69.  
  70. #define mylower(c) (isupper(c) ? (c)-'A'+'a' : (c))
  71. #define myupper(c) (islower(c) ? (c)-'a'+'A' : (c))
  72. #define STRLEN(s) (sizeof(s) - 1)
  73. #define mydup(s) (strcpy((char *)challoc(strlen(s) + 1, 0), (s)))
  74.  
  75.  
  76. #define DFLT 0x001
  77. #define NORMCOPY 0x002
  78. #define OVERWRITE 0x004
  79. #define NORMMOVE 0x008
  80. #define XMOVE 0x010
  81. #define DIRMOVE 0x020
  82. #define NORMAPPEND 0x040
  83. #define ZAPPEND 0x080
  84. #define HARDLINK 0x100
  85. #define SYMLINK 0x200
  86.  
  87. #define COPY (NORMCOPY | OVERWRITE)
  88. #define MOVE (NORMMOVE | XMOVE | DIRMOVE)
  89. #define APPEND (NORMAPPEND | ZAPPEND)
  90. #define LINK (HARDLINK | SYMLINK)
  91.  
  92. static char MOVENAME[] = "mmv";
  93. static char COPYNAME[] = "mcp";
  94. static char APPENDNAME[] = "mad";
  95. static char LINKNAME[] = "mln";
  96.  
  97. #define ASKDEL 0
  98. #define ALLDEL 1
  99. #define NODEL 2
  100.  
  101. #define ASKBAD 0
  102. #define SKIPBAD 1
  103. #define ABORTBAD 2
  104.  
  105. #define STAY 0
  106. #define LOWER 1
  107. #define UPPER 2
  108.  
  109. #define MAXWILD 20
  110. #define MAXPATLEN MAXPATH
  111. #define INITROOM 10
  112. #define CHUNKSIZE 2048
  113. #define BUFSIZE 4096
  114.  
  115. #define FI_STTAKEN 0x01
  116. #define FI_LINKERR 0x02
  117. #define FI_INSTICKY 0x04
  118. #define FI_NODEL 0x08
  119. #define FI_KNOWWRITE 0x010
  120. #define FI_CANWRITE 0x20
  121. #define FI_ISDIR 0x40
  122. #define FI_ISLNK 0x80
  123.  
  124. typedef struct {
  125.     char *fi_name;
  126.     struct rep *fi_rep;
  127.     char fi_attrib;
  128. } FILEINFO;
  129.  
  130. #define DI_KNOWWRITE 0x01
  131. #define DI_CANWRITE 0x02
  132. #define DI_CLEANED 0x04
  133.  
  134. typedef struct {
  135.     DEVID di_vid;
  136.     DIRID di_did;
  137.     unsigned di_nfils;
  138.     FILEINFO **di_fils;
  139.     char di_flags;
  140. } DIRINFO;
  141.  
  142. #define H_NODIR 1
  143. #define H_NOREADDIR 2
  144.  
  145. typedef struct {
  146.     char *h_name;
  147.     DIRINFO *h_di;
  148.     char h_err;
  149. } HANDLE;
  150.  
  151. #define R_ISX 0x01
  152. #define R_SKIP 0x02
  153. #define R_DELOK 0x04
  154. #define R_ISALIASED 0x08
  155. #define R_ISCYCLE 0x10
  156. #define R_ONEDIRLINK 0x20
  157.  
  158. typedef struct rep {
  159.     HANDLE *r_hfrom;
  160.     FILEINFO *r_ffrom;
  161.     HANDLE *r_hto;
  162.     char *r_nto;            /* non-path part of new name */
  163.     FILEINFO *r_fdel;
  164.     struct rep *r_first;
  165.     struct rep *r_thendo;
  166.     struct rep *r_next;
  167.     char r_flags;
  168. } REP;
  169.  
  170. typedef struct {
  171.     REP *rd_p;
  172.     DIRINFO *rd_dto;
  173.     char *rd_nto;
  174.     unsigned rd_i;
  175. } REPDICT;
  176.  
  177. typedef struct chunk {
  178.     struct chunk *ch_next;
  179.     unsigned ch_len;
  180. } CHUNK;
  181.  
  182. typedef struct {
  183.     CHUNK *sl_first;
  184.     char *sl_unused;
  185.     int sl_len;
  186. } SLICER;
  187.  
  188.  
  189. static void init(void);
  190. static void procargs(int argc, char **argv,
  191.              char **pfrompat, char **ptopat);
  192. static void domatch(char *cfrom, char *cto);
  193. static int getpat(void);
  194. static int getword(char *buf);
  195. static void matchpat(void);
  196. static int parsepat(void);
  197. static int dostage(char *lastend, char *pathend,
  198.            char **start1, int *len1, int stage, int anylev);
  199. static int trymatch(FILEINFO *ffrom, char *pat);
  200. static int keepmatch(FILEINFO *ffrom, char *pathend,
  201.              int *pk, int needslash, int dirs, int fils);
  202. static int badrep(HANDLE *hfrom, FILEINFO *ffrom,
  203.           HANDLE **phto, char **pnto, FILEINFO **pfdel, int *pflags);
  204. static int checkto(HANDLE *hfrom, char *f,
  205.            HANDLE **phto, char **pnto, FILEINFO **pfdel);
  206. static char *getpath(char *tpath);
  207. static int badname(char *s);
  208. static FILEINFO *fsearch(char *s, DIRINFO *d);
  209. static int ffirst(char *s, int n, DIRINFO *d);
  210. static HANDLE *checkdir(char *p, char *pathend, int which);
  211. static void takedir(FILEFINDBUF3 *pff, DIRINFO *di);
  212. static int fcmp(FILEINFO **pf1, FILEINFO **pf2);
  213. static HANDLE *hadd(char *n);
  214. static int hsearch(char *n, int which, HANDLE **ph);
  215. static DIRINFO *dadd(DEVID v, DIRID d);
  216. static DIRINFO *dsearch(DEVID v, DIRID d);
  217. static int match(char *pat, char *s, char **start1, int *len1);
  218. static void makerep(void);
  219. static void checkcollisions(void);
  220. static int rdcmp(REPDICT *rd1, REPDICT *rd2);
  221. static void findorder(void);
  222. static void scandeletes(int (*pkilldel)(REP *p));
  223. static int baddel(REP *p);
  224. static int skipdel(REP *p);
  225. static void nochains(void);
  226. static void printchain(REP *p);
  227. static void goonordie(void);
  228. static void doreps(void);
  229. static long appendalias(REP *first, REP *p, int *pprintaliased);
  230. static int movealias(REP *first, REP *p, int *pprintaliased);
  231. static int snap(REP *first, REP *p);
  232. static void showdone(REP *fin);
  233. static void breakout(void);
  234. static void breakrep(void);
  235. static void breakstat(void);
  236. static void quit(void);
  237. static int copymove(REP *p);
  238. static int copy(FILEINFO *f, long len);
  239. static int myunlink(char *n, FILEINFO *f);
  240. static int getreply(char *m, int failact);
  241. static void *myalloc(unsigned k);
  242. static void *challoc(int k, int which);
  243. static void chgive(void *p, unsigned k);
  244. static int mygetc(void);
  245. static char *mygets(char *s, int l);
  246. static int leave(void);
  247. static void cleanup(void);
  248.  
  249. static int op, badstyle, delstyle, verbose, noex, matchall;
  250. static int patflags;
  251.  
  252. static unsigned ndirs = 0, dirroom;
  253. static DIRINFO **dirs;
  254. static unsigned nhandles = 0, handleroom;
  255. static HANDLE **handles;
  256. static HANDLE badhandle = {"\200", NULL, 0};
  257. static HANDLE *(lasthandle[2]) = {&badhandle, &badhandle};
  258. static unsigned nreps = 0;
  259. static REP hrep, *lastrep = &hrep;
  260. static CHUNK *freechunks = NULL;
  261. static SLICER slicer[2] = {{NULL, NULL, 0}, {NULL, NULL, 0}};
  262.  
  263. static int badreps = 0, paterr = 0, direrr, failed = 0, gotsig = 0, repbad;
  264. static FILE *outfile = stdout;
  265.  
  266. static char IDF[] = "$$mmvdid.";
  267. static char TEMP[] = "$$mmvtmp.";
  268. static char TOOLONG[] = "(too long)";
  269. static char EMPTY[] = "(empty)";
  270.  
  271. static char SLASHSTR[] = {SLASH, '\0'};
  272.  
  273. static char PATLONG[] = "%.40s... : pattern too long.\n";
  274.  
  275. char from[MAXPATLEN], to[MAXPATLEN];
  276. static int fromlen, tolen;
  277. static char *(stagel[MAXWILD]), *(firstwild[MAXWILD]), *(stager[MAXWILD]);
  278. static int nwilds[MAXWILD];
  279. static int nstages;
  280. char pathbuf[MAXPATH];
  281. char fullrep[MAXPATH + 1];
  282. static char *(start[MAXWILD]);
  283. static int len[MAXWILD];
  284. static REP mistake;
  285. #define MISTAKE (&mistake)
  286.  
  287. static int olddevflag, curdisk, maxdisk;
  288.  
  289. static struct {
  290.     char ph_banner[30];
  291.     char ph_name[9];
  292.     int ph_dfltop;
  293.     int ph_safeid;
  294.     int ph_clustoff;
  295.     int ph_driveoff;
  296.     int ph_drivea;
  297. } patch = {"mmv 1.0 patchable flags", "mmv", XMOVE, 1, 0};
  298.  
  299. #define DFLTOP (patch.ph_dfltop)
  300. #define CLUSTNO(pff) (*(int *)(((char *)(pff)) + patch.ph_clustoff))
  301. #define DRIVENO(pff) (*(((char *)(pff)) + patch.ph_driveoff) - patch.ph_drivea)
  302.  
  303. static char *home;
  304. static int homelen;
  305. static int uid, euid, oldumask;
  306.  
  307. static int dostdin = 0;
  308. static char *cmdname;
  309. #define CMDNAME cmdname
  310.  
  311.  
  312. int main(argc, argv)
  313.     int argc;
  314.     char *(argv[]);
  315. {
  316.     char *frompat, *topat;
  317.  
  318.     init();
  319.     procargs(argc, argv, &frompat, &topat);
  320.     domatch(frompat, topat);
  321.     if (!(op & APPEND))
  322.         checkcollisions();
  323.     findorder();
  324.     if (op & (COPY | LINK))
  325.         nochains();
  326.     scandeletes(baddel);
  327.     goonordie();
  328.     if (!(op & APPEND) && delstyle == ASKDEL)
  329.         scandeletes(skipdel);
  330.     doreps();
  331.     return(failed ? 2 : nreps == 0 && (paterr || badreps));
  332. }
  333.  
  334.  
  335. static void init()
  336. {
  337.         ULONG drivemap;
  338.  
  339.         DosQueryCurrentDisk(&curdisk, &drivemap);
  340.         for ( maxdisk = 0; drivemap; maxdisk++, drivemap >>= 1);
  341.  
  342.         atexit(cleanup);
  343.         signal(SIGINT, breakout);
  344.  
  345.     if ((home = getenv("HOME")) == NULL || strcmp(home, SLASHSTR) == 0)
  346.         home = "";
  347.     oldumask = umask(0);
  348.     euid = geteuid();
  349.     uid = getuid();
  350.  
  351.     dirroom = handleroom = INITROOM;
  352.     dirs = (DIRINFO **)myalloc(dirroom * sizeof(DIRINFO *));
  353.     handles = (HANDLE **)myalloc(handleroom * sizeof(HANDLE *));
  354.     ndirs = nhandles = 0;
  355. }
  356.  
  357.  
  358. static void usage()
  359. {
  360.         printf(USAGE, CMDNAME);
  361.  
  362.         printf(
  363. "\n  -m -x -r -c -o -a         (default -x)"
  364. "\n         move / move-crossdev / rename / copy / overwrite / append mode"
  365. "\n  -z     append mode with special care to ^Z (end-of-file character)\n"
  366.  
  367. "\n  -h     match . and .. and hidden or system files\n"
  368.  
  369. "\n  -d     overwrite silently existing target files"
  370. "\n  -p     do not overwrite any existing files\n"
  371.         );
  372.  
  373.         printf(
  374. "\n  -g     continue on errors with other actions"
  375. "\n  -t     abort when the first error is encountered\n"
  376.  
  377. "\n  -v     be verbose while working"
  378. "\n  -n     do not execute actions, only show them on stdout\n"
  379.  
  380. "\n  -s     read pattern pairs from stdin (not needed when redirected)\n"
  381.         );
  382.  
  383.         exit(1);
  384. }
  385.  
  386.  
  387. static void procargs(argc, argv, pfrompat, ptopat)
  388.     int argc;
  389.     char **argv;
  390.     char **pfrompat, **ptopat;
  391. {
  392.     char *p, c;
  393.  
  394.         cmdname = argv[0];
  395.  
  396.         if ( (p = strrchr(cmdname, '\\')) != NULL )
  397.           cmdname = p + 1;
  398.         else if ( (p = strrchr(cmdname, '/')) != NULL )
  399.           cmdname = p + 1;
  400.         if ( (p = strchr(cmdname, '.')) != NULL )
  401.           *p = 0;
  402.         strlwr(cmdname);
  403.  
  404.     op = DFLT;
  405.     verbose = noex = matchall = 0;
  406.     delstyle = ASKDEL;
  407.     badstyle = ASKBAD;
  408.     for (argc--, argv++; argc > 0 && **argv == '-'; argc--, argv++)
  409.         for (p = *argv + 1; *p != '\0'; p++) {
  410.             c = mylower(*p);
  411.             if (c == 'v' && !noex)
  412.                 verbose = 1;
  413.             else if (c == 'n' && !verbose)
  414.                 noex = 1;
  415.                         else if (c == 's')
  416.                                 dostdin = 1;
  417.             else if (c == 'h')
  418.                 matchall = 1;
  419.             else if (c == 'd' && delstyle == ASKDEL)
  420.                 delstyle = ALLDEL;
  421.             else if (c == 'p' && delstyle == ASKDEL)
  422.                 delstyle = NODEL;
  423.             else if (c == 'g' && badstyle == ASKBAD)
  424.                 badstyle = SKIPBAD;
  425.             else if (c == 't' && badstyle == ASKBAD)
  426.                 badstyle = ABORTBAD;
  427.             else if (c == 'm' && op == DFLT)
  428.                 op = NORMMOVE;
  429.             else if (c == 'x' && op == DFLT)
  430.                 op = XMOVE;
  431.             else if (c == 'r' && op == DFLT)
  432.                 op = DIRMOVE;
  433.             else if (c == 'c' && op == DFLT)
  434.                 op = NORMCOPY;
  435.             else if (c == 'o' && op == DFLT)
  436.                 op = OVERWRITE;
  437.             else if (c == 'a' && op == DFLT)
  438.                 op = NORMAPPEND;
  439.             else if (c == 'z' && op == DFLT)
  440.                 op = ZAPPEND;
  441.             else if (c == 'l' && op == DFLT)
  442.                 op = HARDLINK;
  443.             else if (c == 's' && op == DFLT)
  444.                 op = SYMLINK;
  445.                         else
  446.                                 usage();
  447.         }
  448.  
  449.     if (op == DFLT)
  450.         if (strcmp(cmdname, MOVENAME) == 0)
  451.             op = XMOVE;
  452.         else if (strcmp(cmdname, COPYNAME) == 0)
  453.             op = NORMCOPY;
  454.         else if (strcmp(cmdname, APPENDNAME) == 0)
  455.             op = NORMAPPEND;
  456.         else if (strcmp(cmdname, LINKNAME) == 0)
  457.             op = HARDLINK;
  458.         else
  459.             op = DFLTOP;
  460.  
  461.     if (badstyle != ASKBAD && delstyle == ASKDEL)
  462.         delstyle = NODEL;
  463.  
  464.     if (argc == 0)
  465.         *pfrompat = NULL;
  466.     else if (argc == 2) {
  467.         *pfrompat = *(argv++);
  468.         *ptopat = *(argv++);
  469.     }
  470.         else
  471.                 usage();
  472. }
  473.  
  474.  
  475. static void domatch(cfrom, cto)
  476.     char *cfrom, *cto;
  477. {
  478.     if (cfrom == NULL)
  479.         {
  480.                 if ( dostdin || !isatty(fileno(stdin)) )
  481.         while (getpat())
  482.             matchpat();
  483.                 else
  484.                         usage();
  485.         }
  486.     else if ((fromlen = strlen(cfrom)) >= MAXPATLEN) {
  487.         printf(PATLONG, cfrom);
  488.         paterr = 1;
  489.     }
  490.     else if ((tolen = strlen(cto)) >= MAXPATLEN) {
  491.         printf(PATLONG, cto);
  492.         paterr = 1;
  493.     }
  494.     else {
  495.         strcpy(from, cfrom);
  496.         strcpy(to, cto);
  497.         matchpat();
  498.     }
  499. }
  500.  
  501.  
  502. static int getpat()
  503. {
  504.     int c, gotit = 0;
  505.     char extra[MAXPATLEN];
  506.  
  507.     patflags = 0;
  508.     do {
  509.         if ((fromlen = getword(from)) == 0 || fromlen == -1)
  510.             goto nextline;
  511.  
  512.         do {
  513.             if ((tolen = getword(to)) == 0) {
  514.                 printf("%s -> ? : missing replacement pattern.\n", from);
  515.                 goto nextline;
  516.             }
  517.             if (tolen == -1)
  518.                 goto nextline;
  519.         } while (
  520.             tolen == 2 &&
  521.             (to[0] == '-' || to[0] == '=') &&
  522.             (to[1] == '>' || to[1] == '^')
  523.         );
  524.         if (getword(extra) == 0)
  525.             gotit = 1;
  526.         else if (strcmp(extra, "(*)") == 0) {
  527.             patflags |= R_DELOK;
  528.             gotit = (getword(extra) == 0);
  529.         }
  530.  
  531. nextline:
  532.         while ((c = mygetc()) != '\n' && c != EOF)
  533.             ;
  534.         if (c == EOF)
  535.             return(0);
  536.     } while (!gotit);
  537.  
  538.     return(1);
  539. }
  540.  
  541.  
  542. static int getword(buf)
  543.     char *buf;
  544. {
  545.     int c, prevc, n;
  546.     char *p;
  547.  
  548.     p = buf;
  549.     prevc = ' ';
  550.     n = 0;
  551.     while ((c = mygetc()) != EOF && (prevc == ESC || !isspace(c))) {
  552.         if (n == -1)
  553.             continue;
  554.         if (n == MAXPATLEN - 1) {
  555.             *p = '\0';
  556.             printf(PATLONG, buf);
  557.             n = -1;
  558.         }
  559.         *(p++) = c;
  560.         n++;
  561.         prevc = c;
  562.     }
  563.     *p = '\0';
  564.     while (c != EOF && isspace(c) && c != '\n')
  565.         c = mygetc();
  566.     if (c != EOF)
  567.         ungetc(c, stdin);
  568.     return(n);
  569. }
  570.  
  571.  
  572. static void matchpat()
  573. {
  574.     if (parsepat())
  575.         paterr = 1;
  576.     else if (dostage(from, pathbuf, start, len, 0, 0)) {
  577.         printf("%s -> %s : no match.\n", from, to);
  578.         paterr = 1;
  579.     }
  580. }
  581.  
  582.  
  583. static int parsepat()
  584. {
  585.     char *p, *lastname, c;
  586.     int totwilds, instage, x;
  587.     static char TRAILESC[] = "%s -> %s : trailing %c is superfluous.\n";
  588.  
  589.     lastname = from;
  590.     if (from[0] != '\0' && from[1] == ':')
  591.         lastname += 2;
  592.     if (from[0] == '~' && from[1] == SLASH) {
  593.         if ((homelen = strlen(home)) + fromlen > MAXPATLEN) {
  594.             printf(PATLONG, from);
  595.             return(-1);
  596.         }
  597.         memmove(from + homelen, from + 1, fromlen);
  598.         memmove(from, home, homelen);
  599.         lastname += homelen + 1;
  600.     }
  601.  
  602.     totwilds = nstages = instage = 0;
  603.     for (p = lastname; (c = *p) != '\0'; p++)
  604.         switch (c) {
  605.         case OTHERSLASH:
  606.             *p = SLASH;
  607.          case SLASH:
  608.             lastname = p + 1;
  609.             if (instage) {
  610.                 if (firstwild[nstages] == NULL)
  611.                     firstwild[nstages] = p;
  612.                 stager[nstages++] = p;
  613.                 instage = 0;
  614.             }
  615.             break;
  616.         case ';':
  617.             if (lastname != p) {
  618.                 printf("%s -> %s : badly placed ;.\n", from, to);
  619.                 return(-1);
  620.             }
  621.         case '!':
  622.         case '*':
  623.         case '?':
  624.         case '[':
  625.             if (totwilds++ == MAXWILD) {
  626.                 printf("%s -> %s : too many wildcards.\n", from, to);
  627.                 return(-1);
  628.             }
  629.             if (instage) {
  630.                 nwilds[nstages]++;
  631.                 if (firstwild[nstages] == NULL)
  632.                     firstwild[nstages] = p;
  633.             }
  634.             else {
  635.                 stagel[nstages] = lastname;
  636.                 firstwild[nstages] = (c == ';' ? NULL : p);
  637.                 nwilds[nstages] = 1;
  638.                 instage = 1;
  639.             }
  640.             if (c != '[')
  641.                 break;
  642.             while ((c = *(++p)) != ']') {
  643.                 switch (c) {
  644.                 case '\0':
  645.                     printf("%s -> %s : missing ].\n", from, to);
  646.                     return(-1);
  647.                 case ':':
  648.                 case OTHERSLASH:
  649.                 case SLASH:
  650.                     printf("%s -> %s : '%c' can not be part of [].\n",
  651.                         from, to, c);
  652.                     return(-1);
  653.                 case ESC:
  654.                     if ((c = *(++p)) == '\0') {
  655.                         printf(TRAILESC, from, to, ESC);
  656.                         return(-1);
  657.                     }
  658.                 }
  659.             }
  660.             break;
  661.         case ESC:
  662.             if ((c = *(++p)) == '\0') {
  663.                 printf(TRAILESC, from, to, ESC);
  664.                 return(-1);
  665.             }
  666.         }
  667.  
  668.     if (instage) {
  669.         if (firstwild[nstages] == NULL)
  670.             firstwild[nstages] = p;
  671.         stager[nstages++] = p;
  672.     }
  673.     else {
  674.         stagel[nstages] = lastname;
  675.         nwilds[nstages] = 0;
  676.         firstwild[nstages] = p;
  677.         stager[nstages++] = p;
  678.     }
  679.  
  680.     lastname = to;
  681.     if (to[0] != '\0' && to[1] == ':')
  682.         lastname += 2;
  683.  
  684.     if (to[0] == '~' && to[1] == SLASH) {
  685.         if ((homelen = strlen(home)) + tolen > MAXPATLEN) {
  686.             printf(PATLONG, to);
  687.                 return(-1);
  688.         }
  689.         memmove(to + homelen, to + 1, tolen);
  690.         memmove(to, home, homelen);
  691.         lastname += homelen + 1;
  692.     }
  693.  
  694.     for (p = lastname; (c = *p) != '\0'; p++)
  695.         switch (c) {
  696.         case OTHERSLASH:
  697.             *p = SLASH;
  698.         case SLASH:
  699.             if (op & DIRMOVE) {
  700.                 printf("%s -> %s : no path allowed in target under -r.\n",
  701.                     from, to);
  702.                 return(-1);
  703.             }
  704.             lastname = p + 1;
  705.             break;
  706.         case '=':
  707.             c = *(++p);
  708.             if (c == 'l' || c == 'u') {
  709.                 c = *(++p);
  710.             }
  711.             if (!isdigit(c)) {
  712.                 printf("%s -> %s : expected digit (not '%c') after =.\n",
  713.                     from, to, c);
  714.                 return(-1);
  715.             }
  716.             for(x = 0; ;x *= 10) {
  717.                 x += c - '0';
  718.                 c = *(p+1);
  719.                 if (!isdigit(c))
  720.                     break;
  721.                 p++;
  722.             }
  723.             if (x < 1 || x > totwilds) {
  724.                 printf("%s -> %s : wildcard %d does not exist.\n",
  725.                     from, to, x);
  726.                 return(-1);
  727.             }
  728.             break;
  729.         case ESC:
  730.             if ((c = *(++p)) == '\0') {
  731.                 printf(TRAILESC, from, to, ESC);
  732.                 return(-1);
  733.             }
  734.         default:
  735.             if (c <= ' ' || c == 127 || c == 255) {
  736.                 printf("%s -> %s : illegal character '%c' (0x%02X).\n",
  737.                     from, to, c, c);
  738.                 return(-1);
  739.             }
  740.         }
  741.  
  742.     return(0);
  743. }
  744.  
  745.  
  746. static int dostage(lastend, pathend, start1, len1, stage, anylev)
  747.     char *lastend, *pathend;
  748.     char **start1;
  749.     int *len1;
  750.     int stage;
  751.     int anylev;
  752. {
  753.     DIRINFO *di;
  754.     HANDLE *h, *hto;
  755.     int prelen, litlen, nfils, i, k, flags, try;
  756.     FILEINFO **pf, *fdel;
  757.     char *nto, *firstesc;
  758.     REP *p;
  759.     int wantdirs, ret = 1, laststage = (stage + 1 == nstages);
  760.  
  761.     wantdirs = !laststage ||
  762.         (op & (DIRMOVE | SYMLINK)) ||
  763.         (nwilds[nstages - 1] == 0);
  764.  
  765.     if (!anylev) {
  766.         prelen = stagel[stage] - lastend;
  767.         if (pathend - pathbuf + prelen >= MAXPATH) {
  768.             printf("%s -> %s : search path after %s too long.\n",
  769.                 from, to, pathbuf);
  770.             paterr = 1;
  771.             return(1);
  772.         }
  773.         memmove(pathend, lastend, prelen);
  774.         pathend += prelen;
  775.         *pathend = '\0';
  776.         lastend = stagel[stage];
  777.     }
  778.  
  779.     if ((h = checkdir(pathbuf, pathend, 0)) == NULL) {
  780.         if (stage == 0 || direrr == H_NOREADDIR) {
  781.             printf("%s -> %s : directory %s does not %s.\n",
  782.                 from, to, pathbuf, direrr == H_NOREADDIR ?
  783.                 "allow reads/searches" : "exist");
  784.             paterr = 1;
  785.         }
  786.         return(stage);
  787.     }
  788.     di = h->h_di;
  789.  
  790.     if (*lastend == ';') {
  791.         anylev = 1;
  792.         *start1 = pathend;
  793.         *len1 = 0;
  794.         lastend++;
  795.     }
  796.  
  797.     nfils = di->di_nfils;
  798.  
  799.     firstesc = strchr(lastend, ESC);
  800.     if (firstesc == NULL || firstesc > firstwild[stage])
  801.         firstesc = firstwild[stage];
  802.     litlen = firstesc - lastend;
  803.     pf = di->di_fils + (i = ffirst(lastend, litlen, di));
  804.     if (i < nfils)
  805.     do {
  806.         if (
  807.             (try = trymatch(*pf, lastend)) != 0 &&
  808.             (
  809.                 try == 1 ||
  810.                 match(lastend + litlen, (*pf)->fi_name + litlen,
  811.                     start1 + anylev, len1 + anylev)
  812.             ) &&
  813.             keepmatch(*pf, pathend, &k, 0, wantdirs, laststage)
  814.         ) {
  815.             if (!laststage)
  816.                 ret &= dostage(stager[stage], pathend + k,
  817.                     start1 + nwilds[stage], len1 + nwilds[stage],
  818.                     stage + 1, 0);
  819.             else {
  820.                 ret = 0;
  821.                 makerep();
  822.                 if (badrep(h, *pf, &hto, &nto, &fdel, &flags))
  823.                     (*pf)->fi_rep = MISTAKE;
  824.                 else {
  825.                     (*pf)->fi_rep = p = (REP *)challoc(sizeof(REP), 1);
  826.                     p->r_flags = flags | patflags;
  827.                     p->r_hfrom = h;
  828.                     p->r_ffrom = *pf;
  829.                     p->r_hto = hto;
  830.                     p->r_nto = nto;
  831.                     p->r_fdel = fdel;
  832.                     p->r_first = p;
  833.                     p->r_thendo = NULL;
  834.                     p->r_next = NULL;
  835.                     lastrep->r_next = p;
  836.                     lastrep = p;
  837.                     nreps++;
  838.                 }
  839.             }
  840.         }
  841.         i++, pf++;
  842.     } while (i < nfils && strncmp(lastend, (*pf)->fi_name, litlen) == 0);
  843.  
  844. skiplev:
  845.     if (anylev)
  846.         for (pf = di->di_fils, i = 0; i < nfils; i++, pf++)
  847.             if (
  848.                 *((*pf)->fi_name) != '.' &&
  849.                                 ((*pf)->fi_attrib & FILE_DIRECTORY) &&
  850.                 keepmatch(*pf, pathend, &k, 1, 1, 0)
  851.             ) {
  852.                 *len1 = pathend - *start1 + k;
  853.                 ret &= dostage(lastend, pathend + k, start1, len1, stage, 1);
  854.             }
  855.  
  856.     return(ret);
  857. }
  858.  
  859.  
  860. static int trymatch(ffrom, pat)
  861.     FILEINFO *ffrom;
  862.     char *pat;
  863. {
  864.     char *p;
  865.  
  866.     if (ffrom->fi_rep != NULL)
  867.         return(0);
  868.     p = ffrom->fi_name;
  869.     if (*p == '.')
  870.         if (p[1] == '\0' || (p[1] == '.' && p[2] == '\0'))
  871.             return(strcmp(pat, p) == 0);
  872.         else if (!matchall && ffrom->fi_attrib & (FILE_HIDDEN | FILE_SYSTEM))
  873.         return(strcmp(pat, p) == 0);
  874.  
  875.     return(-1);
  876. }
  877.  
  878.  
  879. static int keepmatch(ffrom, pathend, pk, needslash, dirs, fils)
  880.     FILEINFO *ffrom;
  881.     char *pathend;
  882.     int *pk;
  883.     int needslash;
  884.     int dirs, fils;
  885. {
  886.     *pk = strlen(ffrom->fi_name);
  887.     if (pathend - pathbuf + *pk + needslash >= MAXPATH) {
  888.         *pathend = '\0';
  889.         printf("%s -> %s : search path %s%s too long.\n",
  890.             from, to, pathbuf, ffrom->fi_name);
  891.         paterr = 1;
  892.         return(0);
  893.     }
  894.     strcpy(pathend, ffrom->fi_name);
  895.         if ((ffrom->fi_attrib & FILE_DIRECTORY) ? !dirs : !fils)
  896.         return(0);
  897.     if (needslash) {
  898.         strcpy(pathend + *pk, SLASHSTR);
  899.         (*pk)++;
  900.     }
  901.     return(1);
  902. }
  903.  
  904.  
  905. static int badrep(hfrom, ffrom, phto, pnto, pfdel, pflags)
  906.     HANDLE *hfrom;
  907.     FILEINFO *ffrom;
  908.     HANDLE **phto;
  909.     char **pnto;
  910.     FILEINFO **pfdel;
  911.     int *pflags;
  912. {
  913.     char *f = ffrom->fi_name;
  914.  
  915.     *pflags = 0;
  916.     if (    (ffrom->fi_attrib & FILE_DIRECTORY) &&
  917.         !(op & (DIRMOVE | SYMLINK)))
  918.         printf("%s -> %s : source file is a directory.\n", pathbuf, fullrep);
  919.     else if ((op & (COPY | APPEND)) && access(pathbuf, R_OK))
  920.         printf("%s -> %s : no read permission for source file.\n",
  921.             pathbuf, fullrep);
  922.     else if (
  923.         *f == '.' &&
  924.         (f[1] == '\0' || strcmp(f, "..") == 0) &&
  925.         !(op & SYMLINK)
  926.     )
  927.         printf("%s -> %s : . and .. can't be renamed.\n", pathbuf, fullrep);
  928.     else if (repbad || checkto(hfrom, f, phto, pnto, pfdel) || badname(*pnto))
  929.         printf("%s -> %s : bad new name.\n", pathbuf, fullrep);
  930.     else if (*phto == NULL)
  931.         printf("%s -> %s : %s.\n", pathbuf, fullrep,
  932.             direrr == H_NOREADDIR ?
  933.             "no read or search permission for target directory" :
  934.             "target directory does not exist");
  935.     else if (
  936.         (*phto)->h_di->di_vid != hfrom->h_di->di_vid &&
  937.         (*pflags = R_ISX, (op & (NORMMOVE | HARDLINK)))
  938.     )
  939.         printf("%s -> %s : cross-device move.\n",
  940.             pathbuf, fullrep);
  941.     else if (*pflags && (op & MOVE) && access(pathbuf, R_OK))
  942.         printf("%s -> %s : no read permission for source file.\n",
  943.             pathbuf, fullrep);
  944.     else if ((op & SYMLINK) &&
  945.         !(
  946.             *(hfrom->h_name) == SLASH ||
  947.             (*pflags |= R_ONEDIRLINK, hfrom->h_di == (*phto)->h_di)
  948.         )
  949.     )
  950.         printf("%s -> %s : symbolic link would be badly aimed.\n",
  951.             pathbuf, fullrep);
  952.     else
  953.         return(0);
  954.     badreps++;
  955.     return(-1);
  956. }
  957.  
  958.  
  959. static int checkto(hfrom, f, phto, pnto, pfdel)
  960.     HANDLE *hfrom;
  961.     char *f;
  962.     HANDLE **phto;
  963.     char **pnto;
  964.     FILEINFO **pfdel;
  965. {
  966.     char tpath[MAXPATH + 1];
  967.     char *pathend;
  968.     FILEINFO *fdel;
  969.     int hlen, tlen;
  970.  
  971.     if (op & DIRMOVE) {
  972.         *phto = hfrom;
  973.         hlen = strlen(hfrom->h_name);
  974.         pathend = fullrep + hlen;
  975.         memmove(pathend, fullrep, strlen(fullrep) + 1);
  976.         memmove(fullrep, hfrom->h_name, hlen);
  977.         if ((fdel = *pfdel = fsearch(pathend, hfrom->h_di)) != NULL) {
  978.             *pnto = fdel->fi_name;
  979.         }
  980.         else
  981.             *pnto = mydup(pathend);
  982.     }
  983.     else {
  984.         pathend = getpath(tpath);
  985.         hlen = pathend - fullrep;
  986.         *phto = checkdir(tpath, tpath + hlen, 1);
  987.         if (
  988.             *phto != NULL &&
  989.             *pathend != '\0' &&
  990.             (fdel = *pfdel = fsearch(pathend, (*phto)->h_di)) != NULL &&
  991.                         (fdel->fi_attrib & FILE_DIRECTORY)
  992.         ) {
  993.             tlen = strlen(pathend);
  994.             strcpy(pathend + tlen, SLASHSTR);
  995.             tlen++;
  996.             strcpy(tpath + hlen, pathend);
  997.             pathend += tlen;
  998.             hlen += tlen;
  999.             *phto = checkdir(tpath, tpath + hlen, 1);
  1000.         }
  1001.  
  1002.         if (*pathend == '\0') {
  1003.             *pnto = f;
  1004.             if (pathend - fullrep + strlen(f) >= MAXPATH) {
  1005.                 strcpy(fullrep, TOOLONG);
  1006.                 return(-1);
  1007.             }
  1008.             strcat(pathend, f);
  1009.             if (*phto != NULL) {
  1010.                 fdel = *pfdel = fsearch(f, (*phto)->h_di);
  1011.             }
  1012.         }
  1013.         else if (fdel != NULL)
  1014.             *pnto = fdel->fi_name;
  1015.         else
  1016.             *pnto = mydup(pathend);
  1017.     }
  1018.     return(0);
  1019. }
  1020.  
  1021.  
  1022. static char *getpath(tpath)
  1023.     char *tpath;
  1024. {
  1025.     char *pathstart, *pathend, c;
  1026.  
  1027.     if (*fullrep != '\0' && fullrep[1] == ':')
  1028.         pathstart = fullrep + 2;
  1029.     else
  1030.         pathstart = fullrep;
  1031.  
  1032.     pathend = pathstart + strlen(pathstart) - 1;
  1033.     while (pathend >= pathstart && *pathend != SLASH)
  1034.         --pathend;
  1035.     pathend++;
  1036.  
  1037.     c = *pathend;
  1038.     *pathend = '\0';
  1039.     strcpy(tpath, fullrep);
  1040.     *pathend = c;
  1041.     return(pathend);
  1042. }
  1043.  
  1044.  
  1045. static int badname(s)
  1046.     char *s;
  1047. {
  1048.     char *ext;
  1049.  
  1050.     return ((*s == '.' && (s[1] == '\0' || strcmp(s, "..") == 0)) ||
  1051.         strlen(s) > MAXPATH || strncmp(s, IDF, STRLEN(IDF)) == 0);
  1052. }
  1053.  
  1054.  
  1055. static FILEINFO *fsearch(s, d)
  1056.     char *s;
  1057.     DIRINFO *d;
  1058. {
  1059.     FILEINFO **fils = d->di_fils;
  1060.     int nfils = d->di_nfils;
  1061.     int first, k, last, res;
  1062.  
  1063.     for(first = 0, last = nfils - 1;;) {
  1064.         if (last < first)
  1065.             return(NULL);
  1066.         k = (first + last) >> 1;
  1067.         if ((res = strcmp(s, fils[k]->fi_name)) == 0)
  1068.             return(fils[k]);
  1069.         if (res < 0)
  1070.             last = k - 1;
  1071.         else
  1072.             first = k + 1;
  1073.     }
  1074. }
  1075.  
  1076.  
  1077. static int ffirst(s, n, d)
  1078.     char *s;
  1079.     int n;
  1080.     DIRINFO *d;
  1081. {
  1082.     int first, k, last, res;
  1083.     FILEINFO **fils = d->di_fils;
  1084.     int nfils = d->di_nfils;
  1085.  
  1086.     if (nfils == 0 || n == 0)
  1087.         return(0);
  1088.     first = 0;
  1089.     last = nfils - 1;
  1090.     for(;;) {
  1091.         k = (first + last) >> 1;
  1092.         res = strncmp(s, fils[k]->fi_name, n);
  1093.         if (first == last)
  1094.             return(res == 0 ? k : nfils);
  1095.         else if (res > 0)
  1096.             first = k + 1;
  1097.         else
  1098.             last = k;
  1099.     }
  1100. }
  1101.  
  1102.  
  1103. static HDIR hdir;
  1104. static ULONG count;
  1105.  
  1106. static HANDLE *checkdir(p, pathend, which)
  1107.     char *p, *pathend;
  1108.     int which;
  1109. {
  1110.         FILEFINDBUF3 de;
  1111.     DIRID d;
  1112.     DEVID v;
  1113.     HANDLE *h;
  1114.     char *dirstart = p;
  1115.     int fd;
  1116.     int firstfound;
  1117.     DIRINFO *di;
  1118.  
  1119.     if (hsearch(p, which, &h))
  1120.         if (h->h_di == NULL) {
  1121.             direrr = h->h_err;
  1122.             return(NULL);
  1123.         }
  1124.         else
  1125.             return(h);
  1126.  
  1127.     if (*p == '\0' || p[1] != ':')
  1128.         v = curdisk;
  1129.     else {
  1130.         dirstart += 2;
  1131.         v = mylower(p[0]) - 'a';
  1132.         if (v < 0 || v >= maxdisk)
  1133.             return(NULL);
  1134.     }
  1135.  
  1136.     if (patch.ph_safeid) {
  1137.         strcpy(pathend, IDF);
  1138.         strcpy(pathend + STRLEN(IDF), "*");
  1139.                 hdir = HDIR_SYSTEM;
  1140.         count = 1;
  1141.                 if (DosFindFirst(p, &hdir, 0, &de, sizeof(de), &count, 1)) {
  1142.             if ((d = ndirs) == 1000) {
  1143.                 fprintf(stderr, "Too many different directories.\n");
  1144.                 quit();
  1145.             }
  1146.             sprintf(pathend + STRLEN(IDF), "%03d", d);
  1147.                         if ((fd = creat(p, S_IREAD | S_IWRITE)) < 0) {
  1148.                 direrr = h->h_err = H_NODIR;
  1149.                 return(NULL);
  1150.             }
  1151.                         close(fd);
  1152.             strcpy(pathend, "*");
  1153.             hdir = HDIR_SYSTEM;
  1154.                         count = 1;
  1155.                         if (DosFindFirst(p, &hdir, 
  1156.                    FILE_DIRECTORY | FILE_SYSTEM | FILE_HIDDEN, 
  1157.                    &de, sizeof(de), &count, 1))
  1158.                 h->h_di = dadd(v, d);
  1159.             else
  1160.                 takedir(&de, h->h_di = dadd(v, d));
  1161.         }
  1162.                 else if ((d = atoi(de.achName + STRLEN(IDF))) < ndirs)
  1163.             h->h_di = dirs[d];
  1164.         else {
  1165.                         strcpy(pathend, de.achName);
  1166.             fprintf(stderr, "Strange dir-id file encountered: %s.\n", p);
  1167.             quit();
  1168.         }
  1169.         *pathend = '\0';
  1170.     }
  1171.     else {
  1172.         strcpy(pathend, "*");
  1173.                 hdir = HDIR_SYSTEM;
  1174.                 count = 1;
  1175.                 firstfound = !DosFindFirst(p, &hdir, 
  1176.                          FILE_DIRECTORY | FILE_SYSTEM | FILE_HIDDEN, 
  1177.                  &de, sizeof(de), &count, 1);
  1178.         *pathend = '\0';
  1179.         if (firstfound) {
  1180.             v = DRIVENO(&de);
  1181.             d = CLUSTNO(&de);
  1182.         }
  1183.         else {
  1184.             strcpy(pathend, "T.D");
  1185.             if (mkdir(p)) {
  1186.                 *pathend = '\0';
  1187.                 direrr = h->h_err = H_NODIR;
  1188.                 return(NULL);
  1189.             }
  1190.             strcpy(pathend, "*");
  1191.             hdir = HDIR_SYSTEM;
  1192.                         count = 1;
  1193.                         firstfound = !DosFindFirst(p, &hdir, 
  1194.                    FILE_DIRECTORY | FILE_SYSTEM | FILE_HIDDEN, 
  1195.                    &de, sizeof(de), &count, 1);
  1196.             *pathend = '\0';
  1197.             v = DRIVENO(&de);
  1198.             d = CLUSTNO(&de);
  1199.             rmdir(p);
  1200.             if (!firstfound || d != 0) {
  1201.                 fprintf(stderr,
  1202.                     "Strange, %s does not seem to be a root dir.\n",
  1203.                     p);
  1204.                 quit();
  1205.             }
  1206.         }
  1207.  
  1208.         if ((di = dsearch(v, d)) == NULL)
  1209.             if (firstfound)
  1210.                 takedir(&de, h->h_di = dadd(v, d));
  1211.             else
  1212.                 h->h_di = dadd(v, d);
  1213.         else
  1214.             h->h_di = di;
  1215.     }
  1216.  
  1217.     return(h);
  1218. }
  1219.  
  1220.  
  1221. static void takedir(pff, di)
  1222.         FILEFINDBUF3 *pff;
  1223.     DIRINFO *di;
  1224. {
  1225.     int cnt, room;
  1226.     FILEINFO **fils, *f;
  1227.     char c, *p, *p1;
  1228.  
  1229.     room = INITROOM;
  1230.     di->di_fils = fils = (FILEINFO **)myalloc(room * sizeof(FILEINFO *));
  1231.     cnt = 0;
  1232.     do {
  1233.                 if (strnicmp(pff->achName, IDF, STRLEN(IDF)) == 0)
  1234.             continue;
  1235.         if (cnt == room) {
  1236.             room *= 2;
  1237.             fils = (FILEINFO **)myalloc(room * sizeof(FILEINFO *));
  1238.             memcpy(fils, di->di_fils, cnt * sizeof(FILEINFO *));
  1239.             chgive(di->di_fils, cnt * sizeof(FILEINFO *));
  1240.             di->di_fils = fils;
  1241.             fils = di->di_fils + cnt;
  1242.         }
  1243.         *fils = f = (FILEINFO *)challoc(sizeof(FILEINFO), 1);
  1244.         f->fi_name = p = (char *)challoc(pff->cchName + 1, 0);
  1245.         strcpy(p, pff->achName);
  1246.                 f->fi_attrib = (char) pff->attrFile;
  1247.         f->fi_rep = NULL;
  1248.         cnt++;
  1249.         fils++;
  1250.         } while (DosFindNext(hdir, pff, sizeof(*pff), &count) == 0);
  1251.     qsort(di->di_fils, cnt, sizeof(FILEINFO *), fcmp);
  1252.     di->di_nfils = cnt;
  1253. }
  1254.  
  1255.  
  1256. static int fcmp(pf1, pf2)
  1257.     FILEINFO **pf1, **pf2;
  1258. {
  1259.         return(strcmp((*pf1)->fi_name, (*pf2)->fi_name));
  1260. }
  1261.  
  1262.  
  1263. static HANDLE *hadd(n)
  1264.     char *n;
  1265. {
  1266.     HANDLE **newhandles, *h;
  1267.  
  1268.     if (nhandles == handleroom) {
  1269.         handleroom *= 2;
  1270.         newhandles = (HANDLE **)myalloc(handleroom * sizeof(HANDLE *));
  1271.         memcpy(newhandles, handles, nhandles * sizeof(HANDLE *));
  1272.         chgive(handles, nhandles * sizeof(HANDLE *));
  1273.         handles = newhandles;
  1274.     }
  1275.     handles[nhandles++] = h = (HANDLE *)challoc(sizeof(HANDLE), 1);
  1276.     h->h_name = (char *)challoc(strlen(n) + 1, 0);
  1277.     strcpy(h->h_name, n);
  1278.     h->h_di = NULL;
  1279.     return(h);
  1280. }
  1281.  
  1282.  
  1283. static int hsearch(n, which, pret)
  1284.     char *n;
  1285.     int which;
  1286.     HANDLE **pret;
  1287. {
  1288.     int i;
  1289.     HANDLE **ph;
  1290.  
  1291.     if (strcmp(n, lasthandle[which]->h_name) == 0) {
  1292.         *pret = lasthandle[which];
  1293.         return(1);
  1294.     }
  1295.  
  1296.     for(i = 0, ph = handles; i < nhandles; i++, ph++)
  1297.         if (strcmp(n, (*ph)->h_name) == 0) {
  1298.             lasthandle[which] = *pret = *ph;
  1299.             return(1);
  1300.         }
  1301.  
  1302.     lasthandle[which] = *pret = hadd(n);
  1303.     return(0);
  1304. }
  1305.  
  1306.  
  1307. static DIRINFO *dadd(v, d)
  1308.     DEVID v;
  1309.     DIRID d;
  1310. {
  1311.     DIRINFO *di;
  1312.     DIRINFO **newdirs;
  1313.  
  1314.     if (ndirs == dirroom) {
  1315.         dirroom *= 2;
  1316.         newdirs = (DIRINFO **)myalloc(dirroom * sizeof(DIRINFO *));
  1317.         memcpy(newdirs, dirs, ndirs * sizeof(DIRINFO *));
  1318.         chgive(dirs, ndirs * sizeof(DIRINFO *));
  1319.         dirs = newdirs;
  1320.     }
  1321.     dirs[ndirs++] = di = (DIRINFO *)challoc(sizeof(DIRINFO), 1);
  1322.     di->di_vid = v;
  1323.     di->di_did = d;
  1324.     di->di_nfils = 0;
  1325.     di->di_fils = NULL;
  1326.     di->di_flags = 0;
  1327.     return(di);
  1328. }
  1329.  
  1330.  
  1331. static DIRINFO *dsearch(v, d)
  1332.     DEVID v;
  1333.     DIRID d;
  1334. {
  1335.     int i;
  1336.     DIRINFO *di;
  1337.  
  1338.     for(i = 0, di = *dirs; i < ndirs; i++, di++)
  1339.         if (v == di->di_vid && d == di->di_did)
  1340.             return(di);
  1341.     return(NULL);
  1342. }
  1343.  
  1344.  
  1345. static int match(pat, s, start1, len1)
  1346.     char *pat, *s, **start1;
  1347.     int *len1;
  1348. {
  1349.     char c, *olds;
  1350.  
  1351.     *start1 = 0;
  1352.     for(;;)
  1353.         switch (c = *pat) {
  1354.         case '\0':
  1355.         case SLASH:
  1356.             return(*s == '\0');
  1357.         case '*':
  1358.             *start1 = s;
  1359.             if ((c = *(++pat)) == '\0') {
  1360.                 *len1 = strlen(s);
  1361.                 return(1);
  1362.             }
  1363.             else {
  1364.                 for (*len1=0; !match(pat, s, start1+1, len1+1); (*len1)++, s++)
  1365.                     if (*s == '\0')
  1366.                         return(0);
  1367.                 return(1);
  1368.             }
  1369.         case '?':
  1370.             if (*s == '\0')
  1371.                 return(0);
  1372.             *(start1++) = s;
  1373.             *(len1++) = 1;
  1374.             pat++;
  1375.             s++;
  1376.             break;
  1377.         case '[':
  1378.             {
  1379.                 int matched = 0, notin = 0, inrange = 0;
  1380.                 char prevc = '\0';
  1381.  
  1382.                 if ((c = *(++pat)) == '^') {
  1383.                     notin = 1;
  1384.                     c = *(++pat);
  1385.                 }
  1386.                 while (c != ']') {
  1387.                     if (c == '-' && !inrange)
  1388.                         inrange = 1;
  1389.                     else {
  1390.                         if (c == ESC) {
  1391.                             c = *(++pat);
  1392.                         }
  1393.                         if (inrange) {
  1394.                             if (*s >= prevc && *s <= c)
  1395.                                 matched = 1;
  1396.                             inrange = 0;
  1397.                         }
  1398.                         else if (c == *s)
  1399.                             matched = 1;
  1400.                         prevc = c;
  1401.                     }
  1402.                     c = *(++pat);
  1403.                 }
  1404.                 if (inrange && *s >= prevc)
  1405.                     matched = 1;
  1406.                 if (!(matched ^ notin))
  1407.                     return(0);
  1408.                 *(start1++) = s;
  1409.                 *(len1++) = 1;
  1410.                 pat++;
  1411.                 s++;
  1412.             }
  1413.             break;
  1414.         case ESC:
  1415.             c = *(++pat);
  1416.         default:
  1417.             if (c == *s) {
  1418.                  pat++;
  1419.                 s++;
  1420.             }
  1421.             else
  1422.                 return(0);
  1423.         }
  1424. }
  1425.  
  1426.  
  1427. static void makerep()
  1428. {
  1429.     int l, x;
  1430.     int i, cnv;
  1431.     char *q;
  1432.     char *p, *pat, c, pc;
  1433.  
  1434.     repbad = 0;
  1435.     p = fullrep;
  1436.     for (pat = to, l = 0; (c = *pat) != '\0'; pat++, l++) {
  1437.         if (c == '=') {
  1438.             c = *(++pat);
  1439.             if (c == 'l') {
  1440.                 cnv = LOWER;
  1441.                 c = *(++pat);
  1442.             }
  1443.             else if (c == 'u') {
  1444.                 cnv = UPPER;
  1445.                 c = *(++pat);
  1446.             }
  1447.             else
  1448.                 cnv = STAY;
  1449.             for(x = 0; ;x *= 10) {
  1450.                 x += c - '0';
  1451.                 c = *(pat+1);
  1452.                 if (!isdigit(c))
  1453.                     break;
  1454.                 pat++;
  1455.             }
  1456.             --x;
  1457.             if (l + len[x] >= MAXPATH)
  1458.                 goto toolong;
  1459.             switch (cnv) {
  1460.             case STAY:
  1461.                 memmove(p, start[x], len[x]);
  1462.                 p += len[x];
  1463.                 break;
  1464.             case LOWER:
  1465.                 for (i = len[x], q = start[x]; i > 0; i--, p++, q++)
  1466.                     *p = mylower(*q);
  1467.                 break;
  1468.             case UPPER:
  1469.                 for (i = len[x], q = start[x]; i > 0; i--, p++, q++)
  1470.                     *p = myupper(*q);
  1471.             }
  1472.         }
  1473.         else {
  1474.             if (c == ESC)
  1475.                 c = *(++pat);
  1476.             if (l == MAXPATH)
  1477.                 goto toolong;
  1478.             if (
  1479.                 (c == SLASH) &&
  1480.                 (
  1481.                     p == fullrep ? pat != to :
  1482.                     (
  1483.                         (
  1484.                             (pc = *(p - 1)) == SLASH
  1485.                         ) &&
  1486.                          *(pat - 1) != pc
  1487.                     )
  1488.                 )
  1489.             ) {
  1490.                 repbad = 1;
  1491.                 if (l + STRLEN(EMPTY) >= MAXPATH)
  1492.                     goto toolong;
  1493.                 strcpy(p, EMPTY);
  1494.                 p += STRLEN(EMPTY);
  1495.                 l += STRLEN(EMPTY);
  1496.             }
  1497.             *(p++)= c;
  1498.         }
  1499.     }
  1500.     if (p == fullrep) {
  1501.         strcpy(fullrep, EMPTY);
  1502.         repbad = 1;
  1503.     }
  1504.     *(p++) = '\0';
  1505.     return;
  1506.  
  1507. toolong:
  1508.     repbad = 1;
  1509.     strcpy(fullrep, TOOLONG);
  1510. }
  1511.  
  1512.  
  1513. static void checkcollisions()
  1514. {
  1515.     REPDICT *rd, *prd;
  1516.     REP *p, *q;
  1517.     int i, mult, oldnreps;
  1518.  
  1519.     if (nreps == 0)
  1520.         return;
  1521.     rd = (REPDICT *)myalloc(nreps * sizeof(REPDICT));
  1522.     for (
  1523.         q = &hrep, p = q->r_next, prd = rd, i = 0;
  1524.         p != NULL;
  1525.         q = p, p = p->r_next, prd++, i++
  1526.     ) {
  1527.         prd->rd_p = p;
  1528.         prd->rd_dto = p->r_hto->h_di;
  1529.         prd->rd_nto = p->r_nto;
  1530.         prd->rd_i = i;
  1531.     }
  1532.     qsort(rd, nreps, sizeof(REPDICT), rdcmp);
  1533.     mult = 0;
  1534.     for (i = 0, prd = rd, oldnreps = nreps; i < oldnreps; i++, prd++)
  1535.         if (
  1536.             i < oldnreps - 1 &&
  1537.             prd->rd_dto == (prd + 1)->rd_dto &&
  1538.             strcmp(prd->rd_nto, (prd + 1)->rd_nto) == 0
  1539.         ) {
  1540.             if (!mult)
  1541.                 mult = 1;
  1542.             else
  1543.                 printf(" , ");
  1544.             printf("%s%s", prd->rd_p->r_hfrom->h_name,
  1545.                 prd->rd_p->r_ffrom->fi_name);
  1546.             prd->rd_p->r_flags |= R_SKIP;
  1547.             prd->rd_p->r_ffrom->fi_rep = MISTAKE;
  1548.             nreps--;
  1549.             badreps++;
  1550.         }
  1551.         else if (mult) {
  1552.             prd->rd_p->r_flags |= R_SKIP;
  1553.             prd->rd_p->r_ffrom->fi_rep = MISTAKE;
  1554.             nreps--;
  1555.             badreps++;
  1556.             printf(" , %s%s -> %s%s : collision.\n",
  1557.                 prd->rd_p->r_hfrom->h_name, prd->rd_p->r_ffrom->fi_name,
  1558.                 prd->rd_p->r_hto->h_name, prd->rd_nto);
  1559.             mult = 0;
  1560.         }
  1561.     chgive(rd, oldnreps * sizeof(REPDICT));
  1562. }
  1563.  
  1564.  
  1565. static int rdcmp(rd1, rd2)
  1566.     REPDICT *rd1, *rd2;
  1567. {
  1568.     int ret;
  1569.  
  1570.     if (
  1571.         (ret = rd1->rd_dto - rd2->rd_dto) == 0 &&
  1572.         (ret = strcmp(rd1->rd_nto, rd2->rd_nto)) == 0
  1573.     )
  1574.         ret = rd1->rd_i - rd2->rd_i;
  1575.     return(ret);
  1576. }
  1577.  
  1578.  
  1579. static void findorder()
  1580. {
  1581.     REP *p, *q, *t, *first, *pred;
  1582.     FILEINFO *fi;
  1583.  
  1584.     for (q = &hrep, p = q->r_next; p != NULL; q = p, p = p->r_next)
  1585.         if (p->r_flags & R_SKIP) {
  1586.             q->r_next = p->r_next;
  1587.             p = q;
  1588.         }
  1589.         else if (
  1590.             (fi = p->r_fdel) == NULL ||
  1591.             (pred = fi->fi_rep) == NULL ||
  1592.             pred == MISTAKE
  1593.         )
  1594.             continue;
  1595.         else if ((first = pred->r_first) == p) {
  1596.             p->r_flags |= R_ISCYCLE;
  1597.             pred->r_flags |= R_ISALIASED;
  1598.             if (op & MOVE)
  1599.                 p->r_fdel = NULL;
  1600.         }
  1601.         else {
  1602.             if (op & MOVE)
  1603.                 p->r_fdel = NULL;
  1604.             while (pred->r_thendo != NULL)
  1605.                 pred = pred->r_thendo;
  1606.             pred->r_thendo = p;
  1607.             for (t = p; t != NULL; t = t->r_thendo)
  1608.                 t->r_first = first;
  1609.             q->r_next = p->r_next;
  1610.             p = q;
  1611.         }
  1612. }
  1613.  
  1614.  
  1615. static void nochains()
  1616. {
  1617.     REP *p, *q;
  1618.  
  1619.     for (q = &hrep, p = q->r_next; p != NULL; q = p, p = p->r_next)
  1620.         if (p->r_flags & R_ISCYCLE || p->r_thendo != NULL) {
  1621.             printchain(p);
  1622.             printf("%s%s : no chain copies allowed.\n",
  1623.                 p->r_hto->h_name, p->r_nto);
  1624.             q->r_next = p->r_next;
  1625.             p = q;
  1626.         }
  1627. }
  1628.  
  1629.  
  1630. static void printchain(p)
  1631.     REP *p;
  1632. {
  1633.     if (p->r_thendo != NULL)
  1634.         printchain(p->r_thendo);
  1635.     printf("%s%s -> ", p->r_hfrom->h_name, p->r_ffrom->fi_name);
  1636.     badreps++;
  1637.     nreps--;
  1638.     p->r_ffrom->fi_rep = MISTAKE;
  1639. }
  1640.  
  1641.  
  1642. static void scandeletes(pkilldel)
  1643.     int (*pkilldel)();
  1644. {
  1645.     REP *p, *q, *n;
  1646.  
  1647.     for (q = &hrep, p = q->r_next; p != NULL; q = p, p = p->r_next) {
  1648.         if (p->r_fdel != NULL)
  1649.             while ((*pkilldel)(p)) {
  1650.                 nreps--;
  1651.                 p->r_ffrom->fi_rep = MISTAKE;
  1652.                 if ((n = p->r_thendo) != NULL) {
  1653.                     if (op & MOVE)
  1654.                         n->r_fdel = p->r_ffrom;
  1655.                     n->r_next = p->r_next;
  1656.                     q->r_next = p = n;
  1657.                 }
  1658.                 else {
  1659.                     q->r_next = p->r_next;
  1660.                     p = q;
  1661.                     break;
  1662.                 }
  1663.             }
  1664.     }
  1665. }
  1666.  
  1667.  
  1668. static int baddel(p)
  1669.     REP *p;
  1670. {
  1671.     HANDLE *hfrom = p->r_hfrom, *hto = p->r_hto;
  1672.     FILEINFO *fto = p->r_fdel;
  1673.     char *t = fto->fi_name, *f = p->r_ffrom->fi_name;
  1674.     char *hnf = hfrom->h_name, *hnt = hto->h_name;
  1675.  
  1676.     if (delstyle == NODEL && !(p->r_flags & R_DELOK) && !(op & APPEND))
  1677.         printf("%s%s -> %s%s : old %s%s would have to be %s.\n",
  1678.             hnf, f, hnt, t, hnt, t,
  1679.             (op & OVERWRITE) ? "overwritten" : "deleted");
  1680.     else if (fto->fi_rep == MISTAKE)
  1681.         printf("%s%s -> %s%s : old %s%s was to be done first.\n",
  1682.             hnf, f, hnt, t, hnt, t);
  1683.     else if (fto->fi_attrib & FILE_DIRECTORY)
  1684.         printf("%s%s -> %s%s : %s%s%s is a directory.\n",
  1685.             hnf, f, hnt, t, (op & APPEND) ? "" : "old ", hnt, t);
  1686.     else if (
  1687.         (op & (APPEND | OVERWRITE)) &&
  1688.                 fto->fi_attrib & FILE_READONLY
  1689.     ) {
  1690.         printf("%s%s -> %s%s : %s%s %s.\n",
  1691.             hnf, f, hnt, t, hnt, t,
  1692.             "lacks write permission");
  1693.     }
  1694.     else
  1695.         return(0);
  1696.     badreps++;
  1697.     return(1);
  1698. }
  1699.  
  1700.  
  1701. static int skipdel(p)
  1702.     REP *p;
  1703. {
  1704.     if (p->r_flags & R_DELOK)
  1705.         return(0);
  1706.     fprintf(stderr, "%s%s -> %s%s : ",
  1707.         p->r_hfrom->h_name, p->r_ffrom->fi_name,
  1708.         p->r_hto->h_name, p->r_nto);
  1709.     if (p->r_fdel->fi_attrib & FILE_READONLY)
  1710.         fprintf(stderr, "old %s%s lacks write permission. delete it",
  1711.             p->r_hto->h_name, p->r_nto);
  1712.     else
  1713.         fprintf(stderr, "%s old %s%s",
  1714.             (op & OVERWRITE) ? "overwrite" : "delete",
  1715.             p->r_hto->h_name, p->r_nto);
  1716.     return(!getreply("? ", -1));
  1717. }
  1718.  
  1719.  
  1720. static void goonordie()
  1721. {
  1722.     if ((paterr || badreps) && nreps > 0) {
  1723.         fprintf(stderr, "Not everything specified can be done.");
  1724.         if (badstyle == ABORTBAD) {
  1725.             fprintf(stderr, " Aborting.\n");
  1726.             exit(1);
  1727.         }
  1728.         else if (badstyle == SKIPBAD)
  1729.             fprintf(stderr, " Proceeding with the rest.\n");
  1730.         else if (!getreply(" Proceed with the rest? ", -1))
  1731.             exit(1);
  1732.     }
  1733. }
  1734.  
  1735.  
  1736. static void doreps()
  1737. {
  1738.     char *fstart;
  1739.     int k, printaliased = 0, alias;
  1740.     REP *first, *p;
  1741.     long aliaslen;
  1742.  
  1743.     signal(SIGINT, breakrep);
  1744.  
  1745.     for (first = hrep.r_next, k = 0; first != NULL; first = first->r_next) {
  1746.         for (p = first; p != NULL; p = p->r_thendo, k++) {
  1747.             if (gotsig) {
  1748.                 fflush(stdout);
  1749.                 fprintf(stderr, "User break.\n");
  1750.                 printaliased = snap(first, p);
  1751.                 gotsig = 0;
  1752.             }
  1753.             strcpy(fullrep, p->r_hto->h_name);
  1754.             strcat(fullrep, p->r_nto);
  1755.             if (!noex && (p->r_flags & R_ISCYCLE))
  1756.                 if (op & APPEND)
  1757.                     aliaslen = appendalias(first, p, &printaliased);
  1758.                 else
  1759.                     alias = movealias(first, p, &printaliased);
  1760.             strcpy(pathbuf, p->r_hfrom->h_name);
  1761.             fstart = pathbuf + strlen(pathbuf);
  1762.             if ((p->r_flags & R_ISALIASED) && !(op & APPEND))
  1763.                 sprintf(fstart, "%s%03d", TEMP, alias);
  1764.             else
  1765.                 strcpy(fstart, p->r_ffrom->fi_name);
  1766.             if (!noex) {
  1767.                 if (p->r_fdel != NULL && !(op & (APPEND | OVERWRITE)))
  1768.                     myunlink(fullrep, p->r_fdel);
  1769.                 if (
  1770.                     (op & (COPY | APPEND)) ?
  1771.                         copy(p->r_ffrom,
  1772.                             p->r_flags & R_ISALIASED ? aliaslen : -1L) :
  1773. #ifndef OS2
  1774.                     (op & HARDLINK) ?
  1775.                         link(pathbuf, fullrep) :
  1776. #ifndef SYSV
  1777.                     (op & SYMLINK) ?
  1778.                         symlink((p->r_flags & R_ONEDIRLINK) ? fstart : pathbuf,
  1779.                             fullrep) :
  1780. #endif
  1781. #endif
  1782.                     p->r_flags & R_ISX ?
  1783.                         copymove(p) : /* move */
  1784.                         rename(pathbuf, fullrep)
  1785.                 ) {
  1786.                     fprintf(stderr,
  1787.                         "%s -> %s has failed.\n", pathbuf, fullrep);
  1788.                     printaliased = snap(first, p);
  1789.                 }
  1790.             }
  1791.             if (verbose || noex) {
  1792.                 if (p->r_flags & R_ISALIASED && !printaliased)
  1793.                     strcpy(fstart, p->r_ffrom->fi_name);
  1794.                 fprintf(outfile, "%s %c%c %s%s%s\n",
  1795.                     pathbuf,
  1796.                     p->r_flags & R_ISALIASED ? '=' : '-',
  1797.                     p->r_flags & R_ISCYCLE ? '^' : '>',
  1798.                     fullrep,
  1799.                     (p->r_fdel != NULL && !(op & APPEND)) ? " (*)" : "",
  1800.                     noex ? "" : " : done");
  1801.             }
  1802.         }
  1803.         printaliased = 0;
  1804.     }
  1805.     if (k != nreps)
  1806.         fprintf(stderr, "Strange, did %d reps; %d were expected.\n",
  1807.             k, nreps);
  1808.     if (k == 0)
  1809.         fprintf(stderr, "Nothing done.\n");
  1810. }
  1811.  
  1812.  
  1813. static long appendalias(first, p, pprintaliased)
  1814.     REP *first, *p;
  1815.     int *pprintaliased;
  1816. {
  1817.     long ret;
  1818.  
  1819.     struct stat fstat;
  1820.  
  1821.     if (stat(fullrep, &fstat)) {
  1822.         fprintf(stderr, "append cycle stat on %s has failed.\n", fullrep);
  1823.         *pprintaliased = snap(first, p);
  1824.     }
  1825.     else
  1826.         ret = fstat.st_size;
  1827.  
  1828.     return(ret);
  1829. }
  1830.  
  1831.  
  1832. static int movealias(first, p, pprintaliased)
  1833.     REP *first, *p;
  1834.     int *pprintaliased;
  1835. {
  1836.     char *fstart;
  1837.     int ret;
  1838.  
  1839.     strcpy(pathbuf, p->r_hto->h_name);
  1840.     fstart = pathbuf + strlen(pathbuf);
  1841.     strcpy(fstart, TEMP);
  1842.     for (
  1843.         ret = 0;
  1844.         sprintf(fstart + STRLEN(TEMP), "%03d", ret),
  1845.         fsearch(fstart, p->r_hto->h_di) != NULL;
  1846.         ret++
  1847.     )
  1848.         ;
  1849.     if (rename(fullrep, pathbuf)) {
  1850.         fprintf(stderr,
  1851.             "%s -> %s has failed.\n", fullrep, pathbuf);
  1852.         *pprintaliased = snap(first, p);
  1853.     }
  1854.     return(ret);
  1855. }
  1856.  
  1857.  
  1858. static int snap(first, p)
  1859.     REP *first, *p;
  1860. {
  1861.     char fname[80];
  1862.     int redirected = 0;
  1863.  
  1864.     if (noex)
  1865.         exit(1);
  1866.  
  1867.     failed = 1;
  1868.     signal(SIGINT, breakstat);
  1869.     if (
  1870.         badstyle == ASKBAD &&
  1871.         isatty(fileno(stdout)) &&
  1872.         getreply("Redirect standard output to file? ", 0)
  1873.     ) {
  1874.         redirected = 1;
  1875.         umask(oldumask);
  1876.         while (
  1877.             fprintf(stderr, "File name> "),
  1878.             (outfile = fopen(mygets(fname, 80), "w")) == NULL
  1879.         )
  1880.             fprintf(stderr, "Can't open %s.\n", fname);
  1881.     }
  1882.     if (redirected || !verbose)
  1883.         showdone(p);
  1884.     fprintf(outfile, "The following left undone:\n");
  1885.     noex = 1;
  1886.     return(first != p);
  1887. }
  1888.  
  1889.  
  1890. static void showdone(fin)
  1891.     REP *fin;
  1892. {
  1893.     REP *first, *p;
  1894.  
  1895.     for (first = hrep.r_next; ; first = first->r_next)
  1896.         for (p = first; p != NULL; p = p->r_thendo) {
  1897.             if (p == fin)
  1898.                 return;
  1899.             fprintf(outfile, "%s%s %c%c %s%s : done%s\n",
  1900.                 p->r_hfrom->h_name, p->r_ffrom->fi_name,
  1901.                 p->r_flags & R_ISALIASED ? '=' : '-',
  1902.                 p->r_flags & R_ISCYCLE ? '^' : '>',
  1903.                 p->r_hto->h_name, p->r_nto,
  1904.                 (p->r_fdel != NULL && !(op & APPEND)) ? " (*)" : "");
  1905.         }
  1906. }
  1907.  
  1908.  
  1909. static void breakout()
  1910. {
  1911.     fflush(stdout);
  1912.     fprintf(stderr, "Aborting, nothing done.\n");
  1913.     exit(1);
  1914. }
  1915.  
  1916.  
  1917. static void breakrep()
  1918. {
  1919.     gotsig = 1;
  1920. }
  1921.  
  1922.  
  1923. static void breakstat()
  1924. {
  1925.     exit(1);
  1926. }
  1927.  
  1928.  
  1929. static void quit()
  1930. {
  1931.     fprintf(stderr, "Aborting, nothing done.\n");
  1932.     exit(1);
  1933. }
  1934.  
  1935.  
  1936. static int copymove(p)
  1937.     REP *p;
  1938. {
  1939. #if 0
  1940.     int llen;
  1941.     char linkbuf[MAXPATH];
  1942.  
  1943.     if ((llen = readlink(pathbuf, linkbuf, MAXPATH - 1)) >= 0) {
  1944.         linkbuf[llen] = '\0';
  1945.         return(symlink(linkbuf, fullrep) || 
  1946.                myunlink(pathbuf, p->r_ffrom));
  1947.     }
  1948. #endif
  1949.     return(copy(p->r_ffrom, -1L) || myunlink(pathbuf, p->r_ffrom));
  1950. }
  1951.  
  1952.  
  1953.  
  1954. #define IRWMASK (S_IREAD | S_IWRITE)
  1955. #define RWMASK (IRWMASK | (IRWMASK >> 3) | (IRWMASK >> 6))
  1956.  
  1957. static int copy(ff, len)
  1958.     FILEINFO *ff;
  1959.     long len;
  1960. {
  1961.     char buf[BUFSIZE], c;
  1962.     int f, t, k, mode, perm;
  1963.         FILESTATUS fs;
  1964.  
  1965.     if ((f = open(pathbuf, O_RDONLY | O_BINARY, 0)) < 0)
  1966.         return(-1);
  1967.     perm = IRWMASK;
  1968.     mode = O_CREAT | (op & APPEND ? 0 : O_TRUNC) |
  1969.         O_BINARY | (op & ZAPPEND ? O_RDWR : O_WRONLY);
  1970.     t = open(fullrep, mode, perm);
  1971.     if (t < 0) {
  1972.         close(f);
  1973.         return(-1);
  1974.     }
  1975.     if (op & APPEND)
  1976.         lseek(t, 0L, 2);
  1977.     if (op & ZAPPEND && filelength(t) != 0) {
  1978.         if (lseek(t, -1L, 1) == -1L || read(t, &c, 1) != 1) {
  1979.             close(f);
  1980.             close(t);
  1981.             return(-1);
  1982.         }
  1983.         if (c == 26)
  1984.             lseek(t, -1L, 1);
  1985.     }
  1986.     if ((op & APPEND) && len != -1L) {
  1987.         while (
  1988.             len != 0 &&
  1989.             (k = read(f, buf, len > BUFSIZE ? BUFSIZE : (unsigned)len)) > 0 &&
  1990.             write(t, buf, k) == k
  1991.         )
  1992.             len -= k;
  1993.         if (len == 0)
  1994.             k = 0;
  1995.     }
  1996.     else
  1997.         while ((k = read(f, buf, BUFSIZE)) > 0 && write(t, buf, k) == k)
  1998.             ;
  1999.     if (!(op & (APPEND | OVERWRITE)))
  2000.         if (DosQueryFileInfo(f, 1, &fs, sizeof(fs)) ||
  2001.             DosSetFileInfo(t, 1, &fs, sizeof(fs)))
  2002.             fprintf(stderr, "Strange, couldn't transfer time from %s to %s.\n",
  2003.                 pathbuf, fullrep);
  2004.  
  2005.     close(f);
  2006.     close(t);
  2007.     if (k != 0) {
  2008.         if (!(op & APPEND))
  2009.             unlink(fullrep);
  2010.         return(-1);
  2011.     }
  2012.     return(0);
  2013. }
  2014.  
  2015.  
  2016. static int myunlink(n, f)
  2017.     char *n;
  2018.     FILEINFO *f;
  2019. {
  2020.         if ((f->fi_attrib & FILE_READONLY) && chmod(n, 0666)) {
  2021.         fprintf(stderr, "Strange, can not chmod %s.\n", f);
  2022.         return(-1);
  2023.     }
  2024.     if (unlink(n)) {
  2025.         fprintf(stderr, "Strange, can not unlink %s.\n", n);
  2026.         return(-1);
  2027.     }
  2028.     return(0);
  2029. }
  2030.  
  2031.  
  2032. static int getreply(m, failact)
  2033.     char *m;
  2034.     int failact;
  2035. {
  2036.     static FILE *tty = NULL;
  2037.     int c, r;
  2038.  
  2039.     fprintf(stderr, m);
  2040.     if (tty == NULL && (tty = fopen(TTY, "r")) == NULL) {
  2041.         fprintf(stderr, "Can not open %s to get reply.\n", TTY);
  2042.         if (failact == -1)
  2043.             quit();
  2044.         else
  2045.             return(failact);
  2046.     }
  2047.     for (;;) {
  2048.         r = fgetc(tty);
  2049.         if (r == EOF) {
  2050.             fprintf(stderr, "Can not get reply.\n");
  2051.             if (failact == -1)
  2052.                 quit();
  2053.             else
  2054.                 return(failact);
  2055.         }
  2056.         if (r != '\n')
  2057.             while ((c = fgetc(tty)) != '\n' && c != EOF)
  2058.                 ;
  2059.         r = mylower(r);
  2060.         if (r == 'y' || r == 'n')
  2061.             return(r == 'y');
  2062.         fprintf(stderr, "Yes or No? ");
  2063.     }
  2064. }
  2065.  
  2066.  
  2067. static void *myalloc(k)
  2068.     unsigned k;
  2069. {
  2070.     void *ret;
  2071.  
  2072.     if (k == 0)
  2073.         return(NULL);
  2074.     if ((ret = (void *)malloc(k)) == NULL) {
  2075.         fprintf(stderr, "Insufficient memory.\n");
  2076.         quit();
  2077.     }
  2078.     return(ret);
  2079. }
  2080.  
  2081.  
  2082. static void *challoc(k, which)
  2083.     int which;
  2084.     int k;
  2085. {
  2086.     void *ret;
  2087.     CHUNK *p, *q;
  2088.     SLICER *sl = &(slicer[which]);
  2089.  
  2090.     if (k > sl->sl_len) {
  2091.         for (
  2092.             q = NULL, p = freechunks;
  2093.             p != NULL && (sl->sl_len = p->ch_len) < k;
  2094.             q = p, p = p->ch_next
  2095.         )
  2096.             ;
  2097.         if (p == NULL) {
  2098.             sl->sl_len = CHUNKSIZE - sizeof(CHUNK *);
  2099.             p = (CHUNK *)myalloc(CHUNKSIZE);
  2100.         }
  2101.         else if (q == NULL)
  2102.             freechunks = p->ch_next;
  2103.         else
  2104.             q->ch_next = p->ch_next;
  2105.         p->ch_next = sl->sl_first;
  2106.         sl->sl_first = p;
  2107.         sl->sl_unused = (char *)&(p->ch_len);
  2108.     }
  2109.     sl->sl_len -= k;
  2110.     ret = (void *)sl->sl_unused;
  2111.     sl->sl_unused += k;
  2112.     return(ret);
  2113. }
  2114.  
  2115.  
  2116. static void chgive(p, k)
  2117.     void *p;
  2118.     unsigned k;
  2119. {
  2120.     ((CHUNK *)p)->ch_len = k - sizeof(CHUNK *);
  2121.     ((CHUNK *)p)->ch_next = freechunks;
  2122.     freechunks = (CHUNK *)p;
  2123. }
  2124.  
  2125.  
  2126. static int mygetc()
  2127. {
  2128.     static int lastc = 0;
  2129.  
  2130.     if (lastc == EOF)
  2131.         return(EOF);
  2132.     return(lastc = getchar());
  2133. }
  2134.  
  2135.  
  2136. static char *mygets(s, l)
  2137.     char *s;
  2138.     int l;
  2139. {
  2140.     char *nl;
  2141.  
  2142.     for (;;) {
  2143.         if (fgets(s, l, stdin) == NULL)
  2144.             return(NULL);
  2145.         if ((nl = strchr(s, '\n')) != NULL)
  2146.             break;
  2147.         fprintf(stderr, "Input string too long. Try again> ");
  2148.     }
  2149.     *nl = '\0';
  2150.     return(s);
  2151. }
  2152.  
  2153.  
  2154. static int leave()
  2155. {
  2156.     return(0);
  2157. }
  2158.  
  2159. static void cleanup()
  2160. {
  2161.     int i;
  2162.  
  2163.     if (patch.ph_safeid) {
  2164.         for (i = 0; i < nhandles; i++) {
  2165.             if (!(handles[i]->h_di->di_flags & DI_CLEANED)) {
  2166.                 sprintf(pathbuf, "%s%s%03d",
  2167.                     handles[i]->h_name, IDF, handles[i]->h_di->di_did);
  2168.                 if (unlink(pathbuf))
  2169.                     fprintf(stderr, "Strange, couldn't unlink %s.\n", pathbuf);
  2170.                 handles[i]->h_di->di_flags |= DI_CLEANED;
  2171.             }
  2172.         }
  2173.     }
  2174. }
  2175.