home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / library / dos / directry / mv / normal.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-05  |  10.7 KB  |  442 lines

  1. /*
  2.   8-Sep-86 16:13:40-PDT,10218;000000000000
  3. Return-Path: <pwu@unix.macc.wisc.edu>
  4. Received: FROM UNIX.MACC.WISC.EDU BY B.ISI.EDU WITH TCP ; 8 Sep 86 16:11:21 PDT
  5. Received: by unix.macc.wisc.edu;
  6.           id AA04984; 4.12/5; Mon, 8 Sep 86 17:32:05 cdt
  7. Date: Mon, 8 Sep 86 17:32:05 cdt
  8. From: Peter Wu <pwu@unix.macc.wisc.edu>
  9. Message-Id: <8609082232.AA04984@unix.macc.wisc.edu>
  10. To: info-ibmpc-request@mosis
  11. Subject: normal.c
  12. */
  13. /* The normal routine "normalizes" a given path name to this form:
  14. ** drv:\id\id\id...\id
  15. ** so that two identical directory/file will yield the same normalized
  16. ** path regardless of how the user typed it in
  17. ** E.g.
  18. **       a:\x\y
  19. **   and a:\X\Y\.
  20. **  both yield A:\X\Y
  21. **
  22. ** In addition, the later one would also set the flag "dir" indicating
  23. ** that the user specified it as an directory.
  24. **
  25. ** Written by Peter Wu @ Faculty Support Center @ Univ. of Wisconsin
  26. ** 7/14/86
  27. */
  28. #define LINT_ARGS
  29.  
  30. #define T_ID1 1  /* id without period */
  31. #define T_ID2 2  /* id with period */
  32. #define T_DOT 3  /* '.' */
  33. #define T_DD  4
  34. #define T_BS  5
  35. #define T_COL 6
  36. #define T_NUL 0
  37.  
  38. #define PLEN 200
  39.  
  40. #include "dta.h"
  41. #include <dos.h>
  42. #include <string.h>
  43. #include <conio.h>
  44.  
  45. char *insert();
  46.  
  47. index(str,c) /* first occurence of c in str */
  48. char *str, c;
  49. {
  50.   char *i, d;
  51.  
  52.   i = str;
  53.   d = *i;
  54.   while (d != '\0') {
  55.     if (d == c) {
  56.       return i - str;
  57.     }
  58.     i++;
  59.     d = *i;
  60.   }
  61.   return -1;
  62. }
  63.  
  64. char lastc(str)  /* return last character of the string */
  65. register char *str;
  66. {
  67.   if (*str == '\0') {
  68.     return '\0';
  69.   }
  70.  
  71.   do {
  72.     str++;
  73.   } while (*str != '\0');
  74.  
  75.   return *(str-1);
  76. }
  77.  
  78. normal(path)  /* normalize a path */
  79. char *path;
  80. {
  81.   char work1[PLEN], work2[PLEN], token[13], token2[13], *ptr;
  82.   int i, drv, marker, t, ftype, t2;
  83.  
  84.   /* first make the path a complete path (include drive, and root) */
  85.   i = index(path, ':');  /* search for ':' */
  86.   if (i < 0) {  /* no drive specification */
  87.     if (*path == '\\') {  /* start from root */
  88.       work1[0] = '@' + drive();  /* default disk */
  89.       work1[1] = ':';
  90.       work1[2] = '\0';
  91.       strcat(work1, path);  /* now we have full path */
  92.     } else {  /* no drive and no root */
  93.       current(0,work1);  /* get current drive and path */
  94.       strcat(work1, path);  /* now we have full path */
  95.     }
  96.   } else {  /* has drive specification */
  97.     if (path[i+1] != '\\') {  /* but no root, so insert current path */
  98.       drv = toupper(path[i-1]) - '@';  /* get drive number */
  99.       current(drv,work1);  /* put down drive and path */
  100.       strcat(work1, path+i+1);  /* now we have full path */
  101.     } else {  /* nothing to change */
  102.       strcpy(work1,path);
  103.     }
  104.   }
  105.  
  106. #ifdef debug
  107.   printf("full path is %s\n", work1);
  108. #endif
  109.  
  110.   /* now we have full path in work, but we need to normalize it to get rid
  111.   ** of .. and .
  112.   */
  113.   marker = -2;
  114.   work2[PLEN-1] = '\0';  /* this is where we accumulate result backwards */
  115.   ptr = work2 + PLEN - 1;  /* point to first char */
  116.   ftype = -1;  /* -1=init, 0=unknown,  A_DIR=dir */
  117.  
  118.   do {
  119.     t = scan(work1,&marker,token);
  120. #ifdef debug
  121.     printf("ptr is %s so far, and t=%d\n", ptr, t);
  122. #endif
  123.     switch (t) {
  124.  
  125.       case T_ID1:
  126.       case T_ID2:
  127.         ptr = insert(token, ptr);
  128.         if (ftype == -1) {
  129.           ftype = 0;  /* this could be a file or a directory */
  130.         }
  131.         break;
  132.  
  133. #ifdef ha
  134.       case T_ID2:
  135.         if (ftype == -1) {
  136.           ptr = insert(token, ptr);
  137.           ftype = 0;  /* this could be file or a directory */
  138.         } else {
  139.           putn("invalid sub-directory name \"", token, "\"\n\015",0);
  140.           exit(1);
  141.         }
  142.         break;
  143. #endif
  144.  
  145.       case T_DD:
  146.         t2 = scan(work1,&marker,token);  /* see what's in front of .. */
  147.         if (t2 != T_BS) {
  148.           cputs("incorrect use of \"..\" in path name\n\015");
  149.           exit(1);
  150.         }
  151.         /* now delete \id\.. */
  152.         t2 = scan(work1,&marker,token);  /* read the id (hopefully) */
  153.         if (t2 != T_ID1) {
  154.           if (t2 == T_COL) {  /* A:\.. is not permitted */
  155.             cputs("sorry, but root directory has no parent\n\015");
  156.             exit(1);
  157.           } else {  /* what could t2 be? */
  158.             cputs("missing directory name in front of \"\\..\"\n\015");
  159.             exit(1);
  160.           }
  161.         }
  162.         t2 = scan(work1,&marker,token2);  /* read the '\' */
  163.         if (t2 != T_BS) {  /* can this ever happen? */
  164.           putn("missing \"\\\" before \"", token, "\" in path\n\015",0);
  165.           exit(1);
  166.         }
  167.  
  168.         /* a:\id\.. should yield a:\ not a:
  169.         ** a:\id1\..\id2 should yield a:\id2
  170.         ** this is taken care of somewhere else
  171.         */
  172.  
  173.         /* ok, \id\.. deleted */
  174.         if (ftype == -1) {
  175.           ftype = A_DIR;  /* this has to be a directory */
  176.         }
  177.         break;
  178.  
  179.       case T_DOT:
  180.         t2 = scan(work1,&marker,token);  /* read the '\' */
  181.         if (t2 != T_BS) {  /* is this error possible? */
  182.           cputs("missing \"\\\" in front of \".\"\n\015");
  183.           exit(1);
  184.         }
  185.         if (ftype == -1) {
  186.           ftype = A_DIR;  /* this has to be a directory */
  187.         }
  188.         /* special case is "a:\." we want this to turn into "A:\" and
  189.         ** not "A:"
  190.         */
  191.         break;
  192.  
  193.       case T_BS:
  194.         ptr = insert("\\", ptr);
  195.         break;
  196.  
  197.       case T_COL:
  198.         ptr = insert(":", ptr);
  199.         break;
  200.     }
  201.   } while (t != T_NUL);
  202.  
  203.   if (lastc(ptr) == ':') {  /* special case like a: */
  204.     strcat(ptr,"\\");
  205.   }
  206.   strcpy(path,ptr);  /* copy normalized path back */
  207.   return ftype;
  208. }
  209.  
  210. char *insert(str1,str2)  /* insert str1 in front of str2 */
  211. char *str1, *str2;
  212. {
  213.   int i;
  214.  
  215.   i = strlen(str1);
  216.   return strncpy(str2 - i, str1, i);
  217. }
  218.  
  219. scan(path,marker,tstr) /* return tokens backwards */
  220. char *path, *tstr;
  221. int *marker;
  222. {
  223.   char c, d;
  224.  
  225.   if (*marker == -2) {  /* signal new scan */
  226.     *marker = strlen(path) - 1;
  227.   }
  228.  
  229.   if (*marker == -1) {
  230.     return T_NUL;  /* end of string */
  231.   }
  232.  
  233.   c = path[*marker];
  234.   if ( ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) ) {
  235.     return collect_id(tstr, path, marker);
  236.   }
  237.  
  238.   switch (c) {
  239.     case '.':
  240.       if (*marker == 0) {
  241.         *marker = -1;
  242.         return T_DOT;
  243.       } else {
  244.         d = path[*marker - 1];
  245.         if (d == '.') {
  246.           *marker -= 2;
  247.           return T_DD;
  248.         } else {
  249.           if ((d == '\\') || (d == ':')) {
  250.             (*marker)--;
  251.             return T_DOT;
  252.           } else {  /* must be an id with trailing dot */
  253.             return collect_id(tstr, path, marker);
  254.           }
  255.         }
  256.       }
  257.       cputs("how do I get here?\n\015");
  258.       error("scan", 0);
  259.  
  260.     case '\\':
  261.       (*marker)--;
  262.       return T_BS;
  263.  
  264.     case ':':
  265.       (*marker)--;
  266.       return T_COL;
  267.  
  268.     default:
  269.       return collect_id(tstr, path, marker);  /* non-alpha ID */
  270.   }
  271. }
  272.  
  273. check_fn(fn)  /* look for invalid characters in file name */
  274. char *fn;
  275. {
  276.   char c, *s;
  277.  
  278.   s = fn;
  279.   while((c= *s) != '\0') {
  280.     if ((c < 32) || (index("\"[]|<>+=;,/",c) > -1)) {
  281.       cputs("invalid character '"); putch(c);
  282.       putn("' in file/sub-directory name \"", fn, "\"", 0);
  283.       exit(1);
  284.     }
  285.     s++;
  286.   }
  287. }
  288.  
  289. collect_id(tstr, path, marker)
  290. char *tstr, *path;
  291. int *marker;
  292. {
  293.   char c, id[13];
  294.   int flag, i;
  295.  
  296.   id[13] = '\0';
  297.   i = 12;
  298.   flag = T_ID1;  /* no period in file name */
  299.   do {
  300.     c = path[*marker];
  301.  
  302.     if (c == '.') {  /* indicate there's period in the file name */
  303.       flag = T_ID2;
  304.     } else {
  305.       c = toupper(c);
  306.       if ((c == '\\') || (c == ':')) {  /* end of file name */
  307.         strncpy(tstr, id+i+1, 13);
  308.         check_fn(tstr);
  309.         return flag;
  310.       }
  311.     }
  312.  
  313.     id[i] = c;
  314.     (*marker)--;
  315.     if (*marker < 0) {
  316.       strncpy(tstr, id+i, 13);
  317.       check_fn(tstr);
  318.       return flag;
  319.     }
  320.     i--;
  321.   } while (i >= 0);
  322.  
  323.   putn("file/sub-directory name \"...", id, "\" too long\n\015", 0);
  324.   exit(1);
  325. }
  326.  
  327. drive()  /* returns current drive number 1=A 2=B */
  328. {
  329.   return (char) bdos(0x19, 0, 0) + 1;
  330. }
  331.  
  332. current(drv,cpath)  /* returns current path "drv:\id\..\id on drv */
  333. char *cpath;
  334. int drv;
  335. {
  336.   union REGS inregs, outregs;
  337.   char tmp[64];
  338.  
  339.   inregs.h.ah = 0x47;  /* get current path */
  340.   inregs.x.si = (int) tmp;
  341.   inregs.h.dl = drv;  /* drive number 0=default, 1=A, 2=B */
  342.   intdos(&inregs, &outregs);
  343.   if (drv == 0) {
  344.     drv = drive();
  345.   }
  346.   if (outregs.x.cflag) {
  347.     cputs("cannot find current path on drive "); putch('@'+drv);
  348.     cputs(":\n\015");
  349.     error("current", 0);
  350.   } else {
  351.     cpath[0] = '@' + drv;
  352.     cpath[1] = ':';
  353.     cpath[2] = '\\';
  354.     cpath[3] = '\0';
  355.     if (*tmp != '\0') {  /* if not root directory, then append path */
  356.       strcat(cpath,tmp);
  357.       strcat(cpath,"\\");
  358.     }
  359.   }
  360. }
  361.  
  362. catpath(path, name)  /* concatenate name to path, adding \ when neccessary */
  363. char *path, *name;
  364. {
  365.   if (path[strlen(path)-1] != '\\') {
  366.     strcat(path, "\\");
  367.   }
  368.   strcat(path, name);
  369. }
  370.  
  371. chopath(path)  /* chop off the last portion of a path */
  372. char *path;
  373. {
  374.   char *tmp;
  375.  
  376.   tmp = strrchr(path, '\\');
  377.   if (tmp == (char *)0) {
  378.     putn("can't find '\\' in ", path, "\n\015");
  379.     error("chopath", 0);
  380.   }
  381.   if (*(tmp-1) == ':') {  /* special case for root */
  382.     *(tmp+1) = '\0';
  383.   } else {
  384.     *tmp = '\0';
  385.   }
  386. }
  387.  
  388. #define A_INT 0x80      /* interactive flag */
  389.  
  390. /* extract the file-type specifier from the given path.
  391. ** E.g.  x/f becomes x with file type,
  392. **       animal\dog/d becomes animal\dog with sub-directory type,
  393. **       *./f becomes *. with file type
  394. **       *.* becomes *.* with no type
  395. **       *./i becomes interactive (i.e. prompts for y/n for each file)
  396. */
  397. extype(path)
  398. char *path;
  399. {
  400.   char *s;
  401.   int type;
  402.  
  403.   s = strrchr(path,'/');  /* find last '/' */
  404.   if (s == (char *) 0) {  /* no type specified */
  405.     return 0;
  406.   }
  407.  
  408.   type = 0;
  409.   *s = '\0';
  410.   for (++s; *s != '\0'; s++) {  /* start scanning after the '/' */
  411.     switch (*s) {
  412.       case 'f':
  413.       case 'F':
  414.         type |= A_FIL;
  415.         break;
  416.  
  417.       case 'd':
  418.       case 'D':
  419.         type |= A_DIR;
  420.         break;
  421.  
  422.       case 'h':
  423.       case 'H':
  424.         type |= A_HID;  /* search for hidden files */
  425.         break;
  426.  
  427.       case 'i':
  428.       case 'I':
  429.         type |= A_INT;  /* requires user's confirmation for each file */
  430.         break;
  431.  
  432.       default:
  433.         cputs("unrecognized file attribute '"); putch(*s);
  434.         putn("' in path \"", path, "\"\n\015",
  435. "valid attributes are f, d, h, i (for file, directory, hidden, interac)\n\015",
  436.  0);
  437.         exit(1); /* maybe the user doesn't know what he/she's doing */
  438.     }
  439.   }
  440.   return type;
  441. }
  442.