📄 iwordexp.c
字号:
/* POSIX.2 wordexp implementation. Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Tim Waugh <tim@cyberelk.demon.co.uk>. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *//* Modified for Intercom by Shane Wegner <shane@cm.nu> */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <ctype.h>#include <errno.h>#include <fcntl.h>#include <fnmatch.h>#include <glob.h>#include <paths.h>#include <pwd.h>#include <signal.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/param.h>#include <sys/stat.h>#include <sys/time.h>#include <sys/types.h>#include <sys/types.h>#include <sys/wait.h>#include <unistd.h>#ifdef USE_IN_LIBIO# include <wchar.h>#endif#ifdef USE_GETTEXT#ifdef HAVE_LOCALE_H#include <locale.h>#endif#include <libintl.h>#define _(String) gettext(String)#define gettext_noop(String) (String)#define N_(String) gettext_noop(String)#else#define _(String) (String)#define N_(String) (String)#endif#include "iwordexp.h"/* Undefine the following line for the production version. *//* #define NDEBUG 1 */#include <assert.h>#ifndef internal_function#define internal_function#endifextern char **environ;#ifndef strdupa/* Duplicate S, returning an identical alloca'd string. */# define strdupa(s) \ (({ \ __const char *__old = (s); \ size_t __len = strlen (__old) + 1; \ char *__new = (char *) alloca (__len); \ (char *) memcpy (__new, __old, __len); \ }))#endif#ifndef strndupa/* Return an alloca'd copy of at most N bytes of string. */# define strndupa(s, n) \ (({ \ __const char *__old = (s); \ size_t __len = strnlen (__old, (n)); \ char *__new = (char *) alloca (__len + 1); \ __new[__len] = '\0'; \ (char *) memcpy (__new, __old, __len); \ }))#endif/* * This is a recursive-descent-style word expansion routine. *//* Some forward declarations */static int parse_dollars (char **word, size_t *word_length, size_t *max_length, const char *words, size_t *offset, int flags, wordexp_t *pwordexp, const char *ifs, const char *ifs_white, int quoted) internal_function;static int parse_backtick (char **word, size_t *word_length, size_t *max_length, const char *words, size_t *offset, int flags, wordexp_t *pwordexp, const char *ifs, const char *ifs_white) internal_function;static int parse_dquote (char **word, size_t *word_length, size_t *max_length, const char *words, size_t *offset, int flags, wordexp_t *pwordexp, const char *ifs, const char *ifs_white) internal_function;static int eval_expr (char *expr, long int *result) internal_function;/* Convert VALUE into ASCII in base BASE (2..36). Write backwards starting the character just before BUFLIM. Return the address of the first (left-to-right) character in the number. Use upper case letters iff UPPER_CASE is nonzero. */static char *itoa (unsigned long long int value, char *buflim, unsigned int base, int upper_case);#define itoa_word itoa/* The w_*() functions manipulate word lists. */#define W_CHUNK (100)/* Result of w_newword will be ignored if it's the last word. */static inline char *w_newword (size_t *actlen, size_t *maxlen){ *actlen = *maxlen = 0; return NULL;}static inline char *w_addchar (char *buffer, size_t *actlen, size_t *maxlen, char ch) /* (lengths exclude trailing zero) */{ /* Add a character to the buffer, allocating room for it if needed. */ if (*actlen == *maxlen) { char *old_buffer = buffer; assert (buffer == NULL || *maxlen != 0); *maxlen += W_CHUNK; buffer = realloc (buffer, 1 + *maxlen); if (buffer == NULL) free (old_buffer); } if (buffer != NULL) { buffer[*actlen] = ch; buffer[++(*actlen)] = '\0'; } return buffer;}static char *internal_functionw_addmem (char *buffer, size_t *actlen, size_t *maxlen, const char *str, size_t len){ /* Add a string to the buffer, allocating room for it if needed. */ if (*actlen + len > *maxlen) { char *old_buffer = buffer; assert (buffer == NULL || *maxlen != 0); *maxlen += MAX (2 * len, W_CHUNK); buffer = realloc (old_buffer, 1 + *maxlen); if (buffer == NULL) free (old_buffer); } if (buffer != NULL) { *((char *) mempcpy (&buffer[*actlen], str, len)) = '\0'; *actlen += len; } return buffer;}static char *internal_functionw_addstr (char *buffer, size_t *actlen, size_t *maxlen, const char *str) /* (lengths exclude trailing zero) */{ /* Add a string to the buffer, allocating room for it if needed. */ size_t len; assert (str != NULL); /* w_addstr only called from this file */ len = strlen (str); return w_addmem (buffer, actlen, maxlen, str, len);}static intinternal_functionw_addword (wordexp_t *pwordexp, char *word){ /* Add a word to the wordlist */ size_t num_p; char **new_wordv; /* Internally, NULL acts like "". Convert NULLs to "" before * the caller sees them. */ if (word == NULL) { word = strdup (""); if (word == NULL) goto no_space; } num_p = 2 + pwordexp->we_wordc + pwordexp->we_offs; new_wordv = realloc (pwordexp->we_wordv, sizeof (char *) * num_p); if (new_wordv != NULL) { pwordexp->we_wordv = new_wordv; pwordexp->we_wordv[pwordexp->we_offs + pwordexp->we_wordc++] = word; pwordexp->we_wordv[pwordexp->we_offs + pwordexp->we_wordc] = NULL; return 0; }no_space: return WRDE_NOSPACE;}/* The parse_*() functions should leave *offset being the offset in 'words' * to the last character processed. */static intinternal_functionparse_backslash (char **word, size_t *word_length, size_t *max_length, const char *words, size_t *offset){ /* We are poised _at_ a backslash, not in quotes */ switch (words[1 + *offset]) { case 0: /* Backslash is last character of input words */ return WRDE_SYNTAX; case '\n': ++(*offset); break; default: *word = w_addchar (*word, word_length, max_length, words[1 + *offset]); if (*word == NULL) return WRDE_NOSPACE; ++(*offset); break; } return 0;}static intinternal_functionparse_qtd_backslash (char **word, size_t *word_length, size_t *max_length, const char *words, size_t *offset){ /* We are poised _at_ a backslash, inside quotes */ switch (words[1 + *offset]) { case 0: /* Backslash is last character of input words */ return WRDE_SYNTAX; case '\n': ++(*offset); break; case '$': case '`': case '"': case '\\': *word = w_addchar (*word, word_length, max_length, words[1 + *offset]); if (*word == NULL) return WRDE_NOSPACE; ++(*offset); break; default: *word = w_addchar (*word, word_length, max_length, words[*offset]); if (*word != NULL) *word = w_addchar (*word, word_length, max_length, words[1 + *offset]); if (*word == NULL) return WRDE_NOSPACE; ++(*offset); break; } return 0;}static intinternal_functionparse_tilde (char **word, size_t *word_length, size_t *max_length, const char *words, size_t *offset, size_t wordc){ /* We are poised _at_ a tilde */ size_t i; if (*word_length != 0) { if (!((*word)[*word_length - 1] == '=' && wordc == 0)) { if (!((*word)[*word_length - 1] == ':' && strchr (*word, '=') && wordc == 0)) { *word = w_addchar (*word, word_length, max_length, '~'); return *word ? 0 : WRDE_NOSPACE; } } } for (i = 1 + *offset; words[i]; i++) { if (words[i] == ':' || words[i] == '/' || words[i] == ' ' || words[i] == '\t' || words[i] == 0 ) break; if (words[i] == '\\') { *word = w_addchar (*word, word_length, max_length, '~'); return *word ? 0 : WRDE_NOSPACE; } } if (i == 1 + *offset) { /* Tilde appears on its own */ uid_t uid; struct passwd *pwd; char* home; /* POSIX.2 says ~ expands to $HOME and if HOME is unset the results are unspecified. We do a lookup on the uid if HOME is unset. */ home = getenv ("HOME"); if (home != NULL) { *word = w_addstr (*word, word_length, max_length, home); if (*word == NULL) return WRDE_NOSPACE; } else { uid = getuid (); if ((pwd = getpwuid (uid)) != NULL) { *word = w_addstr (*word, word_length, max_length, pwd->pw_dir); if (*word == NULL) return WRDE_NOSPACE; } else { *word = w_addchar (*word, word_length, max_length, '~'); if (*word == NULL) return WRDE_NOSPACE; } } } else { /* Look up user name in database to get home directory */ char *user = strndupa (&words[1 + *offset], i - (1 + *offset)); struct passwd *pwd; if ((pwd = getpwnam (user)) != NULL) *word = w_addstr (*word, word_length, max_length, pwd->pw_dir); else { /* (invalid login name) */ *word = w_addchar (*word, word_length, max_length, '~'); if (*word != NULL) *word = w_addstr (*word, word_length, max_length, user); } *offset = i - 1; } return *word ? 0 : WRDE_NOSPACE;}static intinternal_functiondo_parse_glob (const char *glob_word, char **word, size_t *word_length, size_t *max_length, wordexp_t *pwordexp, const char *ifs, const char *ifs_white){ int error; unsigned int match; glob_t globbuf; error = glob (glob_word, GLOB_NOCHECK, NULL, &globbuf); if (error != 0) { /* We can only run into memory problems. */ assert (error == GLOB_NOSPACE); return WRDE_NOSPACE; } if (ifs && !*ifs) { /* No field splitting allowed. */ assert (globbuf.gl_pathv[0] != NULL); *word = w_addstr (*word, word_length, max_length, globbuf.gl_pathv[0]); for (match = 1; match < globbuf.gl_pathc && *word != NULL; ++match) { *word = w_addchar (*word, word_length, max_length, ' '); if (*word != NULL) *word = w_addstr (*word, word_length, max_length, globbuf.gl_pathv[match]); } globfree (&globbuf); return *word ? 0 : WRDE_NOSPACE; } assert (ifs == NULL || *ifs != '\0'); if (*word != NULL) { free (*word); *word = w_newword (word_length, max_length); } for (match = 0; match < globbuf.gl_pathc; ++match) { char *matching_word = strdup (globbuf.gl_pathv[match]); if (matching_word == NULL || w_addword (pwordexp, matching_word)) { globfree (&globbuf); return WRDE_NOSPACE; } } globfree (&globbuf); return 0;}static intinternal_functionparse_glob (char **word, size_t *word_length, size_t *max_length, const char *words, size_t *offset, int flags, wordexp_t *pwordexp, const char *ifs, const char *ifs_white){ /* We are poised just after a '*', a '[' or a '?'. */ int error = WRDE_NOSPACE; int quoted = 0; /* 1 if singly-quoted, 2 if doubly */ int i; wordexp_t glob_list; /* List of words to glob */ glob_list.we_wordc = 0; glob_list.we_wordv = NULL; glob_list.we_offs = 0; for (; words[*offset] != '\0'; ++*offset) { if ((ifs && strchr (ifs, words[*offset])) || (!ifs && strchr (" \t\n", words[*offset]))) /* Reached IFS */ break; /* Sort out quoting */ if (words[*offset] == '\'') { if (quoted == 0) { quoted = 1; continue; } else if (quoted == 1) { quoted = 0; continue; } } else if (words[*offset] == '"') { if (quoted == 0) { quoted = 2; continue; } else if (quoted == 2) { quoted = 0; continue; } } /* Sort out other special characters */ if (quoted != 1 && words[*offset] == '$') { error = parse_dollars (word, word_length, max_length, words, offset, flags, &glob_list, ifs, ifs_white, quoted == 2); if (error) goto tidy_up; continue; } else if (words[*offset] == '\\') { if (quoted) error = parse_qtd_backslash (word, word_length, max_length, words, offset); else error = parse_backslash (word, word_length, max_length, words, offset); if (error) goto tidy_up; continue; } *word = w_addchar (*word, word_length, max_length, words[*offset]); if (*word == NULL) goto tidy_up; } /* Don't forget to re-parse the character we stopped at. */ --*offset; /* Glob the words */ error = w_addword (&glob_list, *word); *word = w_newword (word_length, max_length); for (i = 0; error == 0 && i < glob_list.we_wordc; i++) error = do_parse_glob (glob_list.we_wordv[i], word, word_length, max_length, pwordexp, ifs, ifs_white); /* Now tidy up */tidy_up: iwordfree (&glob_list); return error;}static intinternal_functionparse_squote (char **word, size_t *word_length, size_t *max_length, const char *words, size_t *offset){ /* We are poised just after a single quote */ for (; words[*offset]; ++(*offset)) { if (words[*offset] != '\'') { *word = w_addchar (*word, word_length, max_length, words[*offset]); if (*word == NULL) return WRDE_NOSPACE; } else return 0; } /* Unterminated string */ return WRDE_SYNTAX;}/* Functions to evaluate an arithmetic expression */static intinternal_functioneval_expr_val (char **expr, long int *result){ int sgn = +1; char *digit; /* Skip white space */ for (digit = *expr; digit && *digit && isspace (*digit); ++digit); switch (*digit) { case '(': /* Scan for closing paren */ for (++digit; **expr && **expr != ')'; ++(*expr)); /* Is there one? */ if (!**expr) return WRDE_SYNTAX;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -