static void texpand(struct table *tp, int nsize) { int i; struct tbl *tblp, **p; struct tbl **ntblp, **otblp = tp->tbls; int osize = tp->size; ntblp = areallocarray(NULL, nsize, sizeof(struct tbl *), tp->areap); for (i = 0; i < nsize; i++) ntblp[i] = NULL; tp->size = nsize; tp->nfree = 7*nsize/10; /* table can get 70% full */ tp->tbls = ntblp; if (otblp == NULL) return; for (i = 0; i < osize; i++) if ((tblp = otblp[i]) != NULL) { if ((tblp->flag&DEFINED)) { for (p = &ntblp[hash(tblp->name) & (tp->size-1)]; *p != NULL; p--) if (p == ntblp) /* wrap */ p += tp->size; *p = tblp; tp->nfree--; } else if (!(tblp->flag & FINUSE)) { afree(tblp, tp->areap); } } afree(otblp, tp->areap); }
static int x_command_glob(int flags, const char *str, int slen, char ***wordsp) { char *toglob; char *pat; char *fpath; int nwords; XPtrV w; struct block *l; if (slen < 0) return 0; toglob = add_glob(str, slen); /* Convert "foo*" (toglob) to a pattern for future use */ pat = evalstr(toglob, DOPAT|DOTILDE); afree(toglob, ATEMP); XPinit(w, 32); glob_table(pat, &w, &keywords); glob_table(pat, &w, &aliases); glob_table(pat, &w, &builtins); for (l = e->loc; l; l = l->next) glob_table(pat, &w, &l->funs); glob_path(flags, pat, &w, path); if ((fpath = str_val(global("FPATH"))) != null) glob_path(flags, pat, &w, fpath); nwords = XPsize(w); if (!nwords) { *wordsp = NULL; XPfree(w); return 0; } /* Sort entries */ if (flags & XCF_FULLPATH) { /* Sort by basename, then path order */ struct path_order_info *info; struct path_order_info *last_info = NULL; char **words = (char **) XPptrv(w); int path_order = 0; int i; info = areallocarray(NULL, nwords, sizeof(struct path_order_info), ATEMP); for (i = 0; i < nwords; i++) { info[i].word = words[i]; info[i].base = x_basename(words[i], NULL); if (!last_info || info[i].base != last_info->base || strncmp(words[i], last_info->word, info[i].base) != 0) { last_info = &info[i]; path_order++; } info[i].path_order = path_order; } qsort(info, nwords, sizeof(struct path_order_info), path_order_cmp); for (i = 0; i < nwords; i++) words[i] = info[i].word; afree(info, ATEMP); } else { /* Sort and remove duplicate entries */ char **words = (char **) XPptrv(w); int i, j; qsortp(XPptrv(w), (size_t) nwords, xstrcmp); for (i = j = 0; i < nwords - 1; i++) { if (strcmp(words[i], words[i + 1])) words[j++] = words[i]; else afree(words[i], ATEMP); } words[j++] = words[i]; nwords = j; w.cur = (void **) &words[j]; } XPput(w, NULL); *wordsp = (char **) XPclose(w); return nwords; }
static int x_try_array(const char *buf, int buflen, const char *want, int wantlen, int *nwords, char ***words) { const char *cmd, *cp; int cmdlen, n, i, slen; char *name, *s; struct tbl *v, *vp; *nwords = 0; *words = NULL; /* Walk back to find start of command. */ if (want == buf) return 0; for (cmd = want; cmd > buf; cmd--) { if (strchr(";|&()`", cmd[-1]) != NULL) break; } while (cmd < want && isspace((u_char)*cmd)) cmd++; cmdlen = 0; while (cmd + cmdlen < want && !isspace((u_char)cmd[cmdlen])) cmdlen++; for (i = 0; i < cmdlen; i++) { if (!isalnum((u_char)cmd[i]) && cmd[i] != '_') return 0; } /* Take a stab at argument count from here. */ n = 1; for (cp = cmd + cmdlen + 1; cp < want; cp++) { if (!isspace((u_char)cp[-1]) && isspace((u_char)*cp)) n++; } /* Try to find the array. */ if (asprintf(&name, "complete_%.*s_%d", cmdlen, cmd, n) < 0) internal_errorf("unable to allocate memory"); v = global(name); free(name); if (~v->flag & (ISSET|ARRAY)) { if (asprintf(&name, "complete_%.*s", cmdlen, cmd) < 0) internal_errorf("unable to allocate memory"); v = global(name); free(name); if (~v->flag & (ISSET|ARRAY)) return 0; } /* Walk the array and build words list. */ for (vp = v; vp; vp = vp->u.array) { if (~vp->flag & ISSET) continue; s = str_val(vp); slen = strlen(s); if (slen < wantlen) continue; if (slen > wantlen) slen = wantlen; if (slen != 0 && strncmp(s, want, slen) != 0) continue; *words = areallocarray(*words, (*nwords) + 2, sizeof **words, ATEMP); (*words)[(*nwords)++] = str_save(s, ATEMP); } if (*nwords != 0) (*words)[*nwords] = NULL; return *nwords != 0; }