tenex.c
来自「<B>Digital的Unix操作系统VAX 4.2源码</B>」· C语言 代码 · 共 1,873 行 · 第 1/3 页
C
1,873 行
return (NULL); return(context->curbfunc->bname); } else if (dirctr == CMD_ALIAS) return (getentry(VAR_WD,context,0)); /* Fall through */ case DIR_WD: /* get a directory entry */ { register struct direct *dirp; /* read a directory entry. None: exit. */ if (dirp = readdir (context->dir_fd)) return (dirp -> d_name); return (NULL); } case VAR_WD: /* get a variable entry */ /* Get next variable in list. None: exit. */ return(NULL); case HIST_WD: /* Get the next non-negative entry in the history list. Negative entries are "hidden". None: exit. */ do context->curhist = context->curhist->Hnext; while (context->curhist && context->curhist->Hnum < 0); return (context->curhist ? context->curhist->Hlex.next->word : NULL); }/* end switch(type) */}/* end getentry() *//* remove_duplicates Routine to remove adjacent duplicate entries from a sorted list and return a count of unique items and the width of the widest item. Duplicate entries are moved to the bottom of the list.*/staticremove_duplicates(items, count, widest)char *items[];register int *widest;{ register char **ip, **op; /* input and output pointers */ register int i = 0; register char *old_item = NULL; *widest = 0; /* clear any old max value */ if (count == 0) /* no entries: exit. */ return(0); /* afd fix 09: old_item starts out as NULL, so we can't do a strcmp on it. So, prime the pump with the first item. */ ip = op = items; *op++ = old_item = *ip; /* copy ip to op and old_item */ *widest = strlen (*ip); for (ip++; *ip; ip++) { /* If this is a duplicate, then release it and count it, otherwise move it to the proper place in the array and bump the output pointer to the next free slot; check for wider entry. */ if (strcmp(old_item,*ip) == 0) /* ip is a duplicate */ { free(*ip); /* free the duplicate */ i++; /* and keep a count of it */ } else { /* ip is not a duplicate */ *op++ = old_item = *ip; /* copy ip to op and old_item */ /* get the current max width */ *widest = max (*widest, strlen (*ip)); } }/* end for "each item" */ /* copy the array terminator also */ *op++ = *ip; return (count - i); /* return number of unique entries */}/* end remove_duplicates *//* print_by_column Print columns that are sorted downwards.*/staticprint_by_column (dir, items, count, maxwidth, type)char *dir;register char *items[];{ register int w, i, r, c; /* various indices */ register int rows; int columns; /* Add two spaces, one to separate columns and one to show the type of the file. (file type only if this is a directory list. */ maxwidth += (type == DIR_WD) ? 2 : 1; /* Determine the number of columns and rows. If this is a history listing or max item width is greater than the screen width, then assume one column. */ if (type == HIST_WD || maxwidth > SCREEN_WIDTH) columns = 1; else columns = SCREEN_WIDTH / maxwidth; rows = (count + (columns - 1)) / columns; for (r = 0; r < rows; r++) { for (c = 0; c < columns; c++) { i = c * rows + r; /* if it is valid, then print it */ if (i < count) { /* special output for history */ if (type == HIST_WD) print_history(items[i], maxwidth); else { csh_printf("%s", items[i]); /* 012 RNF */ w = strlen (items[i]); /* If this is a directory lookup, print filename followed by '/' or '*' or ' ' */ if (type == DIR_WD) { putchar (filetype (dir, items[i])); w++; } /* space between columns, if not last */ if (c < (columns - 1)) for (; w < maxwidth; w++) putchar (' '); } } }/* end for "each column" */ putchar('\n'); }/* end for "each row" */}/* end print_by_column() *//* print_words This routine prints the contents of a wordlist up to, the specified maximum length. If the wordlist exceeds this max length, it is truncated and a FALSE value is returned otherwise the routine returns TRUE.*/staticprint_words(start, end, maxlen)struct wordent *start, *end;register int maxlen;{ register char *wp; /* print each character in the word separated by a space, until we exceed the maximum length or we run out of words. Exceeding maximum length causes a FALSE return. */ for (;;maxlen--) { for (wp = start->word; *wp; wp++) if (--maxlen <= 1) return (FALSE); else putchar(*wp); start = start->next; if (start == end) break; putchar(' '); } return (TRUE);}/* end print_words() *//* print_history This routine will print the first history entry found in the history list, with the rest of the history event text appearing parentheses after the entry. item points to a history keyword. maxwidth is the width of the widest history keyword.*/staticprint_history(item, maxwidth)register char *item;{#define COLWID 2 register int colw; /* used for column positioning */ register struct wordent *wp; /* local word pointer */ register char *ep; /* local entry pointer */ struct Hist *hp; /* local history pointer */ /* add spaces to separate history word from contents */ maxwidth += COLWID; /* Search the history list for each item and print the first matching history entry in its entirety. */ hp = &Histlist; do ep = getentry(HIST_WD, &hp, 0); while (ep && strcmp(ep,item)); /* If none exit, otherwise print it. */ if (ep == 0) return; csh_printf(" %s",ep); /* print match word */ /* 012 RNF */ /* Print the (contents) column, if there is one. */ if ((wp = hp->Hlex.next->next) != hp->Hlex.prev) { for (colw = strlen(ep); colw < maxwidth; colw++) putchar(' '); /* Print as much of the contents as possible. */ putchar('('); if (!print_words( wp, hp->Hlex.prev, SCREEN_WIDTH - maxwidth - (COLWID + 2))) csh_printf("..."); /* truncated */ /* 012 RNF */ putchar(')'); }}/* end print_history() *//* free_items Deallocate space for the specified item list. Item list ends with a 0 entry.*/staticfree_items (items)register char **items;{ register int i; /* free individual items */ for (i = 0; items[i]; i++) free (items[i]); /* free the vector itself */ free ((char*)items);}/* end free_items() *//* FREE_ITEMS Macro to properly call above.*/#define FREE_ITEMS(items)\{\ int omask;\ omask = sigblock(sigmask(SIGINT));\ free_items (items);\ items = NULL;\ (void) sigsetmask(omask);\}/* FREE_DIR Macro to release a directory*/#define FREE_DIR(fd)\{\ int omask;\ omask = sigblock(sigmask(SIGINT));\ closedir (fd);\ fd = NULL;\ (void) sigsetmask(omask);\}/* get_dir_from_path Only called when type == CMD_WD. Get the next directory from the path list; return ptr to next unstripped directory. A path list is a list of directory paths separated by colons or spaces. Increments dirctr. If it is non-negative, then it extracts a directory from the path, otherwise it just returns the path without change.*/char *get_dir_from_path (path, dir, dirctr, dirflag)char *path, dir[], *dirflag;int *dirctr;{ register char *d = dir; /* Increment the directory counter, if it is negative, then return path w/o change. */ if (++(*dirctr) < 0) return (path); /* skip past separators */ while (*path && (*path == ' ' || *path == ':')) path++; /* Copy the dir name */ while (*path && (*path != ' ' && *path != ':')) *(d++) = *(path++); *(d++) = '/'; /* put a trailing slash on the path */ *d = 0; /* Skip past the next separator */ while (*path && (*path == ' ' || *path == ':')) path++; if (*dir == '.') strcpy (dirflag, " ."); else { *dirflag++ = ' '; if (*dirctr <= 9) *dirflag++ = '0' + *dirctr; else { *dirflag++ = '0' + *dirctr / 10; *dirflag++ = '0' + *dirctr % 10; } *dirflag++ = '\0'; } return (path);}/* end get_dir_from_path() *//* item_search The heart of the tenex module. Perform a RECOGNIZE or LIST command on string "word".*/staticitem_search (word, wp, command, routine, max_word_length, looking_for_command)char *word, *wp; /* original start and end-of-word */COMMAND command; /* action: list or recognize */int (*routine) ();{ register numitems, name_length, /* Length of prefix (file name) */ findtype; /* The kind of item to search for */ int showpathn; /* True if we want path number */ struct stat dot_statb, /* Stat buffer for "." */ curdir_statb; /* Stat buffer for current directory */ int dot_scan, /* True if scanning "." */ dot_got; /* True if have scanned dot already */ int dirctr = 0; /* -2,-1 (for BUILTINS), 0,1,2 ...(for dirlist pos)*/ char dirflag[5]; /* ' nn\0' - dir #s - . 1 2 ... */ char *getentry(); char tilded_dir[FILSIZ + 1], /* dir after ~ expansion */ dir[FILSIZ + 1], /* /x/y/z/ part in /x/y/z/f */ name[MAXNAMLEN + 1], /* f part in /d/d/d/f */ extended_name[MAXNAMLEN+1],/* the recognized (extended) name */ *entry, /* single directory entry or logname */ *path; /* hacked PATH environment variable */ union entry_context context; /* entry context, used all over */ static char **items; /* list of found entries */ context.dir_fd = NULL; /* initialize the context */ /* decide what we're looking for */ switch (*word) { case '$': /* variable name */ findtype = VAR_WD; return(0); /* NOTREACHED */ break; case '~': /* login names */ if (index(word,'/') == NULL) { findtype = LNAM_WD; break; } /* Fall through if not LNAM */ default: /* hist expansion */ /* HIST_WD check is processed here because HIST is not a constant expression and so cannot be part of a case. */ if (*word == HIST) /* hist expansion */ findtype = HIST_WD; else if (looking_for_command) /* command position? */ findtype = CMD_WD; else findtype = DIR_WD; /* Default: dir search */ break; }/* end switch (type) */ /* If the user has specified a directory then don't do command path searching, but do normal directory searching. */ if (findtype == CMD_WD && index(word,'/')) findtype = DIR_WD; /* Special setup for command search. Setup for BUILTINs and aliases. */ if (findtype == CMD_WD) { dirctr = CMD_BUILTIN; /* set BUILTINS code */ dirflag[0] = NULL; /* get the current path for command searching */ if ((path = getenv("PATH")) == NULL) path = ""; } numitems = 0; dot_got = FALSE; /* afd fix 09: This must be explicitly initialized (it wasn't on VAX) */ dot_scan = FALSE; stat (".", &dot_statb); do /* One loop per directory in PATH, if findtype == CMD_WD */ { /* Perform the necessary item source initializations. */ switch (findtype) { case LNAM_WD: /* login names */ /* Open pw file, copy word w/o '~' */ setpwent (); copyn (name, &word[1], MAXNAMLEN); break; case DIR_WD: /* Normal dir search */ /* Expand the given directory and open it, if valid. */ extract_dir_and_name (word, dir, name); if (!tilde(tilded_dir, dir) || !(context.dir_fd = opendir (*tilded_dir ? tilded_dir : "."))) return (0); dot_scan = FALSE; break; case CMD_WD: /* Command keyword */ switch (dirctr) { case CMD_BUILTIN: /* Set flag, name and context for builtin function names. Context is set one entry back because getentry() always increments the context ptr prior to access. */ strcpy(dirflag," -"); copyn(name,word,MAXNAMLEN); context.curbfunc = &bfunc[-1]; bfuncnum = 0; break; case CMD_ALIAS: /* Set flag, name and context for aliases. Alise structure is identical to variable structure, but with a different head. */ strcpy(dirflag," +"); copyn(name,word,MAXNAMLEN); context.curvar = &aliases; break; default: /* Expand the passed name, open dir, if valid get next path dir if not valid. */ if (!tilde(tilded_dir, dir) || !(context.dir_fd = opendir (*tilded_dir ? tilded_dir : "."))) continue; dot_scan = FALSE; /* Are we searching "."? */ fstat (context.dir_fd->dd_fd, &curdir_statb); if (curdir_statb.st_dev == dot_statb.st_dev && curdir_statb.st_ino == dot_statb.st_ino) { if (dot_got) /* Second time in PATH? */ continue; dot_scan = TRUE; dot_got = TRUE; } break; }/* end switch (dirctr) */ break; case VAR_WD: /* Variable names */ /* Copy name w/o '$'. Init the current variable ptr to the head of the sorted list. */ copyn (name, &word[1], MAXNAMLEN); context.curvar = &shvhed; break; case HIST_WD: /* History keywords */ /* Copy the name w/o HIST char. Init the current variable ptr to the head of the history list. Entries are in "most recent" order. */ copyn (name, &word[1], MAXNAMLEN); context.curhist = &Histlist; break; }/* end switch (findtype) */ name_length = strlen (name); showpathn = findtype == CMD_WD && is_set("listpathnum"); /* Search the source lists for items that match the user's typed in word. */ while ( entry = getentry (findtype, &context, dirctr)) { if (!is_prefix (name, entry)) continue; /*
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?