/* * Path names. */ #include #include #include #include "names.h" enum { Incr = 128, }; extern void* emalloc(long); extern void* erealloc(void*, long); Name* n_new(void) { Name* n; n = emalloc(sizeof(Name)); n->elems = emalloc(MAXWELEM * sizeof(char*)); memset(n->elems, 0, MAXWELEM*sizeof(char*)); n->aelems= MAXWELEM; n->nelems= 0; n->base = emalloc(Incr); n->end = n->base + Incr; n->ptr = n->base; *n->ptr = 0; return n; } int namefmt(Fmt* f) { Name* n; char* buf; int bufsz; char* s; int i; int r; n = va_arg(f->args, Name*); if (!n) return fmtprint(f, "nil name"); bufsz = n->ptr - n->base + 1; if (bufsz == 1) bufsz++; // be sure we can keep "/" at least buf = emalloc(bufsz); s = buf; s[0] = '/'; s[1] = 0; for (i = 0; i < n->nelems; i++) s = seprint(s, buf + bufsz, "/%s", n->elems[i]); r = fmtprint(f, "%s", buf); free(buf); return r; } void n_reset(Name* n) { n->nelems = 0; n->ptr = n->base; } void n_append(Name* n, char* s) { int slen; int nlen; int alen; char* nbase; int i; slen = strlen(s); nlen = n->ptr - n->base; alen = n->end - n->base; while (alen < nlen + slen + 1){ // + 1 for zero nbase = erealloc(n->base, alen + Incr); alen += Incr; n->end = nbase + alen; n->ptr = nbase + nlen; for (i = 0; i < n->nelems && n->elems[i] != nil; i++) n->elems[i] = nbase + (n->elems[i] - n->base); n->base = n->base; } if (n->nelems == n->aelems){ n->aelems += MAXWELEM; n->elems = erealloc(n->elems, n->aelems * sizeof(char*)); } n->elems[n->nelems++] = n->ptr; strcpy(n->ptr, s); n->ptr += slen; *n->ptr++ = 0; } void n_dotdot(Name* n) { assert(n->nelems > 0); n->ptr = n->elems[--n->nelems]; } void n_getpos(Name* n, int* a, int* b) { *a = n->nelems; *b = n->ptr - n->base; } void n_setpos(Name* n, int a, int b) { n->nelems = a; n->ptr = n->base + b; assert(n->ptr >= n->base && n->ptr < n->end); } void n_cat(Name* cn, Name* n) { int i; for (i = 0; i < n->nelems; i++) n_append(cn, n->elems[i]); } int n_eq(Name* n1, Name* n2) { int i; if (n1 == nil || n2 == nil) return n1 == n2; if (n1->nelems != n2->nelems) return 0; // paths use to differ near the end. // check it out in reverse order. for (i = n1->nelems-1; i >=0; i--) if (strcmp(n1->elems[i], n2->elems[i])) return 0; return 1; } void n_free(Name* n) { free(n->base); free(n->elems); free(n); }