tw.parse.c revision 100616
1100616Smp/* $Header: /src/pub/tcsh/tw.parse.c,v 3.92 2002/06/25 19:02:12 christos Exp $ */ 259243Sobrien/* 359243Sobrien * tw.parse.c: Everyone has taken a shot in this futile effort to 459243Sobrien * lexically analyze a csh line... Well we cannot good 559243Sobrien * a job as good as sh.lex.c; but we try. Amazing that 659243Sobrien * it works considering how many hands have touched this code 759243Sobrien */ 859243Sobrien/*- 959243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California. 1059243Sobrien * All rights reserved. 1159243Sobrien * 1259243Sobrien * Redistribution and use in source and binary forms, with or without 1359243Sobrien * modification, are permitted provided that the following conditions 1459243Sobrien * are met: 1559243Sobrien * 1. Redistributions of source code must retain the above copyright 1659243Sobrien * notice, this list of conditions and the following disclaimer. 1759243Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1859243Sobrien * notice, this list of conditions and the following disclaimer in the 1959243Sobrien * documentation and/or other materials provided with the distribution. 20100616Smp * 3. Neither the name of the University nor the names of its contributors 2159243Sobrien * may be used to endorse or promote products derived from this software 2259243Sobrien * without specific prior written permission. 2359243Sobrien * 2459243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2559243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2659243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2759243Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2859243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2959243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3059243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3159243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3259243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3359243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3459243Sobrien * SUCH DAMAGE. 3559243Sobrien */ 3659243Sobrien#include "sh.h" 3759243Sobrien 38100616SmpRCSID("$Id: tw.parse.c,v 3.92 2002/06/25 19:02:12 christos Exp $") 3959243Sobrien 4059243Sobrien#include "tw.h" 4159243Sobrien#include "ed.h" 4259243Sobrien#include "tc.h" 4359243Sobrien 4469408Sache#ifdef WINNT_NATIVE 4559243Sobrien#include "nt.const.h" 4669408Sache#endif /* WINNT_NATIVE */ 4759243Sobrien#define EVEN(x) (((x) & 1) != 1) 4859243Sobrien 4959243Sobrien#define DOT_NONE 0 /* Don't display dot files */ 5059243Sobrien#define DOT_NOT 1 /* Don't display dot or dot-dot */ 5159243Sobrien#define DOT_ALL 2 /* Display all dot files */ 5259243Sobrien 5359243Sobrien/* TW_NONE, TW_COMMAND, TW_VARIABLE, TW_LOGNAME, */ 5459243Sobrien/* TW_FILE, TW_DIRECTORY, TW_VARLIST, TW_USER, */ 5559243Sobrien/* TW_COMPLETION, TW_ALIAS, TW_SHELLVAR, TW_ENVVAR, */ 5659243Sobrien/* TW_BINDING, TW_WORDLIST, TW_LIMIT, TW_SIGNAL */ 5759243Sobrien/* TW_JOB, TW_EXPLAIN, TW_TEXT, TW_GRPNAME */ 5859243Sobrienstatic void (*tw_start_entry[]) __P((DIR *, Char *)) = { 5959243Sobrien tw_file_start, tw_cmd_start, tw_var_start, tw_logname_start, 6059243Sobrien tw_file_start, tw_file_start, tw_vl_start, tw_logname_start, 6159243Sobrien tw_complete_start, tw_alias_start, tw_var_start, tw_var_start, 6259243Sobrien tw_bind_start, tw_wl_start, tw_limit_start, tw_sig_start, 6359243Sobrien tw_job_start, tw_file_start, tw_file_start, tw_grpname_start 6459243Sobrien}; 6559243Sobrien 6659243Sobrienstatic Char * (*tw_next_entry[]) __P((Char *, int *)) = { 6759243Sobrien tw_file_next, tw_cmd_next, tw_var_next, tw_logname_next, 6859243Sobrien tw_file_next, tw_file_next, tw_var_next, tw_logname_next, 6959243Sobrien tw_var_next, tw_var_next, tw_shvar_next, tw_envvar_next, 7059243Sobrien tw_bind_next, tw_wl_next, tw_limit_next, tw_sig_next, 7159243Sobrien tw_job_next, tw_file_next, tw_file_next, tw_grpname_next 7259243Sobrien}; 7359243Sobrien 7459243Sobrienstatic void (*tw_end_entry[]) __P((void)) = { 7559243Sobrien tw_dir_end, tw_dir_end, tw_dir_end, tw_logname_end, 7659243Sobrien tw_dir_end, tw_dir_end, tw_dir_end, tw_logname_end, 7759243Sobrien tw_dir_end, tw_dir_end, tw_dir_end, tw_dir_end, 7859243Sobrien tw_dir_end, tw_dir_end, tw_dir_end, tw_dir_end, 7959243Sobrien tw_dir_end, tw_dir_end, tw_dir_end, tw_grpname_end 8059243Sobrien}; 8159243Sobrien 8259243Sobrien/* #define TDEBUG */ 8359243Sobrien 8459243Sobrien/* Set to TRUE if recexact is set and an exact match is found 8559243Sobrien * along with other, longer, matches. 8659243Sobrien */ 8759243Sobrien 8859243Sobrienint curchoice = -1; 8959243Sobrien 9059243Sobrienint match_unique_match = FALSE; 9159243Sobrienint non_unique_match = FALSE; 9259243Sobrienstatic bool SearchNoDirErr = 0; /* t_search returns -2 if dir is unreadable */ 9359243Sobrien 9459243Sobrien/* state so if a completion is interrupted, the input line doesn't get 9559243Sobrien nuked */ 9659243Sobrienint InsideCompletion = 0; 9759243Sobrien 9859243Sobrien/* do the expand or list on the command line -- SHOULD BE REPLACED */ 9959243Sobrien 10059243Sobrienextern Char NeedsRedraw; /* from ed.h */ 10159243Sobrienextern int Tty_raw_mode; 10259243Sobrienextern int TermH; /* from the editor routines */ 10359243Sobrienextern int lbuffed; /* from sh.print.c */ 10459243Sobrien 10559243Sobrienstatic void extract_dir_and_name __P((Char *, Char *, Char *)); 10659243Sobrienstatic int insert_meta __P((Char *, Char *, Char *, bool)); 10759243Sobrienstatic Char *tilde __P((Char *, Char *)); 10869408Sache#ifndef __MVS__ 10959243Sobrienstatic int expand_dir __P((Char *, Char *, DIR **, COMMAND)); 11069408Sache#endif 11159243Sobrienstatic bool nostat __P((Char *)); 11259243Sobrienstatic Char filetype __P((Char *, Char *)); 11359243Sobrienstatic int t_glob __P((Char ***, int)); 11459243Sobrienstatic int c_glob __P((Char ***)); 11559243Sobrienstatic int is_prefix __P((Char *, Char *)); 11659243Sobrienstatic int is_prefixmatch __P((Char *, Char *, int)); 11759243Sobrienstatic int is_suffix __P((Char *, Char *)); 11859243Sobrienstatic int recognize __P((Char *, Char *, int, int, int)); 11959243Sobrienstatic int ignored __P((Char *)); 12059243Sobrienstatic int isadirectory __P((Char *, Char *)); 12169408Sache#ifndef __MVS__ 12259243Sobrienstatic int tw_collect_items __P((COMMAND, int, Char *, Char *, 12359243Sobrien Char *, Char *, int)); 12459243Sobrienstatic int tw_collect __P((COMMAND, int, Char *, Char *, 12559243Sobrien Char **, Char *, int, DIR *)); 12669408Sache#endif 12759243Sobrienstatic Char tw_suffix __P((int, Char *, Char *, Char *, 12859243Sobrien Char *)); 12959243Sobrienstatic void tw_fixword __P((int, Char *, Char *, Char *, int)); 13059243Sobrienstatic void tw_list_items __P((int, int, int)); 13159243Sobrienstatic void add_scroll_tab __P((Char *)); 13259243Sobrienstatic void choose_scroll_tab __P((Char **, int)); 13359243Sobrienstatic void free_scroll_tab __P((void)); 13459243Sobrienstatic int find_rows __P((Char *[], int, int)); 13559243Sobrien 13659243Sobrien#ifdef notdef 13759243Sobrien/* 13859243Sobrien * If we find a set command, then we break a=b to a= and word becomes 13959243Sobrien * b else, we don't break a=b. [don't use that; splits words badly and 14059243Sobrien * messes up tw_complete()] 14159243Sobrien */ 14259243Sobrien#define isaset(c, w) ((w)[-1] == '=' && \ 14359243Sobrien ((c)[0] == 's' && (c)[1] == 'e' && (c)[2] == 't' && \ 14459243Sobrien ((c[3] == ' ' || (c)[3] == '\t')))) 14559243Sobrien#endif 14659243Sobrien 14759243Sobrien#define QLINESIZE (INBUFSIZE + 1) 14859243Sobrien 14959243Sobrien/* TRUE if character must be quoted */ 15059243Sobrien#define tricky(w) (cmap(w, _META | _DOL | _QF | _QB | _ESC | _GLOB) && w != '#') 15159243Sobrien/* TRUE if double quotes don't protect character */ 15259243Sobrien#define tricky_dq(w) (cmap(w, _DOL | _QB)) 15359243Sobrien 15459243Sobrien/* tenematch(): 15559243Sobrien * Return: 15659243Sobrien * > 1: No. of items found 15759243Sobrien * = 1: Exactly one match / spelling corrected 15859243Sobrien * = 0: No match / spelling was correct 15959243Sobrien * < 0: Error (incl spelling correction impossible) 16059243Sobrien */ 16159243Sobrienint 16259243Sobrientenematch(inputline, num_read, command) 16359243Sobrien Char *inputline; /* match string prefix */ 16459243Sobrien int num_read; /* # actually in inputline */ 16559243Sobrien COMMAND command; /* LIST or RECOGNIZE or PRINT_HELP */ 16659243Sobrien 16759243Sobrien{ 16859243Sobrien Char qline[QLINESIZE]; 16959243Sobrien Char qu = 0, *pat = STRNULL; 17059243Sobrien Char *str_end, *cp, *wp, *wordp; 17159243Sobrien Char *cmd_start, *word_start, *word; 17259243Sobrien Char *ocmd_start = NULL, *oword_start = NULL, *oword = NULL; 17359243Sobrien int suf = 0; 17459243Sobrien int space_left; 17559243Sobrien int looking; /* what we are looking for */ 17659243Sobrien int search_ret; /* what search returned for debugging */ 17759243Sobrien int backq = 0; 17859243Sobrien 17959243Sobrien if (num_read > QLINESIZE - 1) 18059243Sobrien return -1; 18159243Sobrien str_end = &inputline[num_read]; 18259243Sobrien 18359243Sobrien word_start = inputline; 18459243Sobrien word = cmd_start = wp = qline; 18559243Sobrien for (cp = inputline; cp < str_end; cp++) { 18659243Sobrien if (!cmap(qu, _ESC)) { 18759243Sobrien if (cmap(*cp, _QF|_ESC)) { 18859243Sobrien if (qu == 0 || qu == *cp) { 18959243Sobrien qu ^= *cp; 19059243Sobrien continue; 19159243Sobrien } 19259243Sobrien } 19359243Sobrien if (qu != '\'' && cmap(*cp, _QB)) { 19459243Sobrien if ((backq ^= 1) != 0) { 19559243Sobrien ocmd_start = cmd_start; 19659243Sobrien oword_start = word_start; 19759243Sobrien oword = word; 19859243Sobrien word_start = cp + 1; 19959243Sobrien word = cmd_start = wp + 1; 20059243Sobrien } 20159243Sobrien else { 20259243Sobrien cmd_start = ocmd_start; 20359243Sobrien word_start = oword_start; 20459243Sobrien word = oword; 20559243Sobrien } 20659243Sobrien *wp++ = *cp; 20759243Sobrien continue; 20859243Sobrien } 20959243Sobrien } 21059243Sobrien if (iscmdmeta(*cp)) 21159243Sobrien cmd_start = wp + 1; 21259243Sobrien 21359243Sobrien /* Don't quote '/' to make the recognize stuff work easily */ 21459243Sobrien /* Don't quote '$' in double quotes */ 21559243Sobrien 21659243Sobrien if (cmap(*cp, _ESC) && cp < str_end - 1 && cp[1] == HIST) 21759243Sobrien *wp = *++cp | QUOTE; 21859243Sobrien else if (qu && (tricky(*cp) || *cp == '~') && !(qu == '\"' && tricky_dq(*cp))) 21959243Sobrien *wp = *cp | QUOTE; 22059243Sobrien else 22159243Sobrien *wp = *cp; 22259243Sobrien if (ismetahash(*wp) /* || isaset(cmd_start, wp + 1) */) 22359243Sobrien word = wp + 1, word_start = cp + 1; 22459243Sobrien wp++; 22559243Sobrien if (cmap(qu, _ESC)) 22659243Sobrien qu = 0; 22759243Sobrien } 22859243Sobrien *wp = 0; 22959243Sobrien 23059243Sobrien#ifdef masscomp 23159243Sobrien /* 23259243Sobrien * Avoid a nasty message from the RTU 4.1A & RTU 5.0 compiler concerning 23359243Sobrien * the "overuse of registers". According to the compiler release notes, 23459243Sobrien * incorrect code may be produced unless the offending expression is 23559243Sobrien * rewritten. Therefore, we can't just ignore it, DAS DEC-90. 23659243Sobrien */ 23759243Sobrien space_left = QLINESIZE - 1; 23859243Sobrien space_left -= word - qline; 23959243Sobrien#else 24059243Sobrien space_left = QLINESIZE - 1 - (int) (word - qline); 24159243Sobrien#endif 24259243Sobrien 24359243Sobrien /* 24459243Sobrien * SPECIAL HARDCODED COMPLETIONS: 24559243Sobrien * first word of command -> TW_COMMAND 24659243Sobrien * everything else -> TW_ZERO 24759243Sobrien * 24859243Sobrien */ 24959243Sobrien looking = starting_a_command(word - 1, qline) ? 25059243Sobrien TW_COMMAND : TW_ZERO; 25159243Sobrien 25259243Sobrien wordp = word; 25359243Sobrien 25459243Sobrien#ifdef TDEBUG 25559243Sobrien xprintf(CGETS(30, 1, "starting_a_command %d\n"), looking); 25659243Sobrien xprintf("\ncmd_start:%S:\n", cmd_start); 25759243Sobrien xprintf("qline:%S:\n", qline); 25859243Sobrien xprintf("qline:"); 25959243Sobrien for (wp = qline; *wp; wp++) 26059243Sobrien xprintf("%c", *wp & QUOTE ? '-' : ' '); 26159243Sobrien xprintf(":\n"); 26259243Sobrien xprintf("word:%S:\n", word); 26359243Sobrien xprintf("word:"); 26459243Sobrien /* Must be last, so wp is still pointing to the end of word */ 26559243Sobrien for (wp = word; *wp; wp++) 26659243Sobrien xprintf("%c", *wp & QUOTE ? '-' : ' '); 26759243Sobrien xprintf(":\n"); 26859243Sobrien#endif 26959243Sobrien 27059243Sobrien if ((looking == TW_COMMAND || looking == TW_ZERO) && 27159243Sobrien (command == RECOGNIZE || command == LIST || command == SPELL || 27259243Sobrien command == RECOGNIZE_SCROLL)) { 27359243Sobrien#ifdef TDEBUG 27459243Sobrien xprintf(CGETS(30, 2, "complete %d "), looking); 27559243Sobrien#endif 27659243Sobrien looking = tw_complete(cmd_start, &wordp, &pat, looking, &suf); 27759243Sobrien#ifdef TDEBUG 27859243Sobrien xprintf(CGETS(30, 3, "complete %d %S\n"), looking, pat); 27959243Sobrien#endif 28059243Sobrien } 28159243Sobrien 28259243Sobrien switch (command) { 28359243Sobrien Char buffer[FILSIZ + 1], *bptr; 28459243Sobrien Char *slshp; 28559243Sobrien Char *items[2], **ptr; 28659243Sobrien int i, count; 28759243Sobrien 28859243Sobrien case RECOGNIZE: 28959243Sobrien case RECOGNIZE_SCROLL: 29059243Sobrien case RECOGNIZE_ALL: 29159243Sobrien if (adrof(STRautocorrect)) { 29259243Sobrien if ((slshp = Strrchr(wordp, '/')) != NULL && slshp[1] != '\0') { 29359243Sobrien SearchNoDirErr = 1; 29459243Sobrien for (bptr = wordp; bptr < slshp; bptr++) { 29559243Sobrien /* 29659243Sobrien * do not try to correct spelling of words containing 29759243Sobrien * globbing characters 29859243Sobrien */ 29959243Sobrien if (isglob(*bptr)) { 30059243Sobrien SearchNoDirErr = 0; 30159243Sobrien break; 30259243Sobrien } 30359243Sobrien } 30459243Sobrien } 30559243Sobrien } 30659243Sobrien else 30759243Sobrien slshp = STRNULL; 30859243Sobrien search_ret = t_search(wordp, wp, command, space_left, looking, 1, 30959243Sobrien pat, suf); 31059243Sobrien SearchNoDirErr = 0; 31159243Sobrien 31259243Sobrien if (search_ret == -2) { 31359243Sobrien Char rword[FILSIZ + 1]; 31459243Sobrien 31559243Sobrien (void) Strcpy(rword, slshp); 31659243Sobrien if (slshp != STRNULL) 31759243Sobrien *slshp = '\0'; 31859243Sobrien search_ret = spell_me(wordp, QLINESIZE - (wordp - qline), looking, 31959243Sobrien pat, suf); 32059243Sobrien if (search_ret == 1) { 32159243Sobrien (void) Strcat(wordp, rword); 32259243Sobrien wp = wordp + (int) Strlen(wordp); 32359243Sobrien search_ret = t_search(wordp, wp, command, space_left, 32459243Sobrien looking, 1, pat, suf); 32559243Sobrien } 32659243Sobrien } 32759243Sobrien if (*wp && insert_meta(word_start, str_end, word, !qu) < 0) 32859243Sobrien return -1; /* error inserting */ 32959243Sobrien return search_ret; 33059243Sobrien 33159243Sobrien case SPELL: 33259243Sobrien for (bptr = word_start; bptr < str_end; bptr++) { 33359243Sobrien /* 33459243Sobrien * do not try to correct spelling of words containing globbing 33559243Sobrien * characters 33659243Sobrien */ 33759243Sobrien if (isglob(*bptr)) 33859243Sobrien return 0; 33959243Sobrien } 34059243Sobrien search_ret = spell_me(wordp, QLINESIZE - (wordp - qline), looking, 34159243Sobrien pat, suf); 34259243Sobrien if (search_ret == 1) { 34359243Sobrien if (insert_meta(word_start, str_end, word, !qu) < 0) 34459243Sobrien return -1; /* error inserting */ 34559243Sobrien } 34659243Sobrien return search_ret; 34759243Sobrien 34859243Sobrien case PRINT_HELP: 34959243Sobrien do_help(cmd_start); 35059243Sobrien return 1; 35159243Sobrien 35259243Sobrien case GLOB: 35359243Sobrien case GLOB_EXPAND: 35459243Sobrien (void) Strncpy(buffer, wordp, FILSIZ + 1); 35559243Sobrien items[0] = buffer; 35659243Sobrien items[1] = NULL; 35759243Sobrien ptr = items; 35859243Sobrien count = (looking == TW_COMMAND && Strchr(wordp, '/') == 0) ? 35959243Sobrien c_glob(&ptr) : 36059243Sobrien t_glob(&ptr, looking == TW_COMMAND); 36159243Sobrien if (count > 0) { 36259243Sobrien if (command == GLOB) 36359243Sobrien print_by_column(STRNULL, ptr, count, 0); 36459243Sobrien else { 36559243Sobrien DeleteBack(str_end - word_start);/* get rid of old word */ 36659243Sobrien for (i = 0; i < count; i++) 36759243Sobrien if (ptr[i] && *ptr[i]) { 36859243Sobrien (void) quote(ptr[i]); 36959243Sobrien if (insert_meta(0, 0, ptr[i], 0) < 0 || 37059243Sobrien InsertStr(STRspace) < 0) { 37159243Sobrien blkfree(ptr); 37259243Sobrien return -1; /* error inserting */ 37359243Sobrien } 37459243Sobrien } 37559243Sobrien } 37659243Sobrien blkfree(ptr); 37759243Sobrien } 37859243Sobrien return count; 37959243Sobrien 38059243Sobrien case VARS_EXPAND: 38159243Sobrien if (dollar(buffer, word)) { 38259243Sobrien if (insert_meta(word_start, str_end, buffer, !qu) < 0) 38359243Sobrien return -1; /* error inserting */ 38459243Sobrien return 1; 38559243Sobrien } 38659243Sobrien return 0; 38759243Sobrien 38859243Sobrien case PATH_NORMALIZE: 38959243Sobrien if ((bptr = dnormalize(wordp, symlinks == SYM_IGNORE || 39059243Sobrien symlinks == SYM_EXPAND)) != NULL) { 39159243Sobrien (void) Strcpy(buffer, bptr); 39259243Sobrien xfree((ptr_t) bptr); 39359243Sobrien if (insert_meta(word_start, str_end, buffer, !qu) < 0) 39459243Sobrien return -1; /* error inserting */ 39559243Sobrien return 1; 39659243Sobrien } 39759243Sobrien return 0; 39859243Sobrien 39959243Sobrien case COMMAND_NORMALIZE: 40059243Sobrien if (!cmd_expand(wordp, buffer)) 40159243Sobrien return 0; 40259243Sobrien if (insert_meta(word_start, str_end, buffer, !qu) < 0) 40359243Sobrien return -1; /* error inserting */ 40459243Sobrien return 1; 40559243Sobrien 40659243Sobrien case LIST: 40759243Sobrien case LIST_ALL: 40859243Sobrien search_ret = t_search(wordp, wp, LIST, space_left, looking, 1, 40959243Sobrien pat, suf); 41059243Sobrien return search_ret; 41159243Sobrien 41259243Sobrien default: 41359243Sobrien xprintf(CGETS(30, 4, "%s: Internal match error.\n"), progname); 41459243Sobrien return 1; 41559243Sobrien 41659243Sobrien } 41759243Sobrien} /* end tenematch */ 41859243Sobrien 41959243Sobrien 42059243Sobrien/* t_glob(): 42159243Sobrien * Return a list of files that match the pattern 42259243Sobrien */ 42359243Sobrienstatic int 42459243Sobrient_glob(v, cmd) 42559243Sobrien register Char ***v; 42659243Sobrien int cmd; 42759243Sobrien{ 42859243Sobrien jmp_buf_t osetexit; 42959243Sobrien 43059243Sobrien if (**v == 0) 43159243Sobrien return (0); 43259243Sobrien gflag = 0, tglob(*v); 43359243Sobrien if (gflag) { 43459243Sobrien getexit(osetexit); /* make sure to come back here */ 43559243Sobrien if (setexit() == 0) 43659243Sobrien *v = globall(*v); 43759243Sobrien resexit(osetexit); 43859243Sobrien gargv = 0; 43959243Sobrien if (haderr) { 44059243Sobrien haderr = 0; 44159243Sobrien NeedsRedraw = 1; 44259243Sobrien return (-1); 44359243Sobrien } 44459243Sobrien if (*v == 0) 44559243Sobrien return (0); 44659243Sobrien } 44759243Sobrien else 44859243Sobrien return (0); 44959243Sobrien 45059243Sobrien if (cmd) { 45159243Sobrien Char **av = *v, *p; 45259243Sobrien int fwd, i, ac = gargc; 45359243Sobrien 45459243Sobrien for (i = 0, fwd = 0; i < ac; i++) 45559243Sobrien if (!executable(NULL, av[i], 0)) { 45659243Sobrien fwd++; 45759243Sobrien p = av[i]; 45859243Sobrien av[i] = NULL; 45959243Sobrien xfree((ptr_t) p); 46059243Sobrien } 46159243Sobrien else if (fwd) 46259243Sobrien av[i - fwd] = av[i]; 46359243Sobrien 46459243Sobrien if (fwd) 46559243Sobrien av[i - fwd] = av[i]; 46659243Sobrien gargc -= fwd; 46759243Sobrien av[gargc] = NULL; 46859243Sobrien } 46959243Sobrien 47059243Sobrien return (gargc); 47159243Sobrien} /* end t_glob */ 47259243Sobrien 47359243Sobrien 47459243Sobrien/* c_glob(): 47559243Sobrien * Return a list of commands that match the pattern 47659243Sobrien */ 47759243Sobrienstatic int 47859243Sobrienc_glob(v) 47959243Sobrien register Char ***v; 48059243Sobrien{ 48159243Sobrien Char *pat = **v, *cmd, **av; 48259243Sobrien Char dir[MAXPATHLEN+1]; 48359243Sobrien int flag, at, ac; 48459243Sobrien 48559243Sobrien if (pat == NULL) 48659243Sobrien return (0); 48759243Sobrien 48859243Sobrien ac = 0; 48959243Sobrien at = 10; 49059243Sobrien av = (Char **) xmalloc((size_t) (at * sizeof(Char *))); 49159243Sobrien av[ac] = NULL; 49259243Sobrien 49359243Sobrien tw_cmd_start(NULL, NULL); 49459243Sobrien while ((cmd = tw_cmd_next(dir, &flag)) != NULL) 49559243Sobrien if (Gmatch(cmd, pat)) { 49659243Sobrien if (ac + 1 >= at) { 49759243Sobrien at += 10; 49859243Sobrien av = (Char **) xrealloc((ptr_t) av, 49959243Sobrien (size_t) (at * sizeof(Char *))); 50059243Sobrien } 50159243Sobrien av[ac++] = Strsave(cmd); 50259243Sobrien av[ac] = NULL; 50359243Sobrien } 50459243Sobrien tw_dir_end(); 50559243Sobrien *v = av; 50659243Sobrien 50759243Sobrien return (ac); 50859243Sobrien} /* end c_glob */ 50959243Sobrien 51059243Sobrien 51159243Sobrien/* insert_meta(): 51259243Sobrien * change the word before the cursor. 51359243Sobrien * cp must point to the start of the unquoted word. 51459243Sobrien * cpend to the end of it. 51559243Sobrien * word is the text that has to be substituted. 51659243Sobrien * strategy: 51759243Sobrien * try to keep all the quote characters of the user's input. 51859243Sobrien * change quote type only if necessary. 51959243Sobrien */ 52059243Sobrienstatic int 52159243Sobrieninsert_meta(cp, cpend, word, closequotes) 52259243Sobrien Char *cp; 52359243Sobrien Char *cpend; 52459243Sobrien Char *word; 52559243Sobrien bool closequotes; 52659243Sobrien{ 52759243Sobrien Char buffer[2 * FILSIZ + 1], *bptr, *wptr; 52859243Sobrien int in_sync = (cp != NULL); 52959243Sobrien int qu = 0; 53059243Sobrien int ndel = (int) (cp ? cpend - cp : 0); 53159243Sobrien Char w, wq; 53259415Sobrien#ifdef DSPMBYTE 53359415Sobrien int mbytepos = 1; 53459415Sobrien#endif /* DSPMBYTE */ 53559243Sobrien 53659243Sobrien for (bptr = buffer, wptr = word;;) { 53759243Sobrien if (bptr > buffer + 2 * FILSIZ - 5) 53859243Sobrien break; 53959243Sobrien 54059243Sobrien if (cp >= cpend) 54159243Sobrien in_sync = 0; 54259415Sobrien#ifdef DSPMBYTE 54359415Sobrien if (mbytepos == 1) 54459415Sobrien#endif /* DSPMBYTE */ 54559243Sobrien if (in_sync && !cmap(qu, _ESC) && cmap(*cp, _QF|_ESC)) 54659243Sobrien if (qu == 0 || qu == *cp) { 54759243Sobrien qu ^= *cp; 54859243Sobrien *bptr++ = *cp++; 54959243Sobrien continue; 55059243Sobrien } 55159243Sobrien w = *wptr; 55259243Sobrien if (w == 0) 55359243Sobrien break; 55459243Sobrien 55559243Sobrien wq = w & QUOTE; 55659243Sobrien w &= ~QUOTE; 55759243Sobrien 55859415Sobrien#ifdef DSPMBYTE 55959415Sobrien if (mbytepos == 2) 56059415Sobrien goto mbyteskip; 56159415Sobrien#endif /* DSPMBYTE */ 56259243Sobrien if (cmap(w, _ESC | _QF)) 56359243Sobrien wq = QUOTE; /* quotes are always quoted */ 56459243Sobrien 56559243Sobrien if (!wq && qu && tricky(w) && !(qu == '\"' && tricky_dq(w))) { 56659243Sobrien /* We have to unquote the character */ 56759243Sobrien in_sync = 0; 56859243Sobrien if (cmap(qu, _ESC)) 56959243Sobrien bptr[-1] = w; 57059243Sobrien else { 57159243Sobrien *bptr++ = (Char) qu; 57259243Sobrien *bptr++ = w; 57359243Sobrien if (wptr[1] == 0) 57459243Sobrien qu = 0; 57559243Sobrien else 57659243Sobrien *bptr++ = (Char) qu; 57759243Sobrien } 57859243Sobrien } else if (qu && w == qu) { 57959243Sobrien in_sync = 0; 58059243Sobrien if (bptr > buffer && bptr[-1] == qu) { 58159243Sobrien /* User misunderstanding :) */ 58259243Sobrien bptr[-1] = '\\'; 58359243Sobrien *bptr++ = w; 58459243Sobrien qu = 0; 58559243Sobrien } else { 58659243Sobrien *bptr++ = (Char) qu; 58759243Sobrien *bptr++ = '\\'; 58859243Sobrien *bptr++ = w; 58959243Sobrien *bptr++ = (Char) qu; 59059243Sobrien } 59159243Sobrien } 59259243Sobrien else if (wq && qu == '\"' && tricky_dq(w)) { 59359243Sobrien in_sync = 0; 59459243Sobrien *bptr++ = (Char) qu; 59559243Sobrien *bptr++ = '\\'; 59659243Sobrien *bptr++ = w; 59759243Sobrien *bptr++ = (Char) qu; 59859243Sobrien } else if (wq && ((!qu && (tricky(w) || (w == HISTSUB && bptr == buffer))) || (!cmap(qu, _ESC) && w == HIST))) { 59959243Sobrien in_sync = 0; 60059243Sobrien *bptr++ = '\\'; 60159243Sobrien *bptr++ = w; 60259243Sobrien } else { 60359415Sobrien#ifdef DSPMBYTE 60459415Sobrien mbyteskip: 60559415Sobrien#endif /* DSPMBYTE */ 60659243Sobrien if (in_sync && *cp++ != w) 60759243Sobrien in_sync = 0; 60859243Sobrien *bptr++ = w; 60959415Sobrien#ifdef DSPMBYTE 61059415Sobrien if (mbytepos == 1 && Ismbyte1(w)) 61159415Sobrien mbytepos = 2; 61259415Sobrien else 61359415Sobrien mbytepos = 1; 61459415Sobrien#endif /* DSPMBYTE */ 61559243Sobrien } 61659243Sobrien wptr++; 61759243Sobrien if (cmap(qu, _ESC)) 61859243Sobrien qu = 0; 61959243Sobrien } 62059243Sobrien if (closequotes && qu && !cmap(qu, _ESC)) 62159243Sobrien *bptr++ = (Char) qu; 62259243Sobrien *bptr = '\0'; 62359243Sobrien if (ndel) 62459243Sobrien DeleteBack(ndel); 62559243Sobrien return InsertStr(buffer); 62659243Sobrien} /* end insert_meta */ 62759243Sobrien 62859243Sobrien 62959243Sobrien 63059243Sobrien/* is_prefix(): 63159243Sobrien * return true if check matches initial chars in template 63259243Sobrien * This differs from PWB imatch in that if check is null 63359243Sobrien * it matches anything 63459243Sobrien */ 63559243Sobrienstatic int 63659243Sobrienis_prefix(check, template) 63759243Sobrien register Char *check, *template; 63859243Sobrien{ 63959243Sobrien for (; *check; check++, template++) 64059243Sobrien if ((*check & TRIM) != (*template & TRIM)) 64159243Sobrien return (FALSE); 64259243Sobrien return (TRUE); 64359243Sobrien} /* end is_prefix */ 64459243Sobrien 64559243Sobrien 64659243Sobrien/* is_prefixmatch(): 64759243Sobrien * return true if check matches initial chars in template 64859243Sobrien * This differs from PWB imatch in that if check is null 64959243Sobrien * it matches anything 65059243Sobrien * and matches on shortening of commands 65159243Sobrien */ 65259243Sobrienstatic int 65359243Sobrienis_prefixmatch(check, template, igncase) 65459243Sobrien Char *check, *template; 65559243Sobrien int igncase; 65659243Sobrien{ 65759243Sobrien Char MCH1, MCH2; 65859243Sobrien 65959243Sobrien for (; *check; check++, template++) { 66059243Sobrien if ((*check & TRIM) != (*template & TRIM)) { 66159243Sobrien MCH1 = (*check & TRIM); 66259243Sobrien MCH2 = (*template & TRIM); 66359243Sobrien MCH1 = Isupper(MCH1) ? Tolower(MCH1) : MCH1; 66459243Sobrien MCH2 = Isupper(MCH2) ? Tolower(MCH2) : MCH2; 66559243Sobrien if (MCH1 != MCH2) { 66659243Sobrien if (!igncase && ((*check & TRIM) == '-' || 66759243Sobrien (*check & TRIM) == '.' || 66859243Sobrien (*check & TRIM) == '_')) { 66959243Sobrien MCH1 = MCH2 = (*check & TRIM); 67059243Sobrien if (MCH1 == '_') { 67159243Sobrien MCH2 = '-'; 67259243Sobrien } else if (MCH1 == '-') { 67359243Sobrien MCH2 = '_'; 67459243Sobrien } 67559243Sobrien for (;*template && (*template & TRIM) != MCH1 && 67659243Sobrien (*template & TRIM) != MCH2; template++) 67759243Sobrien continue; 67859243Sobrien if (!*template) { 67959243Sobrien return (FALSE); 68059243Sobrien } 68159243Sobrien } else { 68259243Sobrien return (FALSE); 68359243Sobrien } 68459243Sobrien } 68559243Sobrien } 68659243Sobrien } 68759243Sobrien return (TRUE); 68859243Sobrien} /* end is_prefixmatch */ 68959243Sobrien 69059243Sobrien 69159243Sobrien/* is_suffix(): 69259243Sobrien * Return true if the chars in template appear at the 69359243Sobrien * end of check, I.e., are it's suffix. 69459243Sobrien */ 69559243Sobrienstatic int 69659243Sobrienis_suffix(check, template) 69759243Sobrien register Char *check, *template; 69859243Sobrien{ 69959243Sobrien register Char *t, *c; 70059243Sobrien 70159243Sobrien for (t = template; *t++;) 70259243Sobrien continue; 70359243Sobrien for (c = check; *c++;) 70459243Sobrien continue; 70559243Sobrien for (;;) { 70659243Sobrien if (t == template) 70759243Sobrien return 1; 70859243Sobrien if (c == check || (*--t & TRIM) != (*--c & TRIM)) 70959243Sobrien return 0; 71059243Sobrien } 71159243Sobrien} /* end is_suffix */ 71259243Sobrien 71359243Sobrien 71459243Sobrien/* ignored(): 71559243Sobrien * Return true if this is an ignored item 71659243Sobrien */ 71759243Sobrienstatic int 71859243Sobrienignored(item) 71959243Sobrien register Char *item; 72059243Sobrien{ 72159243Sobrien struct varent *vp; 72259243Sobrien register Char **cp; 72359243Sobrien 72459243Sobrien if ((vp = adrof(STRfignore)) == NULL || (cp = vp->vec) == NULL) 72559243Sobrien return (FALSE); 72659243Sobrien for (; *cp != NULL; cp++) 72759243Sobrien if (is_suffix(item, *cp)) 72859243Sobrien return (TRUE); 72959243Sobrien return (FALSE); 73059243Sobrien} /* end ignored */ 73159243Sobrien 73259243Sobrien 73359243Sobrien 73459243Sobrien/* starting_a_command(): 73559243Sobrien * return true if the command starting at wordstart is a command 73659243Sobrien */ 73759243Sobrienint 73859243Sobrienstarting_a_command(wordstart, inputline) 73959243Sobrien register Char *wordstart, *inputline; 74059243Sobrien{ 74159243Sobrien register Char *ptr, *ncmdstart; 74259243Sobrien int count; 74359243Sobrien static Char 74459243Sobrien cmdstart[] = {'`', ';', '&', '(', '|', '\0'}, 74559243Sobrien cmdalive[] = {' ', '\t', '\'', '"', '<', '>', '\0'}; 74659243Sobrien 74759243Sobrien /* 74859243Sobrien * Find if the number of backquotes is odd or even. 74959243Sobrien */ 75059243Sobrien for (ptr = wordstart, count = 0; 75159243Sobrien ptr >= inputline; 75259243Sobrien count += (*ptr-- == '`')) 75359243Sobrien continue; 75459243Sobrien /* 75559243Sobrien * if the number of backquotes is even don't include the backquote char in 75659243Sobrien * the list of command starting delimiters [if it is zero, then it does not 75759243Sobrien * matter] 75859243Sobrien */ 75959243Sobrien ncmdstart = cmdstart + EVEN(count); 76059243Sobrien 76159243Sobrien /* 76259243Sobrien * look for the characters previous to this word if we find a command 76359243Sobrien * starting delimiter we break. if we find whitespace and another previous 76459243Sobrien * word then we are not a command 76559243Sobrien * 76659243Sobrien * count is our state machine: 0 looking for anything 1 found white-space 76759243Sobrien * looking for non-ws 76859243Sobrien */ 76959243Sobrien for (count = 0; wordstart >= inputline; wordstart--) { 77059243Sobrien if (*wordstart == '\0') 77159243Sobrien continue; 77259243Sobrien if (Strchr(ncmdstart, *wordstart)) 77359243Sobrien break; 77459243Sobrien /* 77559243Sobrien * found white space 77659243Sobrien */ 77759243Sobrien if ((ptr = Strchr(cmdalive, *wordstart)) != NULL) 77859243Sobrien count = 1; 77959243Sobrien if (count == 1 && !ptr) 78059243Sobrien return (FALSE); 78159243Sobrien } 78259243Sobrien 78359243Sobrien if (wordstart > inputline) 78459243Sobrien switch (*wordstart) { 78559243Sobrien case '&': /* Look for >& */ 78659243Sobrien while (wordstart > inputline && 78759243Sobrien (*--wordstart == ' ' || *wordstart == '\t')) 78859243Sobrien continue; 78959243Sobrien if (*wordstart == '>') 79059243Sobrien return (FALSE); 79159243Sobrien break; 79259243Sobrien case '(': /* check for foreach, if etc. */ 79359243Sobrien while (wordstart > inputline && 79459243Sobrien (*--wordstart == ' ' || *wordstart == '\t')) 79559243Sobrien continue; 79659243Sobrien if (!iscmdmeta(*wordstart) && 79759243Sobrien (*wordstart != ' ' && *wordstart != '\t')) 79859243Sobrien return (FALSE); 79959243Sobrien break; 80059243Sobrien default: 80159243Sobrien break; 80259243Sobrien } 80359243Sobrien return (TRUE); 80459243Sobrien} /* end starting_a_command */ 80559243Sobrien 80659243Sobrien 80759243Sobrien/* recognize(): 80859243Sobrien * Object: extend what user typed up to an ambiguity. 80959243Sobrien * Algorithm: 81059243Sobrien * On first match, copy full item (assume it'll be the only match) 81159243Sobrien * On subsequent matches, shorten exp_name to the first 81259243Sobrien * character mismatch between exp_name and item. 81359243Sobrien * If we shorten it back to the prefix length, stop searching. 81459243Sobrien */ 81559243Sobrienstatic int 81659243Sobrienrecognize(exp_name, item, name_length, numitems, enhanced) 81759243Sobrien Char *exp_name, *item; 81859243Sobrien int name_length, numitems, enhanced; 81959243Sobrien{ 82059243Sobrien Char MCH1, MCH2; 82159243Sobrien register Char *x, *ent; 82259243Sobrien register int len = 0; 82369408Sache#ifdef WINNT_NATIVE 82459243Sobrien struct varent *vp; 82559243Sobrien int igncase; 826100616Smp igncase = (vp = adrof(STRcomplete)) != NULL && vp->vec != NULL && 82759243Sobrien Strcmp(*(vp->vec), STRigncase) == 0; 82869408Sache#endif /* WINNT_NATIVE */ 82959243Sobrien 83059243Sobrien if (numitems == 1) { /* 1st match */ 83159243Sobrien copyn(exp_name, item, MAXNAMLEN); 83259243Sobrien return (0); 83359243Sobrien } 83459243Sobrien if (!enhanced 83569408Sache#ifdef WINNT_NATIVE 83659243Sobrien && !igncase 83769408Sache#endif /* WINNT_NATIVE */ 83859243Sobrien ) { 83959243Sobrien for (x = exp_name, ent = item; *x && (*x & TRIM) == (*ent & TRIM); x++, ent++) 84059243Sobrien len++; 84159243Sobrien } else { 84259243Sobrien for (x = exp_name, ent = item; *x; x++, ent++) { 84359243Sobrien MCH1 = *x & TRIM; 84459243Sobrien MCH2 = *ent & TRIM; 84559243Sobrien MCH1 = Isupper(MCH1) ? Tolower(MCH1) : MCH1; 84659243Sobrien MCH2 = Isupper(MCH2) ? Tolower(MCH2) : MCH2; 84759243Sobrien if (MCH1 != MCH2) 84859243Sobrien break; 84959243Sobrien len++; 85059243Sobrien } 85159243Sobrien if (*x || !*ent) /* Shorter or exact match */ 85259243Sobrien copyn(exp_name, item, MAXNAMLEN); 85359243Sobrien } 85459243Sobrien *x = '\0'; /* Shorten at 1st char diff */ 85559243Sobrien if (!(match_unique_match || is_set(STRrecexact) || (enhanced && *ent)) && len == name_length) /* Ambiguous to prefix? */ 85659243Sobrien return (-1); /* So stop now and save time */ 85759243Sobrien return (0); 85859243Sobrien} /* end recognize */ 85959243Sobrien 86059243Sobrien 86159243Sobrien/* tw_collect_items(): 86259243Sobrien * Collect items that match target. 86359243Sobrien * SPELL command: 86459243Sobrien * Returns the spelling distance of the closest match. 86559243Sobrien * else 86659243Sobrien * Returns the number of items found. 86759243Sobrien * If none found, but some ignored items were found, 86859243Sobrien * It returns the -number of ignored items. 86959243Sobrien */ 87059243Sobrienstatic int 87159243Sobrientw_collect_items(command, looking, exp_dir, exp_name, target, pat, flags) 87259243Sobrien COMMAND command; 87359243Sobrien int looking; 87459243Sobrien Char *exp_dir, *exp_name, *target, *pat; 87559243Sobrien int flags; 87659243Sobrien 87759243Sobrien{ 87859243Sobrien int done = FALSE; /* Search is done */ 87959243Sobrien int showdots; /* Style to show dot files */ 88059243Sobrien int nignored = 0; /* Number of fignored items */ 88159243Sobrien int numitems = 0; /* Number of matched items */ 88259243Sobrien int name_length = (int) Strlen(target); /* Length of prefix (file name) */ 88359243Sobrien int exec_check = flags & TW_EXEC_CHK;/* need to check executability */ 88459243Sobrien int dir_check = flags & TW_DIR_CHK; /* Need to check for directories */ 88559243Sobrien int text_check = flags & TW_TEXT_CHK;/* Need to check for non-directories */ 88659243Sobrien int dir_ok = flags & TW_DIR_OK; /* Ignore directories? */ 88759243Sobrien int gpat = flags & TW_PAT_OK; /* Match against a pattern */ 88859243Sobrien int ignoring = flags & TW_IGN_OK; /* Use fignore? */ 88959243Sobrien int d = 4, nd; /* Spelling distance */ 89059243Sobrien Char *item, *ptr; 89159243Sobrien Char buf[MAXPATHLEN+1]; 89259243Sobrien struct varent *vp; 89359243Sobrien int len, enhanced; 89459243Sobrien int cnt = 0; 89559243Sobrien int igncase = 0; 89659243Sobrien 89759243Sobrien 89859243Sobrien flags = 0; 89959243Sobrien 90059243Sobrien showdots = DOT_NONE; 90159243Sobrien if ((ptr = varval(STRlistflags)) != STRNULL) 90259243Sobrien while (*ptr) 90359243Sobrien switch (*ptr++) { 90459243Sobrien case 'a': 90559243Sobrien showdots = DOT_ALL; 90659243Sobrien break; 90759243Sobrien case 'A': 90859243Sobrien showdots = DOT_NOT; 90959243Sobrien break; 91059243Sobrien default: 91159243Sobrien break; 91259243Sobrien } 91359243Sobrien 91459243Sobrien while (!done && (item = (*tw_next_entry[looking])(exp_dir, &flags))) { 91559243Sobrien#ifdef TDEBUG 91659243Sobrien xprintf("item = %S\n", item); 91759243Sobrien#endif 91859243Sobrien switch (looking) { 91959243Sobrien case TW_FILE: 92059243Sobrien case TW_DIRECTORY: 92159243Sobrien case TW_TEXT: 92259243Sobrien /* 92359243Sobrien * Don't match . files on null prefix match 92459243Sobrien */ 92559243Sobrien if (showdots == DOT_NOT && (ISDOT(item) || ISDOTDOT(item))) 92659243Sobrien done = TRUE; 92759243Sobrien if (name_length == 0 && item[0] == '.' && showdots == DOT_NONE) 92859243Sobrien done = TRUE; 92959243Sobrien break; 93059243Sobrien 93159243Sobrien case TW_COMMAND: 93259243Sobrien exec_check = flags & TW_EXEC_CHK; 93359243Sobrien dir_ok = flags & TW_DIR_OK; 93459243Sobrien break; 93559243Sobrien 93659243Sobrien default: 93759243Sobrien break; 93859243Sobrien } 93959243Sobrien 94059243Sobrien if (done) { 94159243Sobrien done = FALSE; 94259243Sobrien continue; 94359243Sobrien } 94459243Sobrien 94559243Sobrien switch (command) { 94659243Sobrien 94759243Sobrien case SPELL: /* correct the spelling of the last bit */ 94859243Sobrien if (name_length == 0) {/* zero-length word can't be misspelled */ 94959243Sobrien exp_name[0] = '\0';/* (not trying is important for ~) */ 95059243Sobrien d = 0; 95159243Sobrien done = TRUE; 95259243Sobrien break; 95359243Sobrien } 95459243Sobrien if (gpat && !Gmatch(item, pat)) 95559243Sobrien break; 95659243Sobrien /* 95759243Sobrien * Swapped the order of the spdist() arguments as suggested 95859243Sobrien * by eeide@asylum.cs.utah.edu (Eric Eide) 95959243Sobrien */ 96059243Sobrien nd = spdist(target, item); /* test the item against original */ 96159243Sobrien if (nd <= d && nd != 4) { 96259243Sobrien if (!(exec_check && !executable(exp_dir, item, dir_ok))) { 96359243Sobrien (void) Strcpy(exp_name, item); 96459243Sobrien d = nd; 96559243Sobrien if (d == 0) /* if found it exactly */ 96659243Sobrien done = TRUE; 96759243Sobrien } 96859243Sobrien } 96959243Sobrien else if (nd == 4) { 97059243Sobrien if (spdir(exp_name, exp_dir, item, target)) { 97159243Sobrien if (exec_check && !executable(exp_dir, exp_name, dir_ok)) 97259243Sobrien break; 97359243Sobrien#ifdef notdef 97459243Sobrien /* 97559243Sobrien * We don't want to stop immediately, because 97659243Sobrien * we might find an exact/better match later. 97759243Sobrien */ 97859243Sobrien d = 0; 97959243Sobrien done = TRUE; 98059243Sobrien#endif 98159243Sobrien d = 3; 98259243Sobrien } 98359243Sobrien } 98459243Sobrien break; 98559243Sobrien 98659243Sobrien case LIST: 98759243Sobrien case RECOGNIZE: 98859243Sobrien case RECOGNIZE_ALL: 98959243Sobrien case RECOGNIZE_SCROLL: 99059243Sobrien 99169408Sache#ifdef WINNT_NATIVE 992100616Smp igncase = (vp = adrof(STRcomplete)) != NULL && vp->vec != NULL && 99359243Sobrien Strcmp(*(vp->vec), STRigncase) == 0; 99469408Sache#endif /* WINNT_NATIVE */ 99559243Sobrien enhanced = (vp = adrof(STRcomplete)) != NULL && !Strcmp(*(vp->vec),STRenhance); 99659243Sobrien if (enhanced || igncase) { 99759243Sobrien if (!is_prefixmatch(target, item, igncase)) 99859243Sobrien break; 99959243Sobrien } else { 100059243Sobrien if (!is_prefix(target, item)) 100159243Sobrien break; 100259243Sobrien } 100359243Sobrien 100459243Sobrien if (exec_check && !executable(exp_dir, item, dir_ok)) 100559243Sobrien break; 100659243Sobrien 100759243Sobrien if (dir_check && !isadirectory(exp_dir, item)) 100859243Sobrien break; 100959243Sobrien 101059243Sobrien if (text_check && isadirectory(exp_dir, item)) 101159243Sobrien break; 101259243Sobrien 101359243Sobrien /* 101459243Sobrien * Only pattern match directories if we're checking 101559243Sobrien * for directories. 101659243Sobrien */ 101759243Sobrien if (gpat && !Gmatch(item, pat) && 101859243Sobrien (dir_check || !isadirectory(exp_dir, item))) 101959243Sobrien break; 102059243Sobrien 102159243Sobrien /* 102259243Sobrien * Remove duplicates in command listing and completion 102359243Sobrien * AFEB added code for TW_LOGNAME and TW_USER cases 102459243Sobrien */ 102559243Sobrien if (looking == TW_COMMAND || looking == TW_LOGNAME 102659243Sobrien || looking == TW_USER || command == LIST) { 102759243Sobrien copyn(buf, item, MAXPATHLEN); 102859243Sobrien len = (int) Strlen(buf); 102959243Sobrien switch (looking) { 103059243Sobrien case TW_COMMAND: 103159243Sobrien if (!(dir_ok && exec_check)) 103259243Sobrien break; 103359243Sobrien if (filetype(exp_dir, item) == '/') { 103459243Sobrien buf[len++] = '/'; 103559243Sobrien buf[len] = '\0'; 103659243Sobrien } 103759243Sobrien break; 103859243Sobrien 103959243Sobrien case TW_FILE: 104059243Sobrien case TW_DIRECTORY: 104159243Sobrien buf[len++] = filetype(exp_dir, item); 104259243Sobrien buf[len] = '\0'; 104359243Sobrien break; 104459243Sobrien 104559243Sobrien default: 104659243Sobrien break; 104759243Sobrien } 104859243Sobrien if ((looking == TW_COMMAND || looking == TW_USER 104959243Sobrien || looking == TW_LOGNAME) && tw_item_find(buf)) 105059243Sobrien break; 105159243Sobrien else { 105259243Sobrien /* maximum length 1 (NULL) + 1 (~ or $) + 1 (filetype) */ 105359243Sobrien ptr = tw_item_add(len + 3); 105459243Sobrien copyn(ptr, buf, MAXPATHLEN); 105559243Sobrien if (command == LIST) 105659243Sobrien numitems++; 105759243Sobrien } 105859243Sobrien } 105959243Sobrien 106059243Sobrien if (command == RECOGNIZE || command == RECOGNIZE_ALL || 106159243Sobrien command == RECOGNIZE_SCROLL) { 106259243Sobrien if (ignoring && ignored(item)) { 106359243Sobrien nignored++; 106459243Sobrien break; 106559243Sobrien } 106659243Sobrien else if (command == RECOGNIZE_SCROLL) { 106759243Sobrien add_scroll_tab(item); 106859243Sobrien cnt++; 106959243Sobrien } 107059243Sobrien 107159243Sobrien if (match_unique_match || is_set(STRrecexact)) { 107259243Sobrien if (StrQcmp(target, item) == 0) { /* EXACT match */ 107359243Sobrien copyn(exp_name, item, MAXNAMLEN); 107459243Sobrien numitems = 1; /* fake into expanding */ 107559243Sobrien non_unique_match = TRUE; 107659243Sobrien done = TRUE; 107759243Sobrien break; 107859243Sobrien } 107959243Sobrien } 108059243Sobrien if (recognize(exp_name, item, name_length, ++numitems, enhanced)) 108159243Sobrien if (command != RECOGNIZE_SCROLL) 108259243Sobrien done = TRUE; 108359243Sobrien if (enhanced && (int)Strlen(exp_name) < name_length) 108459243Sobrien copyn(exp_name, target, MAXNAMLEN); 108559243Sobrien } 108659243Sobrien break; 108759243Sobrien 108859243Sobrien default: 108959243Sobrien break; 109059243Sobrien } 109159243Sobrien#ifdef TDEBUG 109259243Sobrien xprintf("done item = %S\n", item); 109359243Sobrien#endif 109459243Sobrien } 109559243Sobrien 109659243Sobrien 109759243Sobrien if (command == RECOGNIZE_SCROLL) { 109859243Sobrien if ((cnt <= curchoice) || (curchoice == -1)) { 109959243Sobrien curchoice = -1; 110059243Sobrien nignored = 0; 110159243Sobrien numitems = 0; 110259243Sobrien } else if (numitems > 1) { 110359243Sobrien if (curchoice < -1) 110459243Sobrien curchoice = cnt - 1; 110559243Sobrien choose_scroll_tab(&exp_name, cnt); 110659243Sobrien numitems = 1; 110759243Sobrien } 110859243Sobrien } 110959243Sobrien free_scroll_tab(); 111059243Sobrien 111159243Sobrien if (command == SPELL) 111259243Sobrien return d; 111359243Sobrien else { 111459243Sobrien if (ignoring && numitems == 0 && nignored > 0) 111559243Sobrien return -nignored; 111659243Sobrien else 111759243Sobrien return numitems; 111859243Sobrien } 111959243Sobrien} 112059243Sobrien 112159243Sobrien 112259243Sobrien/* tw_suffix(): 112359243Sobrien * Find and return the appropriate suffix character 112459243Sobrien */ 112559243Sobrien/*ARGSUSED*/ 112659243Sobrienstatic Char 112759243Sobrientw_suffix(looking, exp_dir, exp_name, target, name) 112859243Sobrien int looking; 112959243Sobrien Char *exp_dir, *exp_name, *target, *name; 113059243Sobrien{ 113159243Sobrien Char *ptr; 113259243Sobrien struct varent *vp; 113359243Sobrien 113459243Sobrien USE(name); 113559243Sobrien (void) strip(exp_name); 113659243Sobrien 113759243Sobrien switch (looking) { 113859243Sobrien 113959243Sobrien case TW_LOGNAME: 114059243Sobrien return '/'; 114159243Sobrien 114259243Sobrien case TW_VARIABLE: 114359243Sobrien /* 114459243Sobrien * Don't consider array variables or empty variables 114559243Sobrien */ 1146100616Smp if ((vp = adrof(exp_name)) != NULL && vp->vec != NULL) { 114759243Sobrien if ((ptr = vp->vec[0]) == NULL || *ptr == '\0' || 114859243Sobrien vp->vec[1] != NULL) 114959243Sobrien return ' '; 115059243Sobrien } 115159243Sobrien else if ((ptr = tgetenv(exp_name)) == NULL || *ptr == '\0') 115259243Sobrien return ' '; 115359243Sobrien 115459243Sobrien *--target = '\0'; 115559243Sobrien 115659243Sobrien return isadirectory(exp_dir, ptr) ? '/' : ' '; 115759243Sobrien 115859243Sobrien 115959243Sobrien case TW_DIRECTORY: 116059243Sobrien return '/'; 116159243Sobrien 116259243Sobrien case TW_COMMAND: 116359243Sobrien case TW_FILE: 116459243Sobrien return isadirectory(exp_dir, exp_name) ? '/' : ' '; 116559243Sobrien 116659243Sobrien case TW_ALIAS: 116759243Sobrien case TW_VARLIST: 116859243Sobrien case TW_WORDLIST: 116959243Sobrien case TW_SHELLVAR: 117059243Sobrien case TW_ENVVAR: 117159243Sobrien case TW_USER: 117259243Sobrien case TW_BINDING: 117359243Sobrien case TW_LIMIT: 117459243Sobrien case TW_SIGNAL: 117559243Sobrien case TW_JOB: 117659243Sobrien case TW_COMPLETION: 117759243Sobrien case TW_TEXT: 117859243Sobrien case TW_GRPNAME: 117959243Sobrien return ' '; 118059243Sobrien 118159243Sobrien default: 118259243Sobrien return '\0'; 118359243Sobrien } 118459243Sobrien} /* end tw_suffix */ 118559243Sobrien 118659243Sobrien 118759243Sobrien/* tw_fixword(): 118859243Sobrien * Repair a word after a spalling or a recognizwe 118959243Sobrien */ 119059243Sobrienstatic void 119159243Sobrientw_fixword(looking, word, dir, exp_name, max_word_length) 119259243Sobrien int looking; 119359243Sobrien Char *word, *dir, *exp_name; 119459243Sobrien int max_word_length; 119559243Sobrien{ 119659243Sobrien Char *ptr; 119759243Sobrien 119859243Sobrien switch (looking) { 119959243Sobrien case TW_LOGNAME: 120059243Sobrien copyn(word, STRtilde, 1); 120159243Sobrien break; 120259243Sobrien 120359243Sobrien case TW_VARIABLE: 120459243Sobrien if ((ptr = Strrchr(word, '$')) != NULL) 120559243Sobrien *++ptr = '\0'; /* Delete after the dollar */ 120659243Sobrien else 120759243Sobrien word[0] = '\0'; 120859243Sobrien break; 120959243Sobrien 121059243Sobrien case TW_DIRECTORY: 121159243Sobrien case TW_FILE: 121259243Sobrien case TW_TEXT: 121359243Sobrien copyn(word, dir, max_word_length); /* put back dir part */ 121459243Sobrien break; 121559243Sobrien 121659243Sobrien default: 121759243Sobrien word[0] = '\0'; 121859243Sobrien break; 121959243Sobrien } 122059243Sobrien 122159243Sobrien (void) quote(exp_name); 122259243Sobrien catn(word, exp_name, max_word_length); /* add extended name */ 122359243Sobrien} /* end tw_fixword */ 122459243Sobrien 122559243Sobrien 122659243Sobrien/* tw_collect(): 122759243Sobrien * Collect items. Return -1 in case we were interrupted or 122859243Sobrien * the return value of tw_collect 122959243Sobrien * This is really a wrapper for tw_collect_items, serving two 123059243Sobrien * purposes: 123159243Sobrien * 1. Handles interrupt cleanups. 123259243Sobrien * 2. Retries if we had no matches, but there were ignored matches 123359243Sobrien */ 123459243Sobrienstatic int 123559243Sobrientw_collect(command, looking, exp_dir, exp_name, target, pat, flags, dir_fd) 123659243Sobrien COMMAND command; 123759243Sobrien int looking; 123859243Sobrien Char *exp_dir, *exp_name, **target, *pat; 123959243Sobrien int flags; 124059243Sobrien DIR *dir_fd; 124159243Sobrien{ 124259243Sobrien static int ni; /* static so we don't get clobbered */ 124359243Sobrien jmp_buf_t osetexit; 124459243Sobrien 124559243Sobrien#ifdef TDEBUG 124659243Sobrien xprintf("target = %S\n", *target); 124759243Sobrien#endif 124859243Sobrien ni = 0; 124959243Sobrien getexit(osetexit); 125059243Sobrien for (;;) { 125159243Sobrien (*tw_start_entry[looking])(dir_fd, pat); 125259243Sobrien InsideCompletion = 1; 125359243Sobrien if (setexit()) { 125459243Sobrien /* interrupted, clean up */ 125559243Sobrien resexit(osetexit); 125659243Sobrien InsideCompletion = 0; 125759243Sobrien haderr = 0; 125859243Sobrien 125959243Sobrien#if defined(SOLARIS2) && defined(i386) && !defined(__GNUC__) 126059243Sobrien /* Compiler bug? (from PWP) */ 126159243Sobrien if ((looking == TW_LOGNAME) || (looking == TW_USER)) 126259243Sobrien tw_logname_end(); 126359243Sobrien else 126459243Sobrien if (looking == TW_GRPNAME) 126559243Sobrien tw_grpname_end(); 126659243Sobrien else 126759243Sobrien tw_dir_end(); 126859243Sobrien#else /* !(SOLARIS2 && i386 && !__GNUC__) */ 126959243Sobrien (*tw_end_entry[looking])(); 127059243Sobrien#endif /* !(SOLARIS2 && i386 && !__GNUC__) */ 127159243Sobrien 127259243Sobrien /* flag error */ 127359243Sobrien return(-1); 127459243Sobrien } 127559243Sobrien if ((ni = tw_collect_items(command, looking, exp_dir, exp_name, 127659243Sobrien *target, pat, 127759243Sobrien ni >= 0 ? flags : 127859243Sobrien flags & ~TW_IGN_OK)) >= 0) { 127959243Sobrien resexit(osetexit); 128059243Sobrien InsideCompletion = 0; 128159243Sobrien 128259243Sobrien#if defined(SOLARIS2) && defined(i386) && !defined(__GNUC__) 128359243Sobrien /* Compiler bug? (from PWP) */ 128459243Sobrien if ((looking == TW_LOGNAME) || (looking == TW_USER)) 128559243Sobrien tw_logname_end(); 128659243Sobrien else 128759243Sobrien if (looking == TW_GRPNAME) 128859243Sobrien tw_grpname_end(); 128959243Sobrien else 129059243Sobrien tw_dir_end(); 129159243Sobrien#else /* !(SOLARIS2 && i386 && !__GNUC__) */ 129259243Sobrien (*tw_end_entry[looking])(); 129359243Sobrien#endif /* !(SOLARIS2 && i386 && !__GNUC__) */ 129459243Sobrien 129559243Sobrien return(ni); 129659243Sobrien } 129759243Sobrien } 129859243Sobrien} /* end tw_collect */ 129959243Sobrien 130059243Sobrien 130159243Sobrien/* tw_list_items(): 130259243Sobrien * List the items that were found 130359243Sobrien * 130459243Sobrien * NOTE instead of looking at numerical vars listmax and listmaxrows 130559243Sobrien * we can look at numerical var listmax, and have a string value 130659243Sobrien * listmaxtype (or similar) than can have values 'items' and 'rows' 130759243Sobrien * (by default interpreted as 'items', for backwards compatibility) 130859243Sobrien */ 130959243Sobrienstatic void 131059243Sobrientw_list_items(looking, numitems, list_max) 131159243Sobrien int looking, numitems, list_max; 131259243Sobrien{ 131359243Sobrien Char *ptr; 131459243Sobrien int max_items = 0; 131559243Sobrien int max_rows = 0; 131659243Sobrien 131783098Smp if (numitems == 0) 131883098Smp return; 131983098Smp 132059243Sobrien if ((ptr = varval(STRlistmax)) != STRNULL) { 132159243Sobrien while (*ptr) { 132259243Sobrien if (!Isdigit(*ptr)) { 132359243Sobrien max_items = 0; 132459243Sobrien break; 132559243Sobrien } 132659243Sobrien max_items = max_items * 10 + *ptr++ - '0'; 132759243Sobrien } 132859243Sobrien if ((max_items > 0) && (numitems > max_items) && list_max) 132959243Sobrien max_items = numitems; 133059243Sobrien else 133159243Sobrien max_items = 0; 133259243Sobrien } 133359243Sobrien 133459243Sobrien if (max_items == 0 && (ptr = varval(STRlistmaxrows)) != STRNULL) { 133559243Sobrien int rows; 133659243Sobrien 133759243Sobrien while (*ptr) { 133859243Sobrien if (!Isdigit(*ptr)) { 133959243Sobrien max_rows = 0; 134059243Sobrien break; 134159243Sobrien } 134259243Sobrien max_rows = max_rows * 10 + *ptr++ - '0'; 134359243Sobrien } 134459243Sobrien if (max_rows != 0 && looking != TW_JOB) 134559243Sobrien rows = find_rows(tw_item_get(), numitems, TRUE); 134659243Sobrien else 134759243Sobrien rows = numitems; /* underestimate for lines wider than the termH */ 134859243Sobrien if ((max_rows > 0) && (rows > max_rows) && list_max) 134959243Sobrien max_rows = rows; 135059243Sobrien else 135159243Sobrien max_rows = 0; 135259243Sobrien } 135359243Sobrien 135459243Sobrien 135559243Sobrien if (max_items || max_rows) { 135659243Sobrien char tc; 135759243Sobrien const char *name; 135859243Sobrien int maxs; 135959243Sobrien 136059243Sobrien if (max_items) { 136159243Sobrien name = CGETS(30, 5, "items"); 136259243Sobrien maxs = max_items; 136359243Sobrien } 136459243Sobrien else { 136559243Sobrien name = CGETS(30, 6, "rows"); 136659243Sobrien maxs = max_rows; 136759243Sobrien } 136859243Sobrien 136959243Sobrien xprintf(CGETS(30, 7, "There are %d %s, list them anyway? [n/y] "), 137059243Sobrien maxs, name); 137159243Sobrien flush(); 137259243Sobrien /* We should be in Rawmode here, so no \n to catch */ 137359243Sobrien (void) read(SHIN, &tc, 1); 137459243Sobrien xprintf("%c\r\n", tc); /* echo the char, do a newline */ 137559243Sobrien /* 137659243Sobrien * Perhaps we should use the yesexpr from the 137759243Sobrien * actual locale 137859243Sobrien */ 137959243Sobrien if (strchr(CGETS(30, 13, "Yy"), tc) == NULL) 138059243Sobrien return; 138159243Sobrien } 138259243Sobrien 138359243Sobrien if (looking != TW_SIGNAL) 138459243Sobrien qsort((ptr_t) tw_item_get(), (size_t) numitems, sizeof(Char *), 138559243Sobrien (int (*) __P((const void *, const void *))) fcompare); 138659243Sobrien if (looking != TW_JOB) 138759243Sobrien print_by_column(STRNULL, tw_item_get(), numitems, TRUE); 138859243Sobrien else { 138959243Sobrien /* 139059243Sobrien * print one item on every line because jobs can have spaces 139159243Sobrien * and it is confusing. 139259243Sobrien */ 139359243Sobrien int i; 139459243Sobrien Char **w = tw_item_get(); 139559243Sobrien 139659243Sobrien for (i = 0; i < numitems; i++) { 139759243Sobrien xprintf("%S", w[i]); 139859243Sobrien if (Tty_raw_mode) 139959243Sobrien xputchar('\r'); 140059243Sobrien xputchar('\n'); 140159243Sobrien } 140259243Sobrien } 140359243Sobrien} /* end tw_list_items */ 140459243Sobrien 140559243Sobrien 140659243Sobrien/* t_search(): 140759243Sobrien * Perform a RECOGNIZE, LIST or SPELL command on string "word". 140859243Sobrien * 140959243Sobrien * Return value: 141059243Sobrien * >= 0: SPELL command: "distance" (see spdist()) 141159243Sobrien * other: No. of items found 141259243Sobrien * < 0: Error (message or beep is output) 141359243Sobrien */ 141459243Sobrien/*ARGSUSED*/ 141559243Sobrienint 141659243Sobrient_search(word, wp, command, max_word_length, looking, list_max, pat, suf) 141759243Sobrien Char *word, *wp; /* original end-of-word */ 141859243Sobrien COMMAND command; 141959243Sobrien int max_word_length, looking, list_max; 142059243Sobrien Char *pat; 142159243Sobrien int suf; 142259243Sobrien{ 142359243Sobrien int numitems, /* Number of items matched */ 142459243Sobrien flags = 0, /* search flags */ 142559243Sobrien gpat = pat[0] != '\0', /* Glob pattern search */ 142659243Sobrien nd; /* Normalized directory return */ 142759243Sobrien Char exp_dir[FILSIZ + 1], /* dir after ~ expansion */ 142859243Sobrien dir[FILSIZ + 1], /* /x/y/z/ part in /x/y/z/f */ 142959243Sobrien exp_name[MAXNAMLEN + 1], /* the recognized (extended) */ 143059243Sobrien name[MAXNAMLEN + 1], /* f part in /d/d/d/f name */ 143159243Sobrien *target; /* Target to expand/correct/list */ 143259243Sobrien DIR *dir_fd = NULL; 143359243Sobrien 143459243Sobrien USE(wp); 143559243Sobrien 143659243Sobrien /* 143759243Sobrien * bugfix by Marty Grossman (grossman@CC5.BBN.COM): directory listing can 143859243Sobrien * dump core when interrupted 143959243Sobrien */ 144059243Sobrien tw_item_free(); 144159243Sobrien 144259243Sobrien non_unique_match = FALSE; /* See the recexact code below */ 144359243Sobrien 144459243Sobrien extract_dir_and_name(word, dir, name); 144559243Sobrien 144659243Sobrien /* 144759243Sobrien * SPECIAL HARDCODED COMPLETIONS: 144859243Sobrien * foo$variable -> TW_VARIABLE 144959243Sobrien * ~user -> TW_LOGNAME 145059243Sobrien * 145159243Sobrien */ 145259243Sobrien if ((*word == '~') && (Strchr(word, '/') == NULL)) { 145359243Sobrien looking = TW_LOGNAME; 145459243Sobrien target = name; 145559243Sobrien gpat = 0; /* Override pattern mechanism */ 145659243Sobrien } 145759243Sobrien else if ((target = Strrchr(name, '$')) != 0 && 145859243Sobrien (Strchr(name, '/') == NULL)) { 145959243Sobrien target++; 146059243Sobrien looking = TW_VARIABLE; 146159243Sobrien gpat = 0; /* Override pattern mechanism */ 146259243Sobrien } 146359243Sobrien else 146459243Sobrien target = name; 146559243Sobrien 146659243Sobrien /* 146759243Sobrien * Try to figure out what we should be looking for 146859243Sobrien */ 146959243Sobrien if (looking & TW_PATH) { 147059243Sobrien gpat = 0; /* pattern holds the pathname to be used */ 147159243Sobrien copyn(exp_dir, pat, MAXNAMLEN); 147259243Sobrien if (exp_dir[Strlen(exp_dir) - 1] != '/') 147359243Sobrien catn(exp_dir, STRslash, MAXNAMLEN); 147459243Sobrien catn(exp_dir, dir, MAXNAMLEN); 147559243Sobrien } 147659243Sobrien else 147759243Sobrien exp_dir[0] = '\0'; 147859243Sobrien 147959243Sobrien switch (looking & ~TW_PATH) { 148059243Sobrien case TW_NONE: 148159243Sobrien return -1; 148259243Sobrien 148359243Sobrien case TW_ZERO: 148459243Sobrien looking = TW_FILE; 148559243Sobrien break; 148659243Sobrien 148759243Sobrien case TW_COMMAND: 148859243Sobrien if (Strchr(word, '/') || (looking & TW_PATH)) { 148959243Sobrien looking = TW_FILE; 149059243Sobrien flags |= TW_EXEC_CHK; 149159243Sobrien flags |= TW_DIR_OK; 149259243Sobrien } 149359243Sobrien#ifdef notdef 149459243Sobrien /* PWP: don't even bother when doing ALL of the commands */ 149559243Sobrien if (looking == TW_COMMAND && (*word == '\0')) 149659243Sobrien return (-1); 149759243Sobrien#endif 149859243Sobrien break; 149959243Sobrien 150059243Sobrien 150159243Sobrien case TW_VARLIST: 150259243Sobrien case TW_WORDLIST: 150359243Sobrien gpat = 0; /* pattern holds the name of the variable */ 150459243Sobrien break; 150559243Sobrien 150659243Sobrien case TW_EXPLAIN: 150759243Sobrien if (command == LIST && pat != NULL) { 150859243Sobrien xprintf("%S", pat); 150959243Sobrien if (Tty_raw_mode) 151059243Sobrien xputchar('\r'); 151159243Sobrien xputchar('\n'); 151259243Sobrien } 151359243Sobrien return 2; 151459243Sobrien 151559243Sobrien default: 151659243Sobrien break; 151759243Sobrien } 151859243Sobrien 151959243Sobrien /* 152059243Sobrien * let fignore work only when we are not using a pattern 152159243Sobrien */ 152259243Sobrien flags |= (gpat == 0) ? TW_IGN_OK : TW_PAT_OK; 152359243Sobrien 152459243Sobrien#ifdef TDEBUG 152559243Sobrien xprintf(CGETS(30, 8, "looking = %d\n"), looking); 152659243Sobrien#endif 152759243Sobrien 152859243Sobrien switch (looking) { 152959243Sobrien case TW_ALIAS: 153059243Sobrien case TW_SHELLVAR: 153159243Sobrien case TW_ENVVAR: 153259243Sobrien case TW_BINDING: 153359243Sobrien case TW_LIMIT: 153459243Sobrien case TW_SIGNAL: 153559243Sobrien case TW_JOB: 153659243Sobrien case TW_COMPLETION: 153759243Sobrien case TW_GRPNAME: 153859243Sobrien break; 153959243Sobrien 154059243Sobrien 154159243Sobrien case TW_VARIABLE: 154259243Sobrien if ((nd = expand_dir(dir, exp_dir, &dir_fd, command)) != 0) 154359243Sobrien return nd; 154459243Sobrien break; 154559243Sobrien 154659243Sobrien case TW_DIRECTORY: 154759243Sobrien flags |= TW_DIR_CHK; 154859243Sobrien 154959243Sobrien#ifdef notyet 155059243Sobrien /* 155159243Sobrien * This is supposed to expand the directory stack. 155259243Sobrien * Problems: 155359243Sobrien * 1. Slow 155459243Sobrien * 2. directories with the same name 155559243Sobrien */ 155659243Sobrien flags |= TW_DIR_OK; 155759243Sobrien#endif 155859243Sobrien#ifdef notyet 155959243Sobrien /* 156059243Sobrien * Supposed to do delayed expansion, but it is inconsistent 156159243Sobrien * from a user-interface point of view, since it does not 156259243Sobrien * immediately obey addsuffix 156359243Sobrien */ 156459243Sobrien if ((nd = expand_dir(dir, exp_dir, &dir_fd, command)) != 0) 156559243Sobrien return nd; 156659243Sobrien if (isadirectory(exp_dir, name)) { 156759243Sobrien if (exp_dir[0] != '\0' || name[0] != '\0') { 156859243Sobrien catn(dir, name, MAXNAMLEN); 156959243Sobrien if (dir[Strlen(dir) - 1] != '/') 157059243Sobrien catn(dir, STRslash, MAXNAMLEN); 157159243Sobrien if ((nd = expand_dir(dir, exp_dir, &dir_fd, command)) != 0) 157259243Sobrien return nd; 157359243Sobrien if (word[Strlen(word) - 1] != '/') 157459243Sobrien catn(word, STRslash, MAXNAMLEN); 157559243Sobrien name[0] = '\0'; 157659243Sobrien } 157759243Sobrien } 157859243Sobrien#endif 157959243Sobrien if ((nd = expand_dir(dir, exp_dir, &dir_fd, command)) != 0) 158059243Sobrien return nd; 158159243Sobrien break; 158259243Sobrien 158359243Sobrien case TW_TEXT: 158459243Sobrien flags |= TW_TEXT_CHK; 158559243Sobrien /*FALLTHROUGH*/ 158659243Sobrien case TW_FILE: 158759243Sobrien if ((nd = expand_dir(dir, exp_dir, &dir_fd, command)) != 0) 158859243Sobrien return nd; 158959243Sobrien break; 159059243Sobrien 159159243Sobrien case TW_PATH | TW_TEXT: 159259243Sobrien case TW_PATH | TW_FILE: 159359243Sobrien case TW_PATH | TW_DIRECTORY: 159459243Sobrien case TW_PATH | TW_COMMAND: 159559243Sobrien if ((dir_fd = opendir(short2str(exp_dir))) == NULL) { 159683098Smp if (command == RECOGNIZE) 159783098Smp xprintf("\n"); 159883098Smp xprintf("%S: %s", exp_dir, strerror(errno)); 159983098Smp if (command != RECOGNIZE) 160083098Smp xprintf("\n"); 160183098Smp NeedsRedraw = 1; 160259243Sobrien return -1; 160359243Sobrien } 160459243Sobrien if (exp_dir[Strlen(exp_dir) - 1] != '/') 160559243Sobrien catn(exp_dir, STRslash, MAXNAMLEN); 160659243Sobrien 160759243Sobrien looking &= ~TW_PATH; 160859243Sobrien 160959243Sobrien switch (looking) { 161059243Sobrien case TW_TEXT: 161159243Sobrien flags |= TW_TEXT_CHK; 161259243Sobrien break; 161359243Sobrien 161459243Sobrien case TW_FILE: 161559243Sobrien break; 161659243Sobrien 161759243Sobrien case TW_DIRECTORY: 161859243Sobrien flags |= TW_DIR_CHK; 161959243Sobrien break; 162059243Sobrien 162159243Sobrien case TW_COMMAND: 162259243Sobrien copyn(target, word, MAXNAMLEN); /* so it can match things */ 162359243Sobrien break; 162459243Sobrien 162559243Sobrien default: 162659243Sobrien abort(); /* Cannot happen */ 162759243Sobrien break; 162859243Sobrien } 162959243Sobrien break; 163059243Sobrien 163159243Sobrien case TW_LOGNAME: 163259243Sobrien word++; 163359243Sobrien /*FALLTHROUGH*/ 163459243Sobrien case TW_USER: 163559243Sobrien /* 163659243Sobrien * Check if the spelling was already correct 163759243Sobrien * From: Rob McMahon <cudcv@cu.warwick.ac.uk> 163859243Sobrien */ 163959243Sobrien if (command == SPELL && getpwnam(short2str(word)) != NULL) { 164059243Sobrien#ifdef YPBUGS 164159243Sobrien fix_yp_bugs(); 164259243Sobrien#endif /* YPBUGS */ 164359243Sobrien return (0); 164459243Sobrien } 164559243Sobrien copyn(name, word, MAXNAMLEN); /* name sans ~ */ 164659243Sobrien if (looking == TW_LOGNAME) 164759243Sobrien word--; 164859243Sobrien break; 164959243Sobrien 165059243Sobrien case TW_COMMAND: 165159243Sobrien case TW_VARLIST: 165259243Sobrien case TW_WORDLIST: 165359243Sobrien copyn(target, word, MAXNAMLEN); /* so it can match things */ 165459243Sobrien break; 165559243Sobrien 165659243Sobrien default: 165759243Sobrien xprintf(CGETS(30, 9, 165859243Sobrien "\n%s internal error: I don't know what I'm looking for!\n"), 165959243Sobrien progname); 166059243Sobrien NeedsRedraw = 1; 166159243Sobrien return (-1); 166259243Sobrien } 166359243Sobrien 166459243Sobrien numitems = tw_collect(command, looking, exp_dir, exp_name, 166559243Sobrien &target, pat, flags, dir_fd); 166659243Sobrien if (numitems == -1) 166759243Sobrien return -1; 166859243Sobrien 166959243Sobrien switch (command) { 167059243Sobrien case RECOGNIZE: 167159243Sobrien case RECOGNIZE_ALL: 167259243Sobrien case RECOGNIZE_SCROLL: 167359243Sobrien if (numitems <= 0) 167459243Sobrien return (numitems); 167559243Sobrien 167659243Sobrien tw_fixword(looking, word, dir, exp_name, max_word_length); 167759243Sobrien 167859243Sobrien if (!match_unique_match && is_set(STRaddsuffix) && numitems == 1) { 167959243Sobrien Char suffix[2]; 168059243Sobrien 168159243Sobrien suffix[1] = '\0'; 168259243Sobrien switch (suf) { 168359243Sobrien case 0: /* Automatic suffix */ 168459243Sobrien suffix[0] = tw_suffix(looking, exp_dir, exp_name, target, name); 168559243Sobrien break; 168659243Sobrien 168759243Sobrien case -1: /* No suffix */ 168859243Sobrien return numitems; 168959243Sobrien 169059243Sobrien default: /* completion specified suffix */ 169159243Sobrien suffix[0] = (Char) suf; 169259243Sobrien break; 169359243Sobrien } 169459243Sobrien catn(word, suffix, max_word_length); 169559243Sobrien } 169659243Sobrien return numitems; 169759243Sobrien 169859243Sobrien case LIST: 169959243Sobrien tw_list_items(looking, numitems, list_max); 170059243Sobrien tw_item_free(); 170159243Sobrien return (numitems); 170259243Sobrien 170359243Sobrien case SPELL: 170459243Sobrien tw_fixword(looking, word, dir, exp_name, max_word_length); 170559243Sobrien return (numitems); 170659243Sobrien 170759243Sobrien default: 170859243Sobrien xprintf("Bad tw_command\n"); 170959243Sobrien return (0); 171059243Sobrien } 171159243Sobrien} /* end t_search */ 171259243Sobrien 171359243Sobrien 171459243Sobrien/* extract_dir_and_name(): 171559243Sobrien * parse full path in file into 2 parts: directory and file names 171659243Sobrien * Should leave final slash (/) at end of dir. 171759243Sobrien */ 171859243Sobrienstatic void 171959243Sobrienextract_dir_and_name(path, dir, name) 172059243Sobrien Char *path, *dir, *name; 172159243Sobrien{ 172259243Sobrien register Char *p; 172359243Sobrien 172459243Sobrien p = Strrchr(path, '/'); 172569408Sache#ifdef WINNT_NATIVE 172659243Sobrien if (p == NULL) 172759243Sobrien p = Strrchr(path, ':'); 172869408Sache#endif /* WINNT_NATIVE */ 172959243Sobrien if (p == NULL) { 173059243Sobrien copyn(name, path, MAXNAMLEN); 173159243Sobrien dir[0] = '\0'; 173259243Sobrien } 173359243Sobrien else { 173459243Sobrien p++; 173559243Sobrien copyn(name, p, MAXNAMLEN); 173659243Sobrien copyn(dir, path, p - path); 173759243Sobrien } 173859243Sobrien} /* end extract_dir_and_name */ 173959243Sobrien 174059243Sobrien 174159243Sobrien/* dollar(): 174259243Sobrien * expand "/$old1/$old2/old3/" 174359243Sobrien * to "/value_of_old1/value_of_old2/old3/" 174459243Sobrien */ 174559243SobrienChar * 174659243Sobriendollar(new, old) 174759243Sobrien Char *new; 174859243Sobrien const Char *old; 174959243Sobrien{ 175059243Sobrien Char *p; 175159243Sobrien size_t space; 175259243Sobrien 175359243Sobrien for (space = FILSIZ, p = new; *old && space > 0;) 175459243Sobrien if (*old != '$') { 175559243Sobrien *p++ = *old++; 175659243Sobrien space--; 175759243Sobrien } 175859243Sobrien else { 175959243Sobrien if (expdollar(&p, &old, &space, QUOTE) == NULL) 176059243Sobrien return NULL; 176159243Sobrien } 176259243Sobrien *p = '\0'; 176359243Sobrien return (new); 176459243Sobrien} /* end dollar */ 176559243Sobrien 176659243Sobrien 176759243Sobrien/* tilde(): 176859243Sobrien * expand ~person/foo to home_directory_of_person/foo 176959243Sobrien * or =<stack-entry> to <dir in stack entry> 177059243Sobrien */ 177159243Sobrienstatic Char * 177259243Sobrientilde(new, old) 177359243Sobrien Char *new, *old; 177459243Sobrien{ 177559243Sobrien register Char *o, *p; 177659243Sobrien 177759243Sobrien switch (old[0]) { 177859243Sobrien case '~': 177959243Sobrien for (p = new, o = &old[1]; *o && *o != '/'; *p++ = *o++) 178059243Sobrien continue; 178159243Sobrien *p = '\0'; 178259243Sobrien if (gethdir(new)) { 178359243Sobrien new[0] = '\0'; 178459243Sobrien return NULL; 178559243Sobrien } 178683098Smp#ifdef apollo 178783098Smp /* Special case: if the home directory expands to "/", we do 178883098Smp * not want to create "//" by appending a slash from o. 178983098Smp */ 179083098Smp if (new[0] == '/' && new[1] == '\0' && *o == '/') 179183098Smp ++o; 179283098Smp#endif /* apollo */ 179359243Sobrien (void) Strcat(new, o); 179459243Sobrien return new; 179559243Sobrien 179659243Sobrien case '=': 179759243Sobrien if ((p = globequal(new, old)) == NULL) { 179859243Sobrien *new = '\0'; 179959243Sobrien return NULL; 180059243Sobrien } 180159243Sobrien if (p == new) 180259243Sobrien return new; 180359243Sobrien /*FALLTHROUGH*/ 180459243Sobrien 180559243Sobrien default: 180659243Sobrien (void) Strcpy(new, old); 180759243Sobrien return new; 180859243Sobrien } 180959243Sobrien} /* end tilde */ 181059243Sobrien 181159243Sobrien 181259243Sobrien/* expand_dir(): 181359243Sobrien * Open the directory given, expanding ~user and $var 181459243Sobrien * Optionally normalize the path given 181559243Sobrien */ 181659243Sobrienstatic int 181759243Sobrienexpand_dir(dir, edir, dfd, cmd) 181859243Sobrien Char *dir, *edir; 181959243Sobrien DIR **dfd; 182059243Sobrien COMMAND cmd; 182159243Sobrien{ 182259243Sobrien Char *nd = NULL; 182359243Sobrien Char tdir[MAXPATHLEN + 1]; 182459243Sobrien 182559243Sobrien if ((dollar(tdir, dir) == 0) || 182659243Sobrien (tilde(edir, tdir) == 0) || 182759243Sobrien !(nd = dnormalize(*edir ? edir : STRdot, symlinks == SYM_IGNORE || 182859243Sobrien symlinks == SYM_EXPAND)) || 182959243Sobrien ((*dfd = opendir(short2str(nd))) == NULL)) { 183059243Sobrien xfree((ptr_t) nd); 183159243Sobrien if (cmd == SPELL || SearchNoDirErr) 183259243Sobrien return (-2); 183359243Sobrien /* 183459243Sobrien * From: Amos Shapira <amoss@cs.huji.ac.il> 183559243Sobrien * Print a better message when completion fails 183659243Sobrien */ 183759243Sobrien xprintf("\n%S %s\n", 183859243Sobrien *edir ? edir : 183959243Sobrien (*tdir ? tdir : dir), 184059243Sobrien (errno == ENOTDIR ? CGETS(30, 10, "not a directory") : 184159243Sobrien (errno == ENOENT ? CGETS(30, 11, "not found") : 184259243Sobrien CGETS(30, 12, "unreadable")))); 184359243Sobrien NeedsRedraw = 1; 184459243Sobrien return (-1); 184559243Sobrien } 184659243Sobrien if (nd) { 184759243Sobrien if (*dir != '\0') { 184859243Sobrien Char *s, *d, *p; 184959243Sobrien 185059243Sobrien /* 185159243Sobrien * Copy and append a / if there was one 185259243Sobrien */ 185359243Sobrien for (p = edir; *p; p++) 185459243Sobrien continue; 185559243Sobrien if (*--p == '/') { 185659243Sobrien for (p = nd; *p; p++) 185759243Sobrien continue; 185859243Sobrien if (*--p != '/') 185959243Sobrien p = NULL; 186059243Sobrien } 186159243Sobrien for (d = edir, s = nd; (*d++ = *s++) != '\0';) 186259243Sobrien continue; 186359243Sobrien if (!p) { 186459243Sobrien *d-- = '\0'; 186559243Sobrien *d = '/'; 186659243Sobrien } 186759243Sobrien } 186859243Sobrien xfree((ptr_t) nd); 186959243Sobrien } 187059243Sobrien return 0; 187159243Sobrien} /* end expand_dir */ 187259243Sobrien 187359243Sobrien 187459243Sobrien/* nostat(): 187559243Sobrien * Returns true if the directory should not be stat'd, 187659243Sobrien * false otherwise. 187759243Sobrien * This way, things won't grind to a halt when you complete in /afs 187859243Sobrien * or very large directories. 187959243Sobrien */ 188059243Sobrienstatic bool 188159243Sobriennostat(dir) 188259243Sobrien Char *dir; 188359243Sobrien{ 188459243Sobrien struct varent *vp; 188559243Sobrien register Char **cp; 188659243Sobrien 188759243Sobrien if ((vp = adrof(STRnostat)) == NULL || (cp = vp->vec) == NULL) 188859243Sobrien return FALSE; 188959243Sobrien for (; *cp != NULL; cp++) { 189059243Sobrien if (Strcmp(*cp, STRstar) == 0) 189159243Sobrien return TRUE; 189259243Sobrien if (Gmatch(dir, *cp)) 189359243Sobrien return TRUE; 189459243Sobrien } 189559243Sobrien return FALSE; 189659243Sobrien} /* end nostat */ 189759243Sobrien 189859243Sobrien 189959243Sobrien/* filetype(): 190059243Sobrien * Return a character that signifies a filetype 190159243Sobrien * symbology from 4.3 ls command. 190259243Sobrien */ 190359243Sobrienstatic Char 190459243Sobrienfiletype(dir, file) 190559243Sobrien Char *dir, *file; 190659243Sobrien{ 190759243Sobrien if (dir) { 190859243Sobrien Char path[512]; 190959243Sobrien char *ptr; 191059243Sobrien struct stat statb; 191159243Sobrien#ifdef S_ISCDF 191259243Sobrien /* 191359243Sobrien * From: veals@crchh84d.bnr.ca (Percy Veals) 191459243Sobrien * An extra stat is required for HPUX CDF files. 191559243Sobrien */ 191659243Sobrien struct stat hpstatb; 191759243Sobrien#endif /* S_ISCDF */ 191859243Sobrien 191959243Sobrien if (nostat(dir)) return(' '); 192059243Sobrien 192159243Sobrien (void) Strcpy(path, dir); 192259243Sobrien catn(path, file, (int) (sizeof(path) / sizeof(Char))); 192359243Sobrien 192459243Sobrien if (lstat(ptr = short2str(path), &statb) != -1) 192559243Sobrien /* see above #define of lstat */ 192659243Sobrien { 192759243Sobrien#ifdef S_ISLNK 192859243Sobrien if (S_ISLNK(statb.st_mode)) { /* Symbolic link */ 192959243Sobrien if (adrof(STRlistlinks)) { 193059243Sobrien if (stat(ptr, &statb) == -1) 193159243Sobrien return ('&'); 193259243Sobrien else if (S_ISDIR(statb.st_mode)) 193359243Sobrien return ('>'); 193459243Sobrien else 193559243Sobrien return ('@'); 193659243Sobrien } 193759243Sobrien else 193859243Sobrien return ('@'); 193959243Sobrien } 194059243Sobrien#endif 194159243Sobrien#ifdef S_ISSOCK 194259243Sobrien if (S_ISSOCK(statb.st_mode)) /* Socket */ 194359243Sobrien return ('='); 194459243Sobrien#endif 194559243Sobrien#ifdef S_ISFIFO 194659243Sobrien if (S_ISFIFO(statb.st_mode)) /* Named Pipe */ 194759243Sobrien return ('|'); 194859243Sobrien#endif 194959243Sobrien#ifdef S_ISHIDDEN 195059243Sobrien if (S_ISHIDDEN(statb.st_mode)) /* Hidden Directory [aix] */ 195159243Sobrien return ('+'); 195259243Sobrien#endif 195359243Sobrien#ifdef S_ISCDF 195459243Sobrien (void) strcat(ptr, "+"); /* Must append a '+' and re-stat(). */ 195559243Sobrien if ((stat(ptr, &hpstatb) != -1) && S_ISCDF(hpstatb.st_mode)) 195659243Sobrien return ('+'); /* Context Dependent Files [hpux] */ 195759243Sobrien#endif 195859243Sobrien#ifdef S_ISNWK 195959243Sobrien if (S_ISNWK(statb.st_mode)) /* Network Special [hpux] */ 196059243Sobrien return (':'); 196159243Sobrien#endif 196259243Sobrien#ifdef S_ISCHR 196359243Sobrien if (S_ISCHR(statb.st_mode)) /* char device */ 196459243Sobrien return ('%'); 196559243Sobrien#endif 196659243Sobrien#ifdef S_ISBLK 196759243Sobrien if (S_ISBLK(statb.st_mode)) /* block device */ 196859243Sobrien return ('#'); 196959243Sobrien#endif 197059243Sobrien#ifdef S_ISDIR 197159243Sobrien if (S_ISDIR(statb.st_mode)) /* normal Directory */ 197259243Sobrien return ('/'); 197359243Sobrien#endif 197459243Sobrien if (statb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) 197559243Sobrien return ('*'); 197659243Sobrien } 197759243Sobrien } 197859243Sobrien return (' '); 197959243Sobrien} /* end filetype */ 198059243Sobrien 198159243Sobrien 198259243Sobrien/* isadirectory(): 198359243Sobrien * Return trus if the file is a directory 198459243Sobrien */ 198559243Sobrienstatic int 198659243Sobrienisadirectory(dir, file) /* return 1 if dir/file is a directory */ 198759243Sobrien Char *dir, *file; /* uses stat rather than lstat to get dest. */ 198859243Sobrien{ 198959243Sobrien if (dir) { 199059243Sobrien Char path[MAXPATHLEN]; 199159243Sobrien struct stat statb; 199259243Sobrien 199359243Sobrien (void) Strcpy(path, dir); 199459243Sobrien catn(path, file, (int) (sizeof(path) / sizeof(Char))); 199559243Sobrien if (stat(short2str(path), &statb) >= 0) { /* resolve through 199659243Sobrien * symlink */ 199759243Sobrien#ifdef S_ISSOCK 199859243Sobrien if (S_ISSOCK(statb.st_mode)) /* Socket */ 199959243Sobrien return 0; 200059243Sobrien#endif 200159243Sobrien#ifdef S_ISFIFO 200259243Sobrien if (S_ISFIFO(statb.st_mode)) /* Named Pipe */ 200359243Sobrien return 0; 200459243Sobrien#endif 200559243Sobrien if (S_ISDIR(statb.st_mode)) /* normal Directory */ 200659243Sobrien return 1; 200759243Sobrien } 200859243Sobrien } 200959243Sobrien return 0; 201059243Sobrien} /* end isadirectory */ 201159243Sobrien 201259243Sobrien 201359243Sobrien 201459243Sobrien/* find_rows(): 201559243Sobrien * Return how many rows needed to print sorted down columns 201659243Sobrien */ 201759243Sobrienstatic int 201859243Sobrienfind_rows(items, count, no_file_suffix) 201959243Sobrien Char *items[]; 202059243Sobrien int count, no_file_suffix; 202159243Sobrien{ 202259243Sobrien register int i, columns, rows; 202359243Sobrien unsigned int maxwidth = 0; 202459243Sobrien 202559243Sobrien for (i = 0; i < count; i++) /* find widest string */ 202659243Sobrien maxwidth = max(maxwidth, (unsigned int) Strlen(items[i])); 202759243Sobrien 202859243Sobrien maxwidth += no_file_suffix ? 1 : 2; /* for the file tag and space */ 202959243Sobrien columns = (TermH + 1) / maxwidth; /* PWP: terminal size change */ 203059243Sobrien if (!columns) 203159243Sobrien columns = 1; 203259243Sobrien rows = (count + (columns - 1)) / columns; 203359243Sobrien 203459243Sobrien return rows; 203559243Sobrien} /* end rows_needed_by_print_by_column */ 203659243Sobrien 203759243Sobrien 203859243Sobrien/* print_by_column(): 203959243Sobrien * Print sorted down columns or across columns when the first 204059243Sobrien * word of $listflags shell variable contains 'x'. 204159243Sobrien * 204259243Sobrien */ 204359243Sobrienvoid 204459243Sobrienprint_by_column(dir, items, count, no_file_suffix) 204559243Sobrien register Char *dir, *items[]; 204659243Sobrien int count, no_file_suffix; 204759243Sobrien{ 204859243Sobrien register int i, r, c, columns, rows; 204959243Sobrien unsigned int w, maxwidth = 0; 205059243Sobrien Char *val; 205159243Sobrien bool across; 205259243Sobrien 205359243Sobrien lbuffed = 0; /* turn off line buffering */ 205459243Sobrien 205559243Sobrien 205659243Sobrien across = ((val = varval(STRlistflags)) != STRNULL) && 205759243Sobrien (Strchr(val, 'x') != NULL); 205859243Sobrien 205959243Sobrien for (i = 0; i < count; i++) /* find widest string */ 206059243Sobrien maxwidth = max(maxwidth, (unsigned int) Strlen(items[i])); 206159243Sobrien 206259243Sobrien maxwidth += no_file_suffix ? 1 : 2; /* for the file tag and space */ 206359243Sobrien columns = TermH / maxwidth; /* PWP: terminal size change */ 206459243Sobrien if (!columns || !isatty(didfds ? 1 : SHOUT)) 206559243Sobrien columns = 1; 206659243Sobrien rows = (count + (columns - 1)) / columns; 206759243Sobrien 206859243Sobrien i = -1; 206959243Sobrien for (r = 0; r < rows; r++) { 207059243Sobrien for (c = 0; c < columns; c++) { 207159243Sobrien i = across ? (i + 1) : (c * rows + r); 207259243Sobrien 207359243Sobrien if (i < count) { 207459243Sobrien w = (unsigned int) Strlen(items[i]); 207559243Sobrien 207659243Sobrien#ifdef COLOR_LS_F 207759243Sobrien if (no_file_suffix) { 207859243Sobrien /* Print the command name */ 207959243Sobrien Char f = items[i][w - 1]; 208059243Sobrien items[i][w - 1] = 0; 208159243Sobrien print_with_color(items[i], w - 1, f); 208259243Sobrien } 208359243Sobrien else { 208459243Sobrien /* Print filename followed by '/' or '*' or ' ' */ 208559243Sobrien print_with_color(items[i], w, filetype(dir, items[i])); 208659243Sobrien w++; 208759243Sobrien } 208859243Sobrien#else /* ifndef COLOR_LS_F */ 208959243Sobrien if (no_file_suffix) { 209059243Sobrien /* Print the command name */ 209159243Sobrien xprintf("%S", items[i]); 209259243Sobrien } 209359243Sobrien else { 209459243Sobrien /* Print filename followed by '/' or '*' or ' ' */ 209559243Sobrien xprintf("%S%c", items[i], 209659243Sobrien filetype(dir, items[i])); 209759243Sobrien w++; 209859243Sobrien } 209959243Sobrien#endif /* COLOR_LS_F */ 210059243Sobrien 210159243Sobrien if (c < (columns - 1)) /* Not last column? */ 210259243Sobrien for (; w < maxwidth; w++) 210359243Sobrien xputchar(' '); 210459243Sobrien } 210559243Sobrien else if (across) 210659243Sobrien break; 210759243Sobrien } 210859243Sobrien if (Tty_raw_mode) 210959243Sobrien xputchar('\r'); 211059243Sobrien xputchar('\n'); 211159243Sobrien } 211259243Sobrien 211359243Sobrien lbuffed = 1; /* turn back on line buffering */ 211459243Sobrien flush(); 211559243Sobrien} /* end print_by_column */ 211659243Sobrien 211759243Sobrien 211859243Sobrien/* StrQcmp(): 211959243Sobrien * Compare strings ignoring the quoting chars 212059243Sobrien */ 212159243Sobrienint 212259243SobrienStrQcmp(str1, str2) 212359243Sobrien register Char *str1, *str2; 212459243Sobrien{ 212559243Sobrien for (; *str1 && samecase(*str1 & TRIM) == samecase(*str2 & TRIM); 212659243Sobrien str1++, str2++) 212759243Sobrien continue; 212859243Sobrien /* 212959243Sobrien * The following case analysis is necessary so that characters which look 213059243Sobrien * negative collate low against normal characters but high against the 213159243Sobrien * end-of-string NUL. 213259243Sobrien */ 213359243Sobrien if (*str1 == '\0' && *str2 == '\0') 213459243Sobrien return (0); 213559243Sobrien else if (*str1 == '\0') 213659243Sobrien return (-1); 213759243Sobrien else if (*str2 == '\0') 213859243Sobrien return (1); 213959243Sobrien else 214059243Sobrien return ((*str1 & TRIM) - (*str2 & TRIM)); 214159243Sobrien} /* end StrQcmp */ 214259243Sobrien 214359243Sobrien 214459243Sobrien/* fcompare(): 214559243Sobrien * Comparison routine for qsort 214659243Sobrien */ 214759243Sobrienint 214859243Sobrienfcompare(file1, file2) 214959243Sobrien Char **file1, **file2; 215059243Sobrien{ 215159243Sobrien return (int) collate(*file1, *file2); 215259243Sobrien} /* end fcompare */ 215359243Sobrien 215459243Sobrien 215559243Sobrien/* catn(): 215659243Sobrien * Concatenate src onto tail of des. 215759243Sobrien * Des is a string whose maximum length is count. 215859243Sobrien * Always null terminate. 215959243Sobrien */ 216059243Sobrienvoid 216159243Sobriencatn(des, src, count) 216259243Sobrien register Char *des, *src; 216359243Sobrien int count; 216459243Sobrien{ 216559243Sobrien while (--count >= 0 && *des) 216659243Sobrien des++; 216759243Sobrien while (--count >= 0) 216859243Sobrien if ((*des++ = *src++) == 0) 216959243Sobrien return; 217059243Sobrien *des = '\0'; 217159243Sobrien} /* end catn */ 217259243Sobrien 217359243Sobrien 217459243Sobrien/* copyn(): 217559243Sobrien * like strncpy but always leave room for trailing \0 217659243Sobrien * and always null terminate. 217759243Sobrien */ 217859243Sobrienvoid 217959243Sobriencopyn(des, src, count) 218059243Sobrien register Char *des, *src; 218159243Sobrien int count; 218259243Sobrien{ 218359243Sobrien while (--count >= 0) 218459243Sobrien if ((*des++ = *src++) == 0) 218559243Sobrien return; 218659243Sobrien *des = '\0'; 218759243Sobrien} /* end copyn */ 218859243Sobrien 218959243Sobrien 219059243Sobrien/* tgetenv(): 219159243Sobrien * like it's normal string counter-part 219259243Sobrien * [apollo uses that in tc.os.c, so it cannot be static] 219359243Sobrien */ 219459243SobrienChar * 219559243Sobrientgetenv(str) 219659243Sobrien Char *str; 219759243Sobrien{ 219859243Sobrien Char **var; 219959243Sobrien int len, res; 220059243Sobrien 220159243Sobrien len = (int) Strlen(str); 220259243Sobrien /* Search the STR_environ for the entry matching str. */ 220359243Sobrien for (var = STR_environ; var != NULL && *var != NULL; var++) 220459243Sobrien if (Strlen(*var) >= len && (*var)[len] == '=') { 220559243Sobrien /* Temporarily terminate the string so we can copy the variable 220659243Sobrien name. */ 220759243Sobrien (*var)[len] = '\0'; 220859243Sobrien res = StrQcmp(*var, str); 220959243Sobrien /* Restore the '=' and return a pointer to the value of the 221059243Sobrien environment variable. */ 221159243Sobrien (*var)[len] = '='; 221259243Sobrien if (res == 0) 221359243Sobrien return (&((*var)[len + 1])); 221459243Sobrien } 221559243Sobrien return (NULL); 221659243Sobrien} /* end tgetenv */ 221759243Sobrien 221859243Sobrien 221959243Sobrienstruct scroll_tab_list *scroll_tab = 0; 222059243Sobrien 222159243Sobrienstatic void 222259243Sobrienadd_scroll_tab(item) 222359243Sobrien Char *item; 222459243Sobrien{ 222559243Sobrien struct scroll_tab_list *new_scroll; 222659243Sobrien 222759243Sobrien new_scroll = (struct scroll_tab_list *) xmalloc((size_t) 222859243Sobrien sizeof(struct scroll_tab_list)); 222959243Sobrien new_scroll->element = Strsave(item); 223059243Sobrien new_scroll->next = scroll_tab; 223159243Sobrien scroll_tab = new_scroll; 223259243Sobrien} 223359243Sobrien 223459243Sobrienstatic void 223559243Sobrienchoose_scroll_tab(exp_name, cnt) 223659243Sobrien Char **exp_name; 223759243Sobrien int cnt; 223859243Sobrien{ 223959243Sobrien struct scroll_tab_list *loop; 224059243Sobrien int tmp = cnt; 224159243Sobrien Char **ptr; 224259243Sobrien 224359243Sobrien ptr = (Char **) xmalloc((size_t) sizeof(Char *) * cnt); 224459243Sobrien 224559243Sobrien for(loop = scroll_tab; loop && (tmp >= 0); loop = loop->next) 224659243Sobrien ptr[--tmp] = loop->element; 224759243Sobrien 224859243Sobrien qsort((ptr_t) ptr, (size_t) cnt, sizeof(Char *), 224959243Sobrien (int (*) __P((const void *, const void *))) fcompare); 225059243Sobrien 225159243Sobrien copyn(*exp_name, ptr[curchoice], (int) Strlen(ptr[curchoice])); 225259243Sobrien xfree((ptr_t) ptr); 225359243Sobrien} 225459243Sobrien 225559243Sobrienstatic void 225659243Sobrienfree_scroll_tab() 225759243Sobrien{ 225859243Sobrien struct scroll_tab_list *loop; 225959243Sobrien 226059243Sobrien while(scroll_tab) { 226159243Sobrien loop = scroll_tab; 226259243Sobrien scroll_tab = scroll_tab->next; 226359243Sobrien xfree((ptr_t) loop->element); 226459243Sobrien xfree((ptr_t) loop); 226559243Sobrien } 226659243Sobrien} 2267