📄 expression.c
字号:
/*LINTLIBRARY*//* expression.c This code provides Borne Shell-like expression expansion. Copyright (C) 1997-1999 Richard Gooch This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Richard Gooch may be reached by email at karma-request@atnf.csiro.au The postal address is: Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.*//* This file contains shell-like expression expansion routines. Written by Richard Gooch 9-OCT-1997 Updated by Richard Gooch 4-DEC-1997: Added support for "${var:-word}" expressions. Updated by Richard Gooch 17-SEP-1998: Took account of some CONST declarations in <r> package. Last updated by Richard Gooch 8-JUN-1999: Changed <st_expr_expand> to support getting variable values from supplied function.*/#include <stdio.h>#include <ctype.h>#include <string.h>#include <stdlib.h>#include <unistd.h>#include <errno.h>#include <pwd.h>#include <karma.h>#ifdef __KARMA__# include <karma_st.h># include <karma_r.h>#endif#define BUF_SIZE 16384#ifndef __KARMA__# define r_getenv getenv#endif/* Private functions */STATIC_FUNCTION (CONST char *expand_variable, (char *buffer, unsigned int length, unsigned int *out_pos, CONST char *input, CONST char *(*func) (CONST char *variable, void *info), void *info, FILE *errfp) );STATIC_FUNCTION (CONST char *get_variable, (CONST char *variable, CONST char *(*func) (CONST char *variable, void *info), void *info) );/* Public functions follow *//*EXPERIMENTAL_FUNCTION*/flag st_expr_expand (char *output, unsigned int length, CONST char *input, CONST char *(*get_variable) (CONST char *variable, void *info), void *info, FILE *errfp)/* [SUMMARY] Expand an expression using Borne Shell-like unquoted rules. <output> The output expanded expression is written here. <length> The size of the output buffer. <input> The input expression. This may equal <<output>>. <get_variable> A function which will be used to get variable values. If this returns NULL, the environment is searched instead. If this is NULL, only the environment is searched. <info> An arbitrary pointer passed to <<get_variable>>. <errfp> Diagnostic messages are written here. If this is NULL the global stderr is used instead. [RETURNS] TRUE on success, else FALSE.*/{ char ch; unsigned int len; unsigned int out_pos = 0; CONST char *env; CONST char *ptr; struct passwd *pwent; char buffer[BUF_SIZE], tmp[STRING_LENGTH]; static char function_name[] = "st_expr_expand"; if (errfp == NULL) errfp = stderr; if (length > BUF_SIZE) length = BUF_SIZE; for (; TRUE; ++input) { switch (ch = *input) { case '$': /* Variable expansion */ input = expand_variable (buffer, length, &out_pos, ++input, get_variable, info, errfp); if (input == NULL) return (FALSE); break; case '~': /* Home directory expansion */ ch = input[1]; if ( isspace (ch) || (ch == '/') || (ch == '\0') ) { /* User's own home directory: leave separator for next time */ if ( ( env = r_getenv ("HOME") ) == NULL ) { fprintf (errfp, "%s: environment variable: \"HOME\" not found\n", function_name); return (FALSE); } len = strlen (env); if (len + out_pos >= length) { fprintf (errfp, "%s: output buffer too small\n", function_name); return (FALSE); } memcpy (buffer + out_pos, env, len + 1); out_pos += len; continue; } /* Someone else's home directory */ for (ptr = ++input; !isspace (ch) && (ch != '/') && (ch != '\0'); ch = *++ptr); len = ptr - input; if (len >= sizeof tmp) { fprintf (errfp, "%s: username buffer too small\n", function_name); return (FALSE); } memcpy (tmp, input, len); tmp[len] = '\0'; input = ptr - 1; if ( ( pwent = getpwnam (tmp) ) == NULL ) { fprintf (errfp, "%s: error getting pwent for user: \"%s\"\n", function_name, tmp); return (FALSE); } len = strlen (pwent->pw_dir); if (len + out_pos >= length) { fprintf (errfp, "%s: output buffer too small\n",function_name); return (FALSE); } memcpy (buffer + out_pos, pwent->pw_dir, len + 1); out_pos += len; break; case '\0': default: if (out_pos >= length) { fprintf (errfp, "%s: output buffer too small\n",function_name); return (FALSE); } buffer[out_pos++] = ch; if (ch == '\0') { memcpy (output, buffer, out_pos); return (TRUE); } break; } } return (FALSE);} /* End Function st_expr_expand *//* Private functions follow */static CONST char *expand_variable (char *buffer, unsigned int length, unsigned int *out_pos, CONST char *input, CONST char *(*func) (CONST char *variable, void *info), void *info, FILE *errfp)/* [SUMMARY] Expand a variable. <buffer> The buffer to write to. <length> The length of the output buffer. <out_pos> The current output position. This is updated. <input> A pointer to the input character pointer. <func> A function which will be used to get variable values. If this returns NULL, the environment is searched instead. If this is NULL, only the environment is searched. <info> An arbitrary pointer passed to <<func>>. <errfp> Diagnostic messages are written here. [RETURNS] A pointer to the end of this subexpression on success, else NULL.*/{ char ch; int len; unsigned int open_braces; CONST char *env, *ptr; char tmp[STRING_LENGTH]; static char function_name[] = "_st_expr_expand_variable"; ch = input[0]; if (ch == '$') { /* Special case for "$$": PID */ sprintf ( tmp, "%d", (int) getpid () ); len = strlen (tmp); if (len + *out_pos >= length) { fprintf (errfp, "%s: output buffer too small\n", function_name); return (NULL); } memcpy (buffer + *out_pos, tmp, len + 1); *out_pos += len; return (input); } /* Ordinary variable expansion, possibly in braces */ if (ch != '{') { /* Simple variable expansion */ for (ptr = input; isalnum (ch) || (ch == '_') || (ch == ':'); ch = *++ptr); len = ptr - input; if (len >= sizeof tmp) { fprintf (errfp, "%s: temporary buffer too small\n", function_name); return (NULL); } memcpy (tmp, input, len); tmp[len] = '\0'; input = ptr - 1; if ( ( env = get_variable (tmp, func, info) ) == NULL ) { fprintf (errfp, "%s: variable: \"%s\" not found\n", function_name, tmp); return (NULL); } len = strlen (env); if (len + *out_pos >= length) { fprintf (errfp, "%s: output buffer too small\n", function_name); return (NULL); } memcpy (buffer + *out_pos, env, len + 1); *out_pos += len; return (input); } /* Variable in braces: check for ':' tricks */ ch = *++input; for (ptr = input; isalnum (ch) || (ch == '_'); ch = *++ptr); if (ch == '}') { /* Must be simple variable expansion with "${var}" */ len = ptr - input; if (len >= sizeof tmp) { fprintf (errfp, "%s: temporary buffer too small\n", function_name); return (NULL); } memcpy (tmp, input, len); tmp[len] = '\0'; ptr = expand_variable (buffer, length, out_pos, tmp, func, info,errfp); if (ptr == NULL) return (NULL); return (input + len); } if (ch != ':') { fprintf (errfp, "%s: illegal character: '%c' in variable name\n", function_name, ch); return (NULL); } if (ptr[1] != '-') { fprintf (errfp, "%s: illegal character: '%c' in variable name\n", function_name, ptr[1]); return (NULL); } /* It's that handy "${var:-word}" expression. Check if var is defined */ len = ptr - input; if (len >= sizeof tmp) { fprintf (errfp, "%s: temporary buffer too small\n", function_name); return (NULL); } memcpy (tmp, input, len); tmp[len] = '\0'; /* Move input pointer to ':' */ input = ptr; /* First skip to closing brace, taking note of nested expressions */ ptr += 2; ch = ptr[0]; for (open_braces = 1; open_braces > 0; ch = *++ptr) { switch (ch) { case '{': ++open_braces; break; case '}': --open_braces; break; case '\0': fprintf (errfp, "%s: closing brace not found in: \"%s\"\n", function_name, input); return (NULL); /*break;*/ default: break; } } --ptr; /* At this point ptr should point to closing brace of "${var:-word}" */ if ( ( env = get_variable (tmp, func, info) ) != NULL ) { /* Found environment variable, so skip the input to the closing brace and return the variable */ input = ptr; len = strlen (env); if (len + *out_pos >= length) { fprintf (errfp, "%s: output buffer too small\n", function_name); return (NULL); } memcpy (buffer + *out_pos, env, len + 1); *out_pos += len; return (input); } /* Environment variable was not found, so process word. Advance input pointer to start of word in "${var:-word}" */ input += 2; len = ptr - input; if (len >= sizeof tmp) { fprintf (errfp, "%s: temporary buffer too small for word\n", function_name); return (NULL); } memcpy (tmp, input, len); tmp[len] = '\0'; input = ptr; if ( !st_expr_expand (tmp, STRING_LENGTH, tmp, func, info, errfp) ) return (NULL); len = strlen (tmp); if (len + *out_pos >= length) { fprintf (errfp, "%s: output buffer too small\n", function_name); return (NULL); } memcpy (buffer + *out_pos, tmp, len + 1); *out_pos += len; return (input);} /* End Function expand_variable */static CONST char *get_variable (CONST char *variable, CONST char *(*func) (CONST char *variable, void *info), void *info)/* [SUMMARY] Get a variable from the environment or . <variable> The variable name. <func> A function which will be used to get the variable. If this returns NULL, the environment is searched instead. If this is NULL, only the environment is searched. [RETURNS] The value of the variable on success, else NULL.*/{ CONST char *value; if (func != NULL) { value = (*func) (variable, info); if (value != NULL) return (value); } return r_getenv (variable);} /* End Function get_variable */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -