2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
24 * $TOG: shellscan.C /main/9 1999/10/14 15:05:42 mgreess $
26 * (c) Copyright 1996 Digital Equipment Corporation.
27 * (c) Copyright 1993,1994,1996 Hewlett-Packard Company.
28 * (c) Copyright 1993,1994,1996 International Business Machines Corp.
29 * (c) Copyright 1993,1994,1996 Sun Microsystems, Inc.
30 * (c) Copyright 1993,1994,1996 Novell, Inc.
31 * (c) Copyright 1996 FUJITSU LIMITED.
32 * (c) Copyright 1996 Hitachi.
34 # if defined(apollo) && !defined(___GID_T)
35 // This kludge is needed for the include conflicts mentioned below
36 // Remove when no longer necessary
37 # define _NEED___PID_T
40 #ifdef DOMAIN_ALLOW_MALLOC_OVERRIDE
41 #include "/usr/include/apollo/shlib.h"
47 #define X_INCLUDE_PWD_H
48 #define XOS_USE_XT_LOCKING
49 #include <X11/Xos_r.h>
50 #include <codelibs/nl_hack.h>
53 // This kludge because of include conflicts between stdlib.h and unistd.h
54 // Remove when problem is fixed
59 _DECL_FUNC(__pid_t, getpid, (void))
63 #else /* not apollo */
65 #endif /* not apollo */
69 #include <codelibs/shellutils.h>
71 #include <codelibs/boolean.h>
72 #include <codelibs/stringx.h>
73 #include "DtSvcLock.h"
77 extern void XtProcessLock(void);
78 extern void XtProcessUnlock(void);
82 #define ISIDENT(CH) (isalnum(CH) || (CH) == '_')
84 static _SHXbuf *buf = NULL;
85 static const char *getvar(const char *var, char *);
87 // Make this a global someday:
88 static const char *(*shellvarfn)(const char *, char *) = getvar;
90 // Parse a sequence of the ksh meta-characters ;&|<> and whitespace
91 // into a single ksh token. Return a pointer to the token as a
92 // string. All whitespace characters are mapped to a single space
93 // character. If ch is not a meta-character, return a NULL pointer.
95 parsemeta(int ch, _StringIO &in, char *ifs, unsigned opts, char *meta)
98 return " "; // whitespace
101 if (buf->quote() != NOQUOTE) {
102 _DtSvcProcessUnlock();
103 return NULL; // normal character
106 if (!(opts & SHX_NOSPACE) && strchr(ifs, ch) != NULL) {
107 _DtSvcProcessUnlock();
108 return " "; // whitespace
111 if (!(opts & SHX_NOMETA))
115 if (buf->new_token() && isascii(ch) && isdigit(ch))
116 if (in.next() == '<' || in.next() == '>')
118 meta[len++] = (char)ch;
122 switch (meta[len++] = (char)ch, ch)
128 meta[len++] = (in.next() == ch) ? in.get() : '\0';
130 _DtSvcProcessUnlock();
133 meta[len++] = (in.next() == '|' || in.next() == '&') ?
136 _DtSvcProcessUnlock();
140 if (in.next() == ch || in.next() == '&')
141 meta[len++] = (char)in.get();
143 _DtSvcProcessUnlock();
148 _DtSvcProcessUnlock();
149 return NULL; // normal character
152 // Takes the name of a variable, and looks up it's value. Someday,
153 // this will be replaceable by the user.
155 getvar(const char *name, char *buff)
157 if (name[0] != '\0' && name[1] == '\0')
161 sprintf(buff, "%d", getpid());
171 // Parse an environment variable name from the _StringIO stream,
172 // and push its value into the _StringIO stream stack.
174 pushvar(_StringIO &in, char *buff)
177 privbuf_charbuf name;
180 int ch = tmp.get(); // get the first character after the $
186 while ((ch = tmp.get()) != '\0')
188 // ${foo!bar} form, grab everything inside {} as name
189 if (ch == '\\') // Only \ does quoting inside ${}
195 else if (ispunct(ch))
196 switch (ch) // Special non-alnum shell variables
211 else if (isdigit(ch))
212 name.end() = ch; // single-digit variables
213 else if (ISIDENT(ch))
218 while (isascii(ch = tmp.get()) && ISIDENT(ch));
227 in.push(shellvarfn(name.getarr(), buff));
232 pushenv(_StringIO &in, char const *name)
234 register char *str = getenv(name);
235 if (str == NULL || *str == '\0')
245 pushtilde(_StringIO &in)
249 privbuf_charbuf name;
254 while ((ch = tmp.get()) != '\0' && ch != '/')
255 name[namelen++] = ch;
256 name[namelen] = '\0';
259 char *str = name.getarr();
263 if (!pushenv(tmp, "HOME"))
267 if (!pushenv(tmp, "PWD"))
271 if (!pushenv(tmp, "OLDPWD"))
276 _Xgetpwparams pwd_buf;
277 memset((char*) &pwd_buf, 0, sizeof(_Xgetpwparams));
278 struct passwd * pwd_ret = _XGetpwnam(str, pwd_buf);
282 tmp.push(pwd_ret->pw_dir);
292 pushgrave(_StringIO &in, const char endchar, boolean quotes, privbuf_charbuf &result)
295 char quote = NOQUOTE;
310 break; // not recognized inside of ""
313 while ((ch = in.get()) != '\'' && ch != '\0');
329 } while (ch != '\0');
333 FILE *fp = popen(cmd.getarr(), "r");
336 while ((ch = getc(fp)) != EOF)
340 // Remove trailing newline, if any
341 long end = result.size() - 1;
342 if (result[end] == '\n')
346 in.push(result.getarr());
350 shellscan(char const *str, int *argc, unsigned opts)
352 if (opts & SHX_COMPLETE)
353 opts |= SHX_NOSPACE | SHX_NOMETA;
355 char *ifs = getenv("IFS");
363 buf->reset((boolean)!(opts & SHX_NOGLOB), (boolean)(opts & SHX_COMPLETE));
367 char buff[10], meta_buff[4];
368 privbuf_charbuf result;
374 // Don't recognize special characters if this is a shell
375 // variable or command substitution.
376 if (!in.in_expansion())
378 // Handle quoting rules, setting the flag array and
379 // quote variable appropriately.
380 if (!(opts & SHX_NOQUOTES))
384 buf->quote(DOUBLEQUOTE);
387 if (buf->quote() == DOUBLEQUOTE)
388 break; // not recognized inside of ""
389 buf->quote(SINGLEQUOTE);
390 while ((ch = in.get()) != '\'' && ch != '\0')
392 buf->quote(SINGLEQUOTE);
396 if (ch == '\n') // ignore \<newline>
400 #if defined(__aix) /* Our Macro doesn't like '\\' (ignores rest of line) */
404 buf->append('\\', SINGLEQUOTE);
408 if (buf->quote() == NOQUOTE)
410 buf->append(ch, SINGLEQUOTE);
415 // inside "", \ only quotes these 4 characters:
422 buf->append(ch, SINGLEQUOTE);
425 // treat the \ and the following char normally
433 if (!(opts & SHX_NOCMD))
437 pushgrave(in, '`', (boolean)!(opts & SHX_NOQUOTES), result);
440 if (in.next() != '(')
442 in.get(); // skip the '('
443 pushgrave(in, ')', (boolean)!(opts & SHX_NOQUOTES), result);
447 if (ch == '~' && buf->new_token() && buf->quote() == NOQUOTE)
448 if (!(opts & SHX_NOTILDE))
456 if (ch == '$' && !(opts & SHX_NOVARS))
458 if (pushvar(in, buff))
465 // If the next item is an unquoted whitespace character or
466 // metacharacter token, terminate the current token. The NUL
467 // character is considered to be whitespace.
469 int curr_opts = opts;
471 if (in.in_expansion())
472 curr_opts |= SHX_NOMETA;
474 char *meta = parsemeta(ch, in, ifs, curr_opts, meta_buff);
476 if (meta != NULL) // is it a meta-character?
478 // Terminate current token, if any
479 if (!buf->new_token())
481 if (*meta == ' ') // whitespace
483 // ignore contiguous whitespace chars
484 if (buf->new_token())
487 else // append the metachar token
494 } while (ch != '\0');
497 *argc = buf->ntokens();
499 _DtSvcProcessUnlock();
500 return ( (char const *const *) buf->vector() );
501 /* !!! error 1325: `)' missing at end of input */