/***********************************************************************
* *
* This software is part of the ast package *
* Copyright (c) 1982-2011 AT&T Intellectual Property *
* and is licensed under the *
* Common Public License, Version 1.0 *
* by AT&T Intellectual Property *
* *
* A copy of the License is available at *
* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
* *
* Information and Software Systems Research *
* AT&T Research *
* Florham Park NJ *
* *
* David Korn <dgk@research.att.com> *
* *
***********************************************************************/
#pragma prototyped
/*
* completion.c - command and file completion for shell editors
*
*/
#include "defs.h"
#include <ast_wchar.h>
#include "lexstates.h"
#include "path.h"
#include "io.h"
#include "edit.h"
#include "history.h"
#if !SHOPT_MULTIBYTE
#define mbchar(p) (*(unsigned char*)p++)
#endif
{
register int n,c;
if(*cp=='#')
stakputc('\\');
return((char*)string);
{
{
if(state[c])
stakputc('\\');
stakputc(c);
}
else
}
stakputc(0);
}
{
if(nocase)
{
if(isupper(a))
a = tolower(a);
if(isupper(b))
b = tolower(b);
}
return(a==b);
}
/*
* overwrites <str> to common prefix of <str> and <newstr>
* if <str> is equal to <newstr> returns <str>+strlen(<str>)+1
* otherwise returns <str>+strlen(<str>)
*/
{
register int c,d;
str++;
if(*str)
*str = 0;
else if(*newstr==0)
str++;
return(str);
}
/*
* returns pointer to beginning of expansion and sets type of expansion
*/
{
*type = 0;
{
{
case '\'': case '"':
if(!inquote)
{
inquote = c;
break;
}
if(inquote==c)
inquote = 0;
break;
case '\\':
if(inquote != '\'')
break;
case '$':
if(inquote == '\'')
break;
c = *(unsigned char*)cp;
{
if(c=='{')
{
c = *(unsigned char*)cp;
if(c!='.' && !isaletter(c))
break;
}
else
dot = 'a';
{
break;
}
{
{
*type='$';
return(++xp);
}
if(c!='}')
}
}
else if(c=='(')
{
else
cp++;
}
break;
case '=':
if(!inquote)
{
inassign = 1;
}
break;
case ':':
break;
case '~':
if(*cp=='(')
break;
/* fall through */
default:
if(c && c==endchar)
return(xp);
{
inassign = 0;
}
break;
}
}
return(bp);
}
/*
* file name generation for edit modes
* non-zero exit for error, <0 ring bell
* don't search back past beginning of the buffer
* mode is '*' for inline expansion,
* mode is '\' for filename completion
* mode is '=' cause files to be listed in select format
*/
{
register char *out;
{
{
return(-1);
mode = '?';
av[1] = 0;
}
else
{
}
}
#if SHOPT_MULTIBYTE
{
register int c = *cur;
/* adjust cur */
c = *cp;
*cp = 0;
*cp = c;
}
#endif /* SHOPT_MULTIBYTE */
{
register int c;
c = *(unsigned char*)out;
/* addstar set to zero if * should not be added */
if(var=='$')
{
stakputs("${!");
stakputs("@}");
}
else
{
addstar = '*';
{
c = *(unsigned char*)out;
if(isexp(c))
addstar = 0;
if (c == '/')
{
if(addstar == 0)
strip = 0;
}
stakputc(c);
out++;
}
}
if(mode=='?')
mode = '*';
addstar = '*';
addstar = 0;
}
if(mode!='*')
{
register char **com;
cp--;
if(!var && !strchr(ap->argval,'/') && (((cp==outbuff&&ep->sh->nextprompt==1) || (strchr(";&|(",size)) && (cp==outbuff+1||size=='('||cp[-2]!='>') && *begin!='~' )))
{
}
{
narg = 1;
if(dir)
}
else
{
/* special handling for leading quotes */
begin--;
}
/* allow a search to be aborted */
{
rval = -1;
goto done;
}
/* match? */
if (*com==0 || (narg <= 1 && (strcmp(ap->argval,*com)==0) || (addstar && com[0][strlen(*com)-1]=='*')))
{
rval = -1;
goto done;
}
if(mode=='=')
{
if (strip && !cmd_completion)
{
register char **ptrcom;
/* trim directory prefix */
}
goto done;
}
/* see if there is enough room */
if(mode=='\\')
{
int c;
if(dir)
{
c = *dir;
*dir = 0;
}
if(dir)
*dir = c;
/* just expand until name is unique */
}
else
{
{
while (*com)
}
}
/* see if room for expansion */
{
com[1] = 0;
}
/* save remainder of the buffer */
if(*out)
else if(mode=='*')
{
{
cp++;
else
var = 0;
}
else
com++;
}
else
if(mode=='\\')
{
{
if(cmd_completion)
else
}
if(out[-1]==0)
out--;
{
if(cmd_completion)
{
/* add as tracked alias */
if(*cp=='/' && (pp=path_dirfind(ep->sh->pathlist,cp,'/')) && (np=nv_search(begin,ep->sh->track_tree,NV_ADD)))
}
/* add quotes if necessary */
*out = '}';
else
*out = ' ';
*++out = 0;
}
{
*--out = 0;
}
if(*begin==0)
ed_ringbell();
}
else
{
while (*com)
{
*out++ = ' ';
}
}
{
{
*out = '}';
else
*out = ' ';
out++;
}
out--;
*out = 0;
}
/* restore rest of buffer */
if(left)
}
done:
if(nomarkdirs)
#if SHOPT_MULTIBYTE
{
register int c,n=0;
/* first re-adjust cur */
*cur = n;
}
#endif /* SHOPT_MULTIBYTE */
return(rval);
}
/*
* look for edit macro named _i
* if found, puts the macro definition into lookahead buffer and returns 1
*/
{
register char *out;
if(i != '@')
/* undocumented feature, macros of the form <ESC>[c evoke alias __c */
if(i=='_')
else
{
#if SHOPT_MULTIBYTE
/* copy to buff in internal representation */
int c = 0;
{
}
if(c)
#else
#endif /* SHOPT_MULTIBYTE */
while(i-- > 0)
return(1);
}
return(0);
}
/*
* Enter the fc command on the current history line
*/
{
register char *cp;
return(-1);
/* use EDITOR on current command */
{
return(-1);
#if SHOPT_MULTIBYTE
#endif /* SHOPT_MULTIBYTE */
}
return(0);
}