home *** CD-ROM | disk | FTP | other *** search
- /*
- 8-Sep-86 16:13:40-PDT,10218;000000000000
- Return-Path: <pwu@unix.macc.wisc.edu>
- Received: FROM UNIX.MACC.WISC.EDU BY B.ISI.EDU WITH TCP ; 8 Sep 86 16:11:21 PDT
- Received: by unix.macc.wisc.edu;
- id AA04984; 4.12/5; Mon, 8 Sep 86 17:32:05 cdt
- Date: Mon, 8 Sep 86 17:32:05 cdt
- From: Peter Wu <pwu@unix.macc.wisc.edu>
- Message-Id: <8609082232.AA04984@unix.macc.wisc.edu>
- To: info-ibmpc-request@mosis
- Subject: normal.c
- */
- /* The normal routine "normalizes" a given path name to this form:
- ** drv:\id\id\id...\id
- ** so that two identical directory/file will yield the same normalized
- ** path regardless of how the user typed it in
- ** E.g.
- ** a:\x\y
- ** and a:\X\Y\.
- ** both yield A:\X\Y
- **
- ** In addition, the later one would also set the flag "dir" indicating
- ** that the user specified it as an directory.
- **
- ** Written by Peter Wu @ Faculty Support Center @ Univ. of Wisconsin
- ** 7/14/86
- */
- #define LINT_ARGS
-
- #define T_ID1 1 /* id without period */
- #define T_ID2 2 /* id with period */
- #define T_DOT 3 /* '.' */
- #define T_DD 4
- #define T_BS 5
- #define T_COL 6
- #define T_NUL 0
-
- #define PLEN 200
-
- #include "dta.h"
- #include <dos.h>
- #include <string.h>
- #include <conio.h>
-
- char *insert();
-
- index(str,c) /* first occurence of c in str */
- char *str, c;
- {
- char *i, d;
-
- i = str;
- d = *i;
- while (d != '\0') {
- if (d == c) {
- return i - str;
- }
- i++;
- d = *i;
- }
- return -1;
- }
-
- char lastc(str) /* return last character of the string */
- register char *str;
- {
- if (*str == '\0') {
- return '\0';
- }
-
- do {
- str++;
- } while (*str != '\0');
-
- return *(str-1);
- }
-
- normal(path) /* normalize a path */
- char *path;
- {
- char work1[PLEN], work2[PLEN], token[13], token2[13], *ptr;
- int i, drv, marker, t, ftype, t2;
-
- /* first make the path a complete path (include drive, and root) */
- i = index(path, ':'); /* search for ':' */
- if (i < 0) { /* no drive specification */
- if (*path == '\\') { /* start from root */
- work1[0] = '@' + drive(); /* default disk */
- work1[1] = ':';
- work1[2] = '\0';
- strcat(work1, path); /* now we have full path */
- } else { /* no drive and no root */
- current(0,work1); /* get current drive and path */
- strcat(work1, path); /* now we have full path */
- }
- } else { /* has drive specification */
- if (path[i+1] != '\\') { /* but no root, so insert current path */
- drv = toupper(path[i-1]) - '@'; /* get drive number */
- current(drv,work1); /* put down drive and path */
- strcat(work1, path+i+1); /* now we have full path */
- } else { /* nothing to change */
- strcpy(work1,path);
- }
- }
-
- #ifdef debug
- printf("full path is %s\n", work1);
- #endif
-
- /* now we have full path in work, but we need to normalize it to get rid
- ** of .. and .
- */
- marker = -2;
- work2[PLEN-1] = '\0'; /* this is where we accumulate result backwards */
- ptr = work2 + PLEN - 1; /* point to first char */
- ftype = -1; /* -1=init, 0=unknown, A_DIR=dir */
-
- do {
- t = scan(work1,&marker,token);
- #ifdef debug
- printf("ptr is %s so far, and t=%d\n", ptr, t);
- #endif
- switch (t) {
-
- case T_ID1:
- case T_ID2:
- ptr = insert(token, ptr);
- if (ftype == -1) {
- ftype = 0; /* this could be a file or a directory */
- }
- break;
-
- #ifdef ha
- case T_ID2:
- if (ftype == -1) {
- ptr = insert(token, ptr);
- ftype = 0; /* this could be file or a directory */
- } else {
- putn("invalid sub-directory name \"", token, "\"\n\015",0);
- exit(1);
- }
- break;
- #endif
-
- case T_DD:
- t2 = scan(work1,&marker,token); /* see what's in front of .. */
- if (t2 != T_BS) {
- cputs("incorrect use of \"..\" in path name\n\015");
- exit(1);
- }
- /* now delete \id\.. */
- t2 = scan(work1,&marker,token); /* read the id (hopefully) */
- if (t2 != T_ID1) {
- if (t2 == T_COL) { /* A:\.. is not permitted */
- cputs("sorry, but root directory has no parent\n\015");
- exit(1);
- } else { /* what could t2 be? */
- cputs("missing directory name in front of \"\\..\"\n\015");
- exit(1);
- }
- }
- t2 = scan(work1,&marker,token2); /* read the '\' */
- if (t2 != T_BS) { /* can this ever happen? */
- putn("missing \"\\\" before \"", token, "\" in path\n\015",0);
- exit(1);
- }
-
- /* a:\id\.. should yield a:\ not a:
- ** a:\id1\..\id2 should yield a:\id2
- ** this is taken care of somewhere else
- */
-
- /* ok, \id\.. deleted */
- if (ftype == -1) {
- ftype = A_DIR; /* this has to be a directory */
- }
- break;
-
- case T_DOT:
- t2 = scan(work1,&marker,token); /* read the '\' */
- if (t2 != T_BS) { /* is this error possible? */
- cputs("missing \"\\\" in front of \".\"\n\015");
- exit(1);
- }
- if (ftype == -1) {
- ftype = A_DIR; /* this has to be a directory */
- }
- /* special case is "a:\." we want this to turn into "A:\" and
- ** not "A:"
- */
- break;
-
- case T_BS:
- ptr = insert("\\", ptr);
- break;
-
- case T_COL:
- ptr = insert(":", ptr);
- break;
- }
- } while (t != T_NUL);
-
- if (lastc(ptr) == ':') { /* special case like a: */
- strcat(ptr,"\\");
- }
- strcpy(path,ptr); /* copy normalized path back */
- return ftype;
- }
-
- char *insert(str1,str2) /* insert str1 in front of str2 */
- char *str1, *str2;
- {
- int i;
-
- i = strlen(str1);
- return strncpy(str2 - i, str1, i);
- }
-
- scan(path,marker,tstr) /* return tokens backwards */
- char *path, *tstr;
- int *marker;
- {
- char c, d;
-
- if (*marker == -2) { /* signal new scan */
- *marker = strlen(path) - 1;
- }
-
- if (*marker == -1) {
- return T_NUL; /* end of string */
- }
-
- c = path[*marker];
- if ( ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) ) {
- return collect_id(tstr, path, marker);
- }
-
- switch (c) {
- case '.':
- if (*marker == 0) {
- *marker = -1;
- return T_DOT;
- } else {
- d = path[*marker - 1];
- if (d == '.') {
- *marker -= 2;
- return T_DD;
- } else {
- if ((d == '\\') || (d == ':')) {
- (*marker)--;
- return T_DOT;
- } else { /* must be an id with trailing dot */
- return collect_id(tstr, path, marker);
- }
- }
- }
- cputs("how do I get here?\n\015");
- error("scan", 0);
-
- case '\\':
- (*marker)--;
- return T_BS;
-
- case ':':
- (*marker)--;
- return T_COL;
-
- default:
- return collect_id(tstr, path, marker); /* non-alpha ID */
- }
- }
-
- check_fn(fn) /* look for invalid characters in file name */
- char *fn;
- {
- char c, *s;
-
- s = fn;
- while((c= *s) != '\0') {
- if ((c < 32) || (index("\"[]|<>+=;,/",c) > -1)) {
- cputs("invalid character '"); putch(c);
- putn("' in file/sub-directory name \"", fn, "\"", 0);
- exit(1);
- }
- s++;
- }
- }
-
- collect_id(tstr, path, marker)
- char *tstr, *path;
- int *marker;
- {
- char c, id[13];
- int flag, i;
-
- id[13] = '\0';
- i = 12;
- flag = T_ID1; /* no period in file name */
- do {
- c = path[*marker];
-
- if (c == '.') { /* indicate there's period in the file name */
- flag = T_ID2;
- } else {
- c = toupper(c);
- if ((c == '\\') || (c == ':')) { /* end of file name */
- strncpy(tstr, id+i+1, 13);
- check_fn(tstr);
- return flag;
- }
- }
-
- id[i] = c;
- (*marker)--;
- if (*marker < 0) {
- strncpy(tstr, id+i, 13);
- check_fn(tstr);
- return flag;
- }
- i--;
- } while (i >= 0);
-
- putn("file/sub-directory name \"...", id, "\" too long\n\015", 0);
- exit(1);
- }
-
- drive() /* returns current drive number 1=A 2=B */
- {
- return (char) bdos(0x19, 0, 0) + 1;
- }
-
- current(drv,cpath) /* returns current path "drv:\id\..\id on drv */
- char *cpath;
- int drv;
- {
- union REGS inregs, outregs;
- char tmp[64];
-
- inregs.h.ah = 0x47; /* get current path */
- inregs.x.si = (int) tmp;
- inregs.h.dl = drv; /* drive number 0=default, 1=A, 2=B */
- intdos(&inregs, &outregs);
- if (drv == 0) {
- drv = drive();
- }
- if (outregs.x.cflag) {
- cputs("cannot find current path on drive "); putch('@'+drv);
- cputs(":\n\015");
- error("current", 0);
- } else {
- cpath[0] = '@' + drv;
- cpath[1] = ':';
- cpath[2] = '\\';
- cpath[3] = '\0';
- if (*tmp != '\0') { /* if not root directory, then append path */
- strcat(cpath,tmp);
- strcat(cpath,"\\");
- }
- }
- }
-
- catpath(path, name) /* concatenate name to path, adding \ when neccessary */
- char *path, *name;
- {
- if (path[strlen(path)-1] != '\\') {
- strcat(path, "\\");
- }
- strcat(path, name);
- }
-
- chopath(path) /* chop off the last portion of a path */
- char *path;
- {
- char *tmp;
-
- tmp = strrchr(path, '\\');
- if (tmp == (char *)0) {
- putn("can't find '\\' in ", path, "\n\015");
- error("chopath", 0);
- }
- if (*(tmp-1) == ':') { /* special case for root */
- *(tmp+1) = '\0';
- } else {
- *tmp = '\0';
- }
- }
-
- #define A_INT 0x80 /* interactive flag */
-
- /* extract the file-type specifier from the given path.
- ** E.g. x/f becomes x with file type,
- ** animal\dog/d becomes animal\dog with sub-directory type,
- ** *./f becomes *. with file type
- ** *.* becomes *.* with no type
- ** *./i becomes interactive (i.e. prompts for y/n for each file)
- */
- extype(path)
- char *path;
- {
- char *s;
- int type;
-
- s = strrchr(path,'/'); /* find last '/' */
- if (s == (char *) 0) { /* no type specified */
- return 0;
- }
-
- type = 0;
- *s = '\0';
- for (++s; *s != '\0'; s++) { /* start scanning after the '/' */
- switch (*s) {
- case 'f':
- case 'F':
- type |= A_FIL;
- break;
-
- case 'd':
- case 'D':
- type |= A_DIR;
- break;
-
- case 'h':
- case 'H':
- type |= A_HID; /* search for hidden files */
- break;
-
- case 'i':
- case 'I':
- type |= A_INT; /* requires user's confirmation for each file */
- break;
-
- default:
- cputs("unrecognized file attribute '"); putch(*s);
- putn("' in path \"", path, "\"\n\015",
- "valid attributes are f, d, h, i (for file, directory, hidden, interac)\n\015",
- 0);
- exit(1); /* maybe the user doesn't know what he/she's doing */
- }
- }
- return type;
- }