📄 complete.c
字号:
/**********Copyright 1990 Regents of the University of California. All rights reserved.Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD GroupModified: 1999 Paolo Nenzi**********//* * Command completion code. We keep a data structure with information on each * command, to make lookups fast. We also keep NCLASSES (which is sort of * hardwired as 32) sets of keywords. Each command has an array of NARGS * bitmasks (also hardwired as 4), stating whether the command takes that * particular class of keywords in that position. Class 0 always means * filename completion. */#include <config.h>#include "ngspice.h"#include "cpdefs.h"#include "complete.h"#ifdef HAVE_SYS_DIR_H#include <sys/types.h>#include <sys/dir.h>#else# ifdef HAVE_DIRENT_H# include <sys/types.h># include <dirent.h># ifndef direct# define direct dirent# endif# endif#endif#ifdef HAVE_PWD_H#include <pwd.h>#endif#ifndef __MINGW32__ /* MW. We also need ioctl.h here I think */#include <sys/ioctl.h>#endif/* Be sure the ioctls get included in the following */#ifdef HAVE_SGTTY_H#include <sgtty.h>#else#ifdef HAVE_TERMIO_H#include <termio.h>#else#ifdef HAVE_TERMIOS_H#include <termios.h>#endif#endif#endif#define CNTRL_D '\004'#define ESCAPE '\033'#define NCLASSES 32bool cp_nocc; /* Don't do command completion. */static struct ccom *commands = NULL; /* The available commands. */static struct ccom *keywords[NCLASSES]; /* Keywords. *//* static declarations */static struct ccom * getccom(char *first);static wordlist * ccfilec(char *buf);static wordlist * ccmatch(char *word, struct ccom **dbase);static void printem(wordlist *wl);static wordlist * cctowl(struct ccom *cc, bool sib);static struct ccom * clookup(register char *word, struct ccom **dd, bool pref, bool create);/* MW. I need top node in cdelete */static void cdelete(struct ccom *node, struct ccom **top);#ifdef TIOCSTIvoidcp_ccom(wordlist *wlist, char *buf, bool esc){ struct ccom *cc; wordlist *a, *pmatches = NULL; char wbuf[BSIZE_SP], *s; int i=0; int j, arg; buf = cp_unquote(copy(buf)); cp_wstrip(buf); if (wlist->wl_next) { /* Not the first word. */ cc = getccom(wlist->wl_word); if (cc && cc->cc_invalid) cc = NULL; arg = wl_length(wlist) - 2; if (arg > 3) arg = 3; /* First filenames. */ if (cc && (cc->cc_kwords[arg] & 1)) { pmatches = ccfilec(buf); s =strrchr(buf, '/'); i = strlen(s ? s + 1 : buf); if ((*buf == '~') && !index(buf, '/')) i--; } /* The keywords. */ for (j = 1; j < NCLASSES; j++) { if (cc && (cc->cc_kwords[arg] & (1 << j))) { /* Find all the matching keywords. */ a = ccmatch(buf, &keywords[j]); i = strlen(buf); if (pmatches) pmatches = wl_append(pmatches, a); else pmatches = a; } } wl_sort(pmatches); } else { pmatches = ccmatch(buf, &commands); i = strlen(buf); } tfree(buf); /*CDHW*/ if (!esc) { printem(pmatches); wl_free(pmatches); return; } if (pmatches == NULL) { (void) putchar('\07'); (void) fflush(cp_out); return; } if (pmatches->wl_next == NULL) { (void) strcpy(wbuf, &pmatches->wl_word[i]); goto found; } /* Now we know which words might work. Extend the command as much * as possible, then TIOCSTI the characters out. */ for (j = 0;; j++, i++) { wbuf[j] = pmatches->wl_word[i]; for (a = pmatches->wl_next; a; a = a->wl_next) if (a->wl_word[i] != wbuf[j]) { (void) putchar('\07'); (void) fflush(cp_out); wbuf[j] = '\0'; goto found; } if (wbuf[j] == '\0') goto found; }found: for (i = 0; wbuf[i]; i++) (void) ioctl(fileno(cp_in), TIOCSTI, &wbuf[i]); wl_free(pmatches); return;}/* Figure out what the command is, given the name. Returns NULL if there * is no such command in the command list. This is tricky, because we have * to do a preliminary history and alias parse. (Or at least we should.) */static struct ccom *getccom(char *first){ struct alias *al; int ntries = 21; /* First look for aliases. Just interested in the first word... * Don't bother doing history yet -- that might get complicated. */ while (ntries-- > 0) { for (al = cp_aliases; al; al = al->al_next) if (eq(first, al->al_name)) { first = al->al_text->wl_word; break; } if (al == NULL) break; } if (ntries == 0) { fprintf(cp_err, "\nError: alias loop.\n"); return (NULL); } return (clookup(first, &commands, FALSE, FALSE));}/* Figure out what files match the prefix. */static wordlist *ccfilec(char *buf){ DIR *wdir; char *lcomp, *dir; struct direct *de; wordlist *wl = NULL, *t; struct passwd *pw; buf = copy(buf); /* Don't mangle anything... */ lcomp =strrchr(buf, '/'); if (lcomp == NULL) { dir = "."; lcomp = buf; if (*buf == cp_til) { /* User name completion... */ buf++; while ((pw = getpwent())) { if (prefix(buf, pw->pw_name)) { if (wl == NULL) { wl = alloc(struct wordlist); wl->wl_next = NULL; wl->wl_prev = NULL; } else { t = wl; wl = alloc(struct wordlist); wl->wl_prev = NULL; wl->wl_next = t; t->wl_prev = wl; } wl->wl_word = copy(pw->pw_name); } } (void) endpwent(); return (wl); } } else { dir = buf; *lcomp = '\0'; lcomp++; if (*dir == cp_til) { dir = cp_tildexpand(dir); if (dir == NULL) return (NULL); } } if (!(wdir = opendir(dir))) return (NULL); while ((de = readdir(wdir))) if ((prefix(lcomp, de->d_name)) && (*lcomp || (*de->d_name != '.'))) { if (wl == NULL) { wl = alloc(struct wordlist); wl->wl_next = NULL; wl->wl_prev = NULL; } else { t = wl; wl = alloc(struct wordlist); wl->wl_next = t; t->wl_prev = wl; wl->wl_prev = NULL; } wl->wl_word = copy(de->d_name); } (void) closedir(wdir); wl_sort(wl); return (wl);}/* See what keywords or commands match the prefix. Check extra also * for matches, if it is non-NULL. Return a wordlist which is in * alphabetical order. Note that we have to call this once for each * class. */static wordlist *ccmatch(char *word, struct ccom **dbase){ wordlist *wl; register struct ccom *cc; cc = clookup(word, dbase, TRUE, FALSE); if (cc) { if (*word) /* This is a big drag. */ wl = cctowl(cc, FALSE); else wl = cctowl(cc, TRUE); } else wl = NULL; return (wl);}/* Print the words in the wordlist in columns. They are already * sorted... This is a hard thing to do with wordlists... */static voidprintem(wordlist *wl){ wordlist *ww; int maxl = 0, num, i, j, k, width = 79, ncols, nlines; (void) putchar('\n'); if (wl == NULL) { return; } num = wl_length(wl); for (ww = wl; ww; ww = ww->wl_next) { j = strlen(ww->wl_word); if (j > maxl) maxl = j; } if (++maxl % 8) maxl += 8 - (maxl % 8); ncols = width / maxl; if (ncols == 0) ncols = 1; nlines = num / ncols + (num % ncols ? 1 : 0); for (k = 0; k < nlines; k++) { for (i = 0; i < ncols; i++) { j = i * nlines + k; if (j < num) { fprintf(cp_out, "%-*s", maxl, wl_nthelem(j, wl)->wl_word); } else break; } (void) putchar('\n'); } return;}#else /* if not TIOCSTI */voidcp_ccom(wordlist *wlist, char *buf, bool esc){ return;}#endifstatic wordlist *cctowl(struct ccom *cc, bool sib){ wordlist *wl, *end; if (!cc) return (NULL); if (!cc->cc_invalid) { wl = alloc(struct wordlist); wl->wl_word = copy(cc->cc_name); wl->wl_prev = NULL; wl->wl_next = cctowl(cc->cc_child, TRUE); if (wl->wl_next) wl->wl_next->wl_prev = wl; } else wl = cctowl(cc->cc_child, TRUE); if (sib) { if (wl) { for (end = wl; end->wl_next; end = end->wl_next) ; end->wl_next = cctowl(cc->cc_sibling, TRUE); if (end->wl_next) end->wl_next->wl_prev = wl; } else wl = cctowl(cc->cc_sibling, TRUE); } return (wl);}/* We use this in com_device... */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -