cleanname.c - 9base - revived minimalist port of Plan 9 userland to Unix
 (HTM) git clone git://git.suckless.org/9base
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       cleanname.c (1199B)
       ---
            1 #include <u.h>
            2 #include <libc.h>
            3 
            4 /*
            5  * In place, rewrite name to compress multiple /, eliminate ., and process ..
            6  */
            7 #define SEP(x)        ((x)=='/' || (x) == 0)
            8 char*
            9 cleanname(char *name)
           10 {
           11         char *p, *q, *dotdot;
           12         int rooted;
           13 
           14         rooted = name[0] == '/';
           15 
           16         /*
           17          * invariants:
           18          *        p points at beginning of path element we're considering.
           19          *        q points just past the last path element we wrote (no slash).
           20          *        dotdot points just past the point where .. cannot backtrack
           21          *                any further (no slash).
           22          */
           23         p = q = dotdot = name+rooted;
           24         while(*p) {
           25                 if(p[0] == '/')        /* null element */
           26                         p++;
           27                 else if(p[0] == '.' && SEP(p[1]))
           28                         p += 1;        /* don't count the separator in case it is nul */
           29                 else if(p[0] == '.' && p[1] == '.' && SEP(p[2])) {
           30                         p += 2;
           31                         if(q > dotdot) {        /* can backtrack */
           32                                 while(--q > dotdot && *q != '/')
           33                                         ;
           34                         } else if(!rooted) {        /* /.. is / but ./../ is .. */
           35                                 if(q != name)
           36                                         *q++ = '/';
           37                                 *q++ = '.';
           38                                 *q++ = '.';
           39                                 dotdot = q;
           40                         }
           41                 } else {        /* real path element */
           42                         if(q != name+rooted)
           43                                 *q++ = '/';
           44                         while((*q = *p) != '/' && *q != 0)
           45                                 p++, q++;
           46                 }
           47         }
           48         if(q == name)        /* empty string is really ``.'' */
           49                 *q++ = '.';
           50         *q = '\0';
           51         return name;
           52 }