diff options
Diffstat (limited to 'appl/lib/names.b')
| -rw-r--r-- | appl/lib/names.b | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/appl/lib/names.b b/appl/lib/names.b new file mode 100644 index 00000000..e15ce189 --- /dev/null +++ b/appl/lib/names.b @@ -0,0 +1,152 @@ +implement Names; + +include "sys.m"; + +include "names.m"; + +# return name rewritten to compress /+, eliminate ., and interpret .. + +cleanname(name: string): string +{ + if(name == nil) + return "."; + + p := rooted := name[0]=='/'; + if(name[0] == '#'){ # special + if(len name < 2) + return name; + p += 2; # character after # whatever it is, is the name (including /) + for(; p < len name; p++) + if(name[p] == '/') + break; + rooted = p; + } + dotdot := rooted; + + # + # invariants: + # p points at beginning of path element we're considering. + # out records up to the last path element (no trailing slash unless root or #/). + # dotdot points in out just past the point where .. cannot backtrack + # any further (no slash). + # + out := name[0:rooted]; + while(p < len name){ + for(q := p; p < len name && name[p] != '/'; p++){ + # skip + } + n := name[q:p]; # path element + p++; + case n { + "" or "." => + ; # null effect + ".." => + if(len out > dotdot){ # can backtrack + for(q = len out; --q > dotdot && out[q] != '/';) + ; + out = out[:q]; + }else if(!rooted){ # /.. is / but ./../ is .. + if(out != nil) + out += "/.."; + else + out += ".."; + dotdot = len out; + } + * => + if(rooted > 1 || len out > rooted) + out[len out] = '/'; + out += n; + } + } + if(out == nil) + return "."; + return out; +} + +dirname(name: string): string +{ + for(i := len name; --i >= 0;) + if(name[i] == '/') + break; + if(i < 0) + return nil; + d := name[0:i]; + if(d != nil) + return d; + if(name[0] == '/') + return "/"; + return nil; +} + +basename(name: string, suffix: string): string +{ + for(i := len name; --i >= 0;) + if(name[i] == '/') + break; + if(i >= 0) + name = name[i+1:]; + if(suffix != nil){ + o := len name - len suffix; + if(o >= 0 && name[o:] == suffix) + return name[0:o]; + } + return name; +} + +relative(name: string, root: string): string +{ + if(root == nil || name == nil) + return name; + if(isprefix(root, name)){ + name = name[len root:]; + while(name != nil && name[0] == '/') + name = name[1:]; + } + return name; +} + +rooted(root: string, name: string): string +{ + if(name == nil) + return root; + if(root == nil || name[0] == '/' || name[0] == '#') + return name; + if(root[len root-1] != '/' && name[0] != '/') + return root+"/"+name; + return root+name; +} + +isprefix(a: string, b: string): int +{ + la := len a; + while(la > 1 && a[la-1] == '/') + a = a[0:--la]; + lb := len b; + if(la > lb) + return 0; + if(la == lb) + return a == b; + return a == b[0:la] && b[la] == '/'; +} + +elements(name: string): list of string +{ + sys := load Sys Sys->PATH; + (nil, fld) := sys->tokenize(name, "/"); + if(name != nil && name[0] == '/') + fld = "/" :: fld; + return fld; +} + +pathname(els: list of string): string +{ + name: string; + sl := els != nil && hd els == "/"; + for(; els != nil; els = tl els){ + if(!sl) + name += "/"; + name += hd els; + sl = 0; + } + return name; +} |
