home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume24 / mkid2 / part02 / cannoname.c next >
C/C++ Source or Header  |  1991-10-09  |  4KB  |  171 lines

  1. /* This file contains routines which put a file name into cannonical
  2.  * form.
  3.  */
  4.  
  5. #define NULL 0
  6.  
  7. /* define special name components */
  8.  
  9. static char slash[]  = "/" ;
  10. static char dot[]    = "." ;
  11. static char dotdot[] = ".." ;
  12.  
  13. /* nextc points to the next character to look at in the string or is
  14.  * null if the end of string was reached.
  15.  *
  16.  * namep points to buffer that holds the components.
  17.  */
  18. static char * nextc = NULL ;
  19. static char * namep ;
  20.  
  21. /* lexname - Return next name component. Uses global variables initialized
  22.  * by cannoname to figure out what it is scanning.
  23.  */
  24. static char *
  25. lexname()
  26. {
  27.    char   c ;
  28.    char * d ;
  29.  
  30.    if (nextc) {
  31.       c = *nextc++ ;
  32.       if (c == '\0') {
  33.          nextc = NULL ;
  34.          return(NULL) ;
  35.       }
  36.       if (c == '/') {
  37.          return(&slash[0]) ;
  38.       }
  39.       if (c == '.') {
  40.          if ((*nextc == '/') || (*nextc == '\0')) return(&dot[0]) ;
  41.          if (*nextc == '.' && (*(nextc+1) == '/' || *(nextc+1) == '\0')) {
  42.             ++nextc ;
  43.             return(&dotdot[0]) ;
  44.          }
  45.       }
  46.       d = namep;
  47.       *namep++ = c;
  48.       while ((c = *nextc) != '/') {
  49.          *namep++ = c ;
  50.          if (c == '\0') {
  51.             nextc = NULL ;
  52.             return(d) ;
  53.          }
  54.          ++nextc;
  55.       }
  56.       *namep++ = '\0' ;
  57.       return(d) ;
  58.    } else {
  59.       return(NULL) ;
  60.    }
  61. }
  62.  
  63. /* cannoname - Put a file name in cannonical form. Looks for all the
  64.  * whacky wonderful things a demented *ni* programmer might put
  65.  * in a file name and reduces the name to cannonical form.
  66.  */
  67. void
  68. cannoname(n)
  69.    char * n;
  70. {
  71.    char *  components[1024] ;
  72.    char ** cap = &components[0] ;
  73.    char ** cad ;
  74.    char *  cp ;
  75.    char    namebuf[2048] ;
  76.    char *  s ;
  77.  
  78.    /* initialize scanner */
  79.    nextc = n ;
  80.    namep = &namebuf[0] ;
  81.  
  82.    /* break the file name into individual components */
  83.    while ((cp = lexname()) != NULL) {
  84.       *cap++ = cp ;
  85.    }
  86.  
  87.    /* If name is empty, leave it that way */
  88.    if (cap == &components[0]) return ;
  89.  
  90.    /* flag end of component list */
  91.    *cap = NULL ;
  92.  
  93.    /* remove all trailing slashes and dots */
  94.    while ((--cap != &components[0]) &&
  95.           ((*cap == &slash[0]) || (*cap == &dot[0]))) *cap = NULL ;
  96.  
  97.    /* squeeze out all . / component sequences */
  98.    cap = &components[0] ;
  99.    cad = cap ;
  100.    while (*cap != NULL) {
  101.       if ((*cap == &dot[0]) && (*(cap+1) == &slash[0])) {
  102.          cap += 2;
  103.       } else {
  104.          *cad++ = *cap++ ;
  105.       }
  106.    }
  107.    *cad++ = NULL ;
  108.  
  109.    /* find multiple // and use last slash as root, except on apollo which
  110.     * apparently actually uses // in real file names (don't ask me why).
  111.     */
  112. #ifndef apollo
  113.    s = NULL ;
  114.    cap = &components[0] ;
  115.    cad = cap ;
  116.    while (*cap != NULL) {
  117.       if ((s == &slash[0]) && (*cap == &slash[0])) {
  118.          cad = &components[0];
  119.       }
  120.       s = *cap++;
  121.       *cad++ = s;
  122.    }
  123.    *cad = NULL ;
  124. #endif
  125.  
  126.    /* if this is absolute name get rid of any /.. at beginning */
  127.    if ((components[0] == &slash[0]) && (components[1] == &dotdot[0])) {
  128.       cap = &components[1] ;
  129.       cad = cap ;
  130.       while (*cap == &dotdot[0]) {
  131.          ++cap;
  132.          if (*cap == NULL) break ;
  133.          if (*cap == &slash[0]) ++cap ;
  134.       }
  135.       while (*cap != NULL) {
  136.          *cad++ = *cap++ ;
  137.       }
  138.       *cad = NULL ;
  139.    }
  140.  
  141.    /* squeeze out any name/.. sequences (but leave leading ../..) */
  142.    cap = &components[0] ;
  143.    cad = cap ;
  144.    while (*cap != NULL) {
  145.       if ((*cap == &dotdot[0]) &&
  146.           ((cad-2) >= &components[0]) &&
  147.           ((*(cad-2)) != &dotdot[0])) {
  148.          cad -= 2 ;
  149.          ++cap;
  150.          if (*cap != NULL) ++cap;
  151.       } else {
  152.          *cad++ = *cap++ ;
  153.       }
  154.    }
  155.    /* squeezing out a trailing /.. can leave unsightly trailing /s */
  156.    if ((cad >= &components[2]) && ((*(cad-1)) == &slash[0])) --cad ;
  157.    *cad = NULL ;
  158.    /* if it was just name/.. it now becomes . */
  159.    if (components[0] == NULL) {
  160.       components[0] = &dot[0] ;
  161.       components[1] = NULL ;
  162.    }
  163.  
  164.    /* re-assemble components */
  165.    cap = &components[0] ;
  166.    while ((s = *cap++) != NULL) {
  167.       while (*s != NULL) *n++ = *s++;
  168.    }
  169.    *n++ = '\0' ;
  170. }
  171.