/* * CDE - Common Desktop Environment * * Copyright (c) 1993-2012, The Open Group. All rights reserved. * * These libraries and programs are free software; you can * redistribute them and/or modify them under the terms of the GNU * Lesser General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * These libraries and programs are distributed in the hope that * they 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 these libraries and programs; if not, write * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth * Floor, Boston, MA 02110-1301 USA */ /******************************<+>************************************* ********************************************************************** ** ** File: WmParse.c ** ** Project: HP/Motif Workspace Manager (dtwm) ** ** Description: ** ----------- ** This file contains the generic parsing routines ** ** ********************************************************************* ** ** (c) Copyright 1987, 1988, 1989, 1990, 1991 HEWLETT-PACKARD COMPANY ** ALL RIGHTS RESERVED ** ********************************************************************** ********************************************************************** ** ** ********************************************************************** ******************************<+>*************************************/ /* ANSI C definitions, This should be the first thing in WmGlobal.h */ #ifdef __STDC__ #define Const const #else #define Const /**/ #endif /* * Included Files: */ #include #include #include "WmGlobal.h" #include "WmParse.h" #include "WmParseP.h" #include #include /* * Internal routines */ static DtWmpParseBuf * _DtWmpIncBuf ( DtWmpParseBuf *pWmPB); #ifndef MAXLINE #define MAXLINE (MAXWMPATH+1) #endif #define MAX_QUOTE_DEPTH 10 /* * This flags non-OSF code in those sections that were lifted * from mwm. */ #define PARSE_LIB /* * Defines used to maintain code similarity between OSF/mwm source * routines and these routines. */ #define cfileP ((pWmPB)->pFile) #define linec ((pWmPB)->lineNumber) #define line ((pWmPB)->pchLine) #define parseP ((pWmPB)->pchNext) #define ScanWhitespace(s) (_DtWmParseSkipWhitespaceC(s)) #define PeekAhead(s,l) (_DtWmParsePeekAhead(s,l)) /*************************************<->************************************* * * _DtWmParseSkipWhitespace(pWmPB) * * * Description: * ----------- * Scan the current string, skipping over all white space characters. * * * Inputs: * ------ * pWmPB = ptr to parse buffer * * * Outputs: * ------- * pWmPB = parse buffer modified; current line ptr may be moved. * * * Comments: * -------- * Assumes there's a current line in the parse buffer * *************************************<->***********************************/ void _DtWmParseSkipWhitespace(DtWmpParseBuf *pWmPB) { _DtWmParseSkipWhitespaceC (&(pWmPB->pchNext)); } /* END OF FUNCTION _DtWmParseSkipWhitespace */ /*************************************<->************************************* * * _DtWmParseNextToken (pWmPB) * * * Description: * ----------- * Returns the next quoted or whitespace-terminated nonquoted string in the * current line buffer. * * * Inputs: * ------ * pWmPB = ptr to parse buffer * * * Outputs: * ------- * Return = ptr to null terminated string. * pWmPB = current line modified internally. * * * Comments: * -------- * May alter the line buffer contents. * Handles quoted strings and characters, removing trailing whitespace from * quoted strings. * Returns NULL string if the line is empty or is a comment. * Does not use session manager style algorithm for dealing with * quoted strings. * *************************************<->***********************************/ unsigned char * _DtWmParseNextToken ( DtWmpParseBuf *pWmPB ) { return (_DtWmParseNextTokenC (&(pWmPB->pchNext), False)); } /*************************************<->************************************* * * _DtWmParseNextTokenExpand (pWmPB) * * * Description: * ----------- * Returns the next quoted or whitespace-terminated nonquoted string in the * current line buffer. Environment variables found in the are expanded. * Characters quoted by '\' are passed through unaffected with the * quoting '\' removed. * * * Inputs: * ------ * pWmPB = ptr to parse buffer * * * Outputs: * ------- * Return = ptr to null terminated string. * Free this string with XtFree(). * pWmPB = current line modified internally. * * * Comments: * -------- * May alter the line buffer contents. * Handles quoted strings and characters, removing trailing whitespace from * quoted strings. * Returns NULL string if the line is empty or is a comment. * *************************************<->***********************************/ unsigned char * _DtWmParseNextTokenExpand ( DtWmpParseBuf *pWmPB ) { unsigned char *pch; unsigned char *pchReturn = NULL; /* isolate the next token */ pch = _DtWmParseNextTokenC (&(pWmPB->pchNext), False); /* expand environment variables, a copy of the string is returned */ pchReturn = _DtWmParseExpandEnvironmentVariables (pch, NULL); /* * If a token was found, but no copy returned, there were no * environment variables. This routine needs to return a copy, * so make one now. */ if (pch && !pchReturn) pchReturn = (unsigned char *) XtNewString ((String) pch); return (pchReturn); } /*************************************<->************************************* * * _DtWmParseBackUp (pWmPB, pchTok) * * * Description: * ----------- * Backs up to the previous token (the one before pchTok) * * * Inputs: * ------ * pWmPB = ptr to parse buffer * pchTok = ptr to a token in the parse buffer * * * Outputs: * ------- * Returns = ptr to prev token * * * Comments: * -------- * Operates on the line buffer in the pWmPB structure. Backs up * the next pointer and writes a space over the interpolated * NULL (if any). * *************************************<->***********************************/ unsigned char * _DtWmParseBackUp ( DtWmpParseBuf *pWmPB, unsigned char *pchTok ) { if ((pchTok > pWmPB->pchLine) && (pchTok < (pWmPB->pchLine + pWmPB->cLineSize))) { unsigned char *pch; unsigned char *pchLast; int chlen; pch = pchLast = pWmPB->pchLine; /* * Search from beginning (because of multibyte chars) to * find the token before the string we're interested in. */ while ((pch < pchTok)) { chlen = mblen ((char *)pch, MB_CUR_MAX); if (*pch == '\0') { pch++; if (pch == pchTok) { /* * Found the NULL preceding the string passed in! * Replace it with a blank and return the previous * token (pointed to by pchLast). */ *(pch - 1) = DTWM_CHAR_SPACE; break; } else { /* * Remember the beginning of this token. */ pchLast = pch; } } else if (chlen < 1) { break; } else { pch += chlen; } } pWmPB->pchNext = pchLast; } return (pWmPB->pchNext); } /*************************************<->************************************* * * _DtWmParseSkipWhitespaceC(linePP) * * * Description: * ----------- * Scan the string, skipping over all white space characters. * * * Inputs: * ------ * linePP = nonNULL pointer to current line buffer pointer * * * Outputs: * ------- * linePP = nonNULL pointer to revised line buffer pointer * * * Comments: * -------- * Assumes linePP is nonNULL * *************************************<->***********************************/ void _DtWmParseSkipWhitespaceC(unsigned char **linePP) { while (*linePP && (mblen ((char *)*linePP, MB_CUR_MAX) == 1) && isspace (**linePP)) { (*linePP)++; } } /* END OF FUNCTION _DtWmParseSkipWhitespaceC */ /*************************************<->************************************* * * _DtWmParseNextTokenC (linePP, SmBehavior) * * * Description: * ----------- * Returns the next quoted or whitespace-terminated nonquoted string in the * line buffer. * Additional functionality added to GetString in that anything in a * quoted string is considered sacred and nothing will be stripped from * the middle of a quoted string. * * * Inputs: * ------ * linePP = pointer to current line buffer pointer. * SmBehavior = flag that enables parsing session manager hints if True. * If False, this behaves as the normal OSF mwm GetString * routine. * * * Outputs: * ------- * linePP = pointer to revised line buffer pointer. * Return = string * * * Comments: * -------- * May alter the line buffer contents. * Handles quoted strings and characters, removing trailing whitespace from * quoted strings. * Returns NULL string if the line is empty or is a comment. * Code stolen from dtmwm. * *************************************<->***********************************/ unsigned char * _DtWmParseNextTokenC ( unsigned char **linePP, Boolean SmBehavior ) { /*********************************************************************** * * The following code is duplicated from WmResParse.c (GetStringC) * GetStringC is the HP DT version of GetString. * * It works here through the magic of #defines. * ***********************************************************************/ unsigned char *lineP = *linePP; unsigned char *endP; unsigned char *curP; unsigned char *lnwsP; unsigned int level = 0, checkLev, i, quoteLevel[MAX_QUOTE_DEPTH]; int chlen; /* get rid of leading white space */ ScanWhitespace (&lineP); /* * Return NULL if line is empty, whitespace, or begins with a comment. */ if ( *lineP == '\0' || ((chlen = mblen ((char *)lineP, MB_CUR_MAX)) < 1) || ((chlen == 1) && ((*lineP == '!') || ((!SmBehavior) && (*lineP == '#')))) ) { *linePP = lineP; return (NULL); } if ((chlen == 1) && (*lineP == '"')) /* Quoted string */ { quoteLevel[level] = 1; /* * Start beyond double quote and find the end of the quoted string. * '\' quotes the next character. * Otherwise, matching double quote or NULL terminates the string. * * We use lnwsP to point to the last non-whitespace character in the * quoted string. When we have found the end of the quoted string, * increment lnwsP and if lnwsP < endP, write NULL into *lnwsP. * This removes any trailing whitespace without overwriting the * matching quote, needed later. If the quoted string was all * whitespace, then this will write a NULL at the beginning of the * string that will be returned -- OK. */ lnwsP = lineP++; /* lnwsP points to first '"' */ curP = endP = lineP; /* other pointers point beyond */ while ((*endP = *curP) && ((chlen = mblen ((char *)curP, MB_CUR_MAX)) > 0) && ((chlen > 1) || (*curP != '"'))) /* Haven't found matching quote yet. * First byte of next character has been copied to endP. */ { curP++; if ((chlen == 1) && (*endP == '\\') && ((chlen = mblen ((char *)curP, MB_CUR_MAX)) > 0)) /* character quote: * copy first byte of quoted nonNULL character down. * point curP to next byte */ { if (SmBehavior) { /* * Check to see if this is a quoted quote - if it is * strip off a level - if not - it's sacred leave it alone */ checkLev = PeekAhead((curP - 1), quoteLevel[level]); if(checkLev > 0) { if(quoteLevel[level] >= checkLev) { if (level > 0) level--; } else if (level < MAX_QUOTE_DEPTH) { level++; quoteLevel[level] = checkLev; } for(i = 0;i < (checkLev - 2);i++) { *endP++ = *curP++;curP++; } *endP = *curP++; } } else { *endP = *curP++; } } if (chlen == 1) /* Singlebyte character: character copy finished. */ { if (isspace (*endP)) /* whitespace character: leave lnwsP unchanged. */ { endP++; } else /* non-whitespace character: point lnwsP to it. */ { lnwsP = endP++; } } else if (chlen > 1) /* Multibyte (nonwhitespace) character: point lnwsP to it. * Finish character byte copy. */ { lnwsP = endP++; while (--chlen) { *endP++ = *curP++; lnwsP++; } } } /* * Found matching quote or NULL. * NULL out any trailing whitespace. */ lnwsP++; if (lnwsP < endP) { *lnwsP = '\0'; } } else /* Unquoted string */ { /* * Find the end of the nonquoted string. * '\' quotes the next character. * Otherwise, whitespace, NULL, or '#' terminates the string. */ curP = endP = lineP; while ((*endP = *curP) && ((chlen = mblen ((char *)curP, MB_CUR_MAX)) > 0) && ((chlen > 1) || (!isspace (*curP) && (SmBehavior || (*curP != '#'))))) /* Haven't found whitespace or '#' yet. * First byte of next character has been copied to endP. */ { curP++; if ((chlen == 1) && (*endP == '\\') && ((chlen = mblen ((char *)curP, MB_CUR_MAX)) > 0)) /* character quote: * copy first byte of quoted nonNULL character down. * point curP to next byte */ { *endP = *curP++; } endP++; if (chlen > 1) /* Multibyte character: finish character copy. */ { while (--chlen) { *endP++ = *curP++; } } } } /* * Three cases for *endP: * '#' --> write NULL over # and point to NULL * whitespace or * matching quote -> write NULL over char and point beyond * NULL -> point to NULL */ if (!SmBehavior && (*endP == '#')) { *endP = '\0'; /* write NULL over '#' */ *linePP = endP; /* point to NULL */ } else if (*endP != '\0') { *endP = '\0'; /* write NULL over terminator */ *linePP = ++curP; /* point beyond terminator */ } else { *linePP = endP; } return ((unsigned char *)lineP); } /* END OF FUNCTION _DtWmParseNextTokenC */ /*************************************<->************************************* * * (DtWmParseBuf *) _DtWmParseNewBuf (void) * * * Description: * ----------- * Allocates a new parse record for parsing. * * Inputs: * ------ * none * * * Outputs: * ------- * Return = ptr to parse buffer record, NULL if memory allocation * error. * * * Comments: * -------- * Call this first before using the other DtWmp routines that require * a parse buffer. Treat this as an opaque type; use the provided * routines to create, access, and destroy this structure. * *************************************<->***********************************/ DtWmpParseBuf * _DtWmParseNewBuf ( void ) { DtWmpParseBuf *pWmPB; pWmPB = (DtWmpParseBuf *) XtMalloc (sizeof (DtWmpParseBuf)); if (pWmPB) { pWmPB->pchLine = (unsigned char *) XtMalloc (MAXLINE+1); if (!pWmPB->pchLine) { XtFree ((char *)pWmPB); pWmPB = NULL; } } if (pWmPB) { pWmPB->lineNumber = 0; pWmPB->pchNext = pWmPB->pchLine; pWmPB->cLineSize = MAXLINE+1; pWmPB->pFile = NULL; *(pWmPB->pchLine) = '\0'; } return (pWmPB); } /* END OF FUNCTION _DtWmParseNewBuf */ /*************************************<->************************************* * * (DtWmParseBuf *) _DtWmpIncBuf (pWmPB) * * * Description: * ----------- * Increases the size of the line buffer in the parse buffer * * Inputs: * ------ * pWmPB = pointer to a parse buffer * * * Outputs: * ------- * Return = ptr to parse buffer record, NULL if memory allocation * error. * * * Comments: * -------- * *************************************<->***********************************/ static DtWmpParseBuf * _DtWmpIncBuf ( DtWmpParseBuf *pWmPB) { if (pWmPB) { int ix; if (pWmPB->pFile) { /* save index into old string */ ix = pWmPB->pchNext - pWmPB->pchLine; } pWmPB->pchLine = (unsigned char *) XtRealloc ((char *)pWmPB->pchLine, (pWmPB->cLineSize + MAXLINE)); if (pWmPB->pchLine) { pWmPB->cLineSize += MAXLINE; if (pWmPB->pFile) { /* restore index into new string */ pWmPB->pchNext = pWmPB->pchLine + ix; } } } return (pWmPB); } /* END OF FUNCTION _DtWmpIncBuf */ /*************************************<->************************************* * * _DtWmParseDestroyBuf (pWmPB) * * * Description: * ----------- * Destroys a parse buffer record, freeing any allocated memory. * * * Inputs: * ------ * pWmPB = ptr to previously allocated parse buffer * * * Outputs: * ------- * none * * * Comments: * -------- * Destroys parse buffers allocated by _DtWmParseNewBuf. * *************************************<->***********************************/ void _DtWmParseDestroyBuf ( DtWmpParseBuf *pWmPB ) { if (pWmPB) { if (pWmPB->pchLine) { XtFree ((char *) pWmPB->pchLine); } XtFree ((char *) pWmPB); } } /* END OF FUNCTION _DtWmParseDestroyBuf */ /*************************************<->************************************* * * (unsigned char *) _DtWmParseSetLine (pWmPB, pch) * * * Description: * ----------- * Sets a line into the parse buffer structure. This is used in cases * where parsing of an embedded string, usually a default, is done * instead of parsing out of a file. * * * Inputs: * ------ * pWmPB = previously allocated parse buffer * pch = ptr to unsigned char string (zero terminated) * * Outputs: * ------- * Return = pch * * * Comments: * -------- * This resets any previous setting of the file pointer. EOF wil be * returned when the string pointed to by pch is exhausted. * * Resets line number count. * *************************************<->***********************************/ void _DtWmParseSetLine ( DtWmpParseBuf *pWmPB, unsigned char *pch ) { if (pWmPB) { pWmPB->pchLine = pch; pWmPB->pchNext = pWmPB->pchLine; pWmPB->pFile = NULL; pWmPB->lineNumber = 0; } } /* END OF FUNCTION _DtWmParseSetLine */ /*************************************<->************************************* * * (FILE *) _DtWmParseSetFile (pWmPB, pFile) * * * Description: * ----------- * Sets the file pointer in a parse buffer. This is used when parsing * from a file is required. * * * Inputs: * ------ * pWmPB = pointer to a parse buffer * pFile = pointer to an opened FILE * * Outputs: * ------- * Return = pFile * * * Comments: * -------- * You fopen the file first, then pass in the FILE * returned to this * routine. * * Resets line number count. * *************************************<->***********************************/ void _DtWmParseSetFile ( DtWmpParseBuf *pWmPB, FILE *pFile ) { if (pWmPB) { pWmPB->pchLine[0] = '\0'; pWmPB->pchNext = NULL; pWmPB->pFile = pFile; pWmPB->lineNumber = 0; } } /* END OF FUNCTION _DtWmParseSetFile */ /*************************************<->************************************* * * (unsigned char *) _DtWmParseNextLine ( pWmPB ) * * * Description: * ----------- * Returns a pointer to the next line to parse. * * * Inputs: * ------ * pWmPB = pointer to a parse buffer * * * Outputs: * ------- * Return = pointer to next line to parse or NULL on EOF. * * * Comments: * -------- * * *************************************<->***********************************/ unsigned char * _DtWmParseNextLine ( DtWmpParseBuf *pWmPB ) { /*********************************************************************** * * The following code is duplicated from WmResParse.c (GetNextLine) * It works here through the magic of #defines. * ***********************************************************************/ unsigned char *string; int len; int chlen; wchar_t last; wchar_t wdelim; char delim; int lastlen; if (cfileP != NULL) /* read fopened file */ { if ((string = (unsigned char *) fgets ((char *)line, MAXLINE, cfileP)) != NULL) { #ifdef PARSE_LIB if (strlen((char *)string) > (size_t)pWmPB->cLineSize) { /* * Bump size of destination buffer */ pWmPB->cLineSize = 1 + strlen((char *)string); pWmPB->pchLine = (unsigned char *) XtRealloc ((char *)pWmPB->pchLine, (pWmPB->cLineSize)); } #endif /* PARSE_LIB */ lastlen = 0; while (*string && ((len = mblen((char *)string, MB_CUR_MAX)) > 0)) { mbtowc(&last, (char *)string, MB_CUR_MAX); lastlen = len; string += len; } delim = '\\'; mbtowc(&wdelim, &delim, MB_CUR_MAX); if (lastlen == 1 && last == wdelim) { do { if (!fgets((char *)string, MAXLINE - (string - line), cfileP)) break; lastlen = 0; while (*string && ((len = mblen((char *)string, MB_CUR_MAX)) > 0)) { mbtowc(&last, (char *)string, MB_CUR_MAX); lastlen = len; string += len; } linec++; } while (lastlen == 1 && last == wdelim); } string = line; } } else if ((parseP != NULL) && (*parseP != '\0')) /* read parse string */ { #ifdef PARSE_LIB if (strlen((char *)parseP) > (size_t)pWmPB->cLineSize) { /* * Bump size of destination buffer */ pWmPB->cLineSize = 1 + strlen((char *)parseP); pWmPB->pchLine = (unsigned char *) XtRealloc ((char *)pWmPB->pchLine, (pWmPB->cLineSize)); } #endif /* PARSE_LIB */ string = line; while ((*parseP != '\0') && ((chlen = mblen ((char *)parseP, MB_CUR_MAX)) != 0) && (*parseP != '\n')) /* copy all but end-of-line and newlines to line buffer */ { if (chlen == -1) parseP++; else { while (chlen--) { *(string++) = *(parseP++); } } } *string = '\0'; if (*parseP == '\n') { parseP++; } } else { string = NULL; } linec++; #ifdef PARSE_LIB if (cfileP) { /* update pchNext to get next line */ pWmPB->pchNext = string; } #endif /* PARSE_LIB */ return (string); } /* END OF FUNCTION _DtWmParseNextLine */ /*************************************<->************************************* * * (unsigned char *) _DtWmParseCurrentChar (pWmPB) * * * Description: * ----------- * Returns a pointer to the rest of the current line. * * * Inputs: * ------ * pWmPB = pointer to a parse buffer * * * Outputs: * ------- * Return = pointer to the rest of the current line * * * Comments: * -------- * Useful in cases where you want to look at a char before getting the * next token or if you want to treat the rest of the line as a * single token. * *************************************<->***********************************/ unsigned char * _DtWmParseCurrentChar ( DtWmpParseBuf *pWmPB ) { return (pWmPB ? pWmPB->pchNext : (unsigned char *)NULL); } /* END OF FUNCTION _DtWmParseCurrentChar */ /*************************************<->************************************* * * (unsigned char *) _DtWmParseNextChar (pWmPB) * * * Description: * ----------- * Advances the pointer to the next char and returns a pointer * to the new current char. * * * Inputs: * ------ * pWmPB = pointer to a parse buffer * * * Outputs: * ------- * Return = pointer to the rest of the current line * * * Comments: * -------- * *************************************<->***********************************/ unsigned char * _DtWmParseNextChar ( DtWmpParseBuf *pWmPB ) { unsigned char *pch = NULL; int chlen; if (pWmPB && pWmPB->pchNext && (chlen = mblen((char *)pWmPB->pchNext, MB_CUR_MAX) > 0)) { pch = (pWmPB->pchNext += chlen); } return (pch); } /*************************************<->************************************* * * (int) _DtWmParseLineNumber (pWmPB) * * * Description: * ----------- * Returns the number of the current line of what's being parsed. * * * Inputs: * ------ * pWmPB = ptr to parse buffer * * * Outputs: * ------- * Return = number of current line * * * Comments: * -------- * Used for error reporting. * * The line number is computed by counting '\n' characters. * *************************************<->***********************************/ int _DtWmParseLineNumber ( DtWmpParseBuf *pWmPB ) { return (pWmPB ? pWmPB->lineNumber : 0); } /* END OF FUNCTION _DtWmParseLineNumber */ /*************************************<->************************************* * * _DtWmParseToLower (string) * * * Description: * ----------- * Lower all characters in a string. * * * Inputs: * ------ * string = NULL-terminated character string or NULL * * * Outputs: * ------- * string = NULL-terminated lower case character string or NULL * * * Comments: * -------- * Can handle multi-byte characters * *************************************<->***********************************/ void _DtWmParseToLower (char *string) { char *pch = string; int chlen; while ((chlen = mblen (pch, MB_CUR_MAX)) > 0) { if ((chlen == 1) && (isupper (*pch))) { *pch = tolower(*pch); } pch += chlen; } } /* END OF FUNCTION _DtWmParseToLower */ /*************************************<->************************************* * * _DtWmParsePeekAhead (currentChar, currentLev) * * * Description: * ----------- * Returns a new level value if this is a new nesting level of quoted string * Otherwise it returns a zero * * * Inputs: * ------ * currentChar = current position in the string * currentLev = current level of nesting * * * Outputs: * ------- * Returns either a new level of nesting or zero if the character is copied in * * * Comments: * -------- * *************************************<->***********************************/ unsigned int _DtWmParsePeekAhead(unsigned char *currentChar, unsigned int currentLev) { Boolean done = False; unsigned int tmpLev = 1; unsigned int chlen; while (((chlen = mblen ((char *)currentChar, MB_CUR_MAX)) > 0) && (chlen == 1) && ((*currentChar == '"') || (*currentChar == '\\')) && (done == False)) { currentChar++; if(((chlen = mblen ((char *)currentChar, MB_CUR_MAX)) > 0) && (chlen == 1) && ((*currentChar == '"') || (*currentChar == '\\'))) { tmpLev++; if(*currentChar == '"') { done = True; } else { currentChar++; } } } /* * Figure out if this is truly a new level of nesting - else ignore it * This section probably could do some error checking and return -1 * If so, change type of routine from unsigned int to int */ if(done == True) { return(tmpLev); } else { return(0); } } /* END OF FUNCTION _DtWmParsePeekAhead */ /*************************************<->************************************* * * (unsigned char *) _DtWmParseFilenameExpand (pchFilename) * * * Description: * ----------- * Returns a copy of a file name with environment variables * expanded. * * * Inputs: * ------ * pchFilename = ptr to a zero terminated character string (filename) * * * Outputs: * ------- * Return = ptr to a new file name with environment variables * expanded. * * * Comments: * -------- * The passed in string is temporarily modified inside here. * * Free the returned string with XtFree(). * * Returns NULL on a memory allocation error. * * Environment variables that can't be expanded are removed from * the returned copy. * * If no environment variables, you get a copy of the string back. * *************************************<->***********************************/ unsigned char * _DtWmParseFilenameExpand ( unsigned char *pchFilename ) { unsigned char *pchN, *pchNew, *pchO; unsigned char *pchEnv, *pchEnv0, *pchEnv1; unsigned char chSave; int len, n, nx, ix; unsigned char pchBrk[] = { DTWM_CHAR_ENVIRONMENT, DTWM_CHAR_DIRECTORY, '\0' }; len = strlen ((char *)pchFilename); pchNew = (unsigned char *) XtMalloc (1+len); pchO = pchFilename; chSave = '\0'; ix = 0; while (pchNew && pchO && *pchO) { /* find next environment variable */ pchEnv0 = (unsigned char *) strchr ((char *)pchO, (int) DTWM_CHAR_ENVIRONMENT); if (pchEnv0) { /* length to this point */ n = pchEnv0 - pchO; /* copy up to environment character */ if (n) { memcpy (&pchNew[ix], pchO, n); ix += n; } /* skip environment character */ pchEnv0++; /* end of variable is at one of: * start of next variable, * start of next directory, * end of string */ pchEnv1 = (unsigned char *) strpbrk ((char *)pchEnv0, (char *)pchBrk); if (pchEnv1) { /* next string starts after this one */ pchO = pchEnv1; n = pchEnv1 - pchEnv0 + 1; /* replace this char with NULL for now */ chSave = *pchEnv1; *pchEnv1 = '\0'; } else { /* This environment variable is the last thing on * the line. Signal all done. */ n = strlen ((char *) pchO); pchO += n; } pchEnv = (unsigned char *) getenv ((char *)pchEnv0); if (pchEnv) { nx = strlen ((char *) pchEnv); if (nx > n) { len += nx - n; pchNew = (unsigned char *) XtRealloc ((char *)pchNew, 1+len); } if (pchNew) { memcpy (&pchNew[ix], pchEnv, nx); ix += nx; } else { continue; } } if (chSave) { *pchO = chSave; chSave = '\0'; } /* keep a kosher string */ pchNew[ix] = '\0'; } else { /* copy the rest of the string */ n = strlen ((char *) pchO); memcpy (&pchNew[ix], pchO, n); pchO += n; /* remember the NULL! (a famous battle cry) */ pchNew[ix + n] = '\0'; } } return (pchNew); } /* END OF FUNCTION _DtWmParseFilenameExpand */ /*************************************<->************************************* * * unsigned char * _DtWmParseExpandEnvironmentVariables (pch, pchBrk) * * * Description: * ----------- * Expands environment variables in a string. * * * Inputs: * ------ * pch = ptr to a zero terminated character string * pchBrk = array of "break" characters (see strpbrk()). * defaults are used if this is NULL. * * Outputs: * ------- * Return = string with expanded environment variables. (free with XtFree) * NULL string if no environment variables or backslashes * found in the string passed in. * * * Comments: * -------- * Free returned string with XtFree() * * Environment variables that can't be expanded are removed from * the returned copy. * * Default delimiter set is [Space], [Tab], '$', [Newline], '\', '/'. * * Variables of form $(..) and ${..} supported. * * A backslash '\' in front of any character quotes it. The backslash * is removed in the returned string. A literal backslash needs to be * quoted with a backslash. * *************************************<->***********************************/ unsigned char * _DtWmParseExpandEnvironmentVariables ( unsigned char *pch, unsigned char *pchBrk ) { int chlen; unsigned char *pchStart; unsigned char chSave; unsigned char *pchEnvStart; unsigned char *pchEnvValue; unsigned char *pchReturn = NULL; unsigned char *pchNext; unsigned char *pchBreak; Boolean bEatBreak; Boolean bAlreadyAdvanced; int lenOriginal; int lenNonEnv; int lenEnvVar; int lenEnvValue; int lenReturn; int lenSave; static unsigned char pchDefaultBrk[] = { DTWM_CHAR_ENVIRONMENT, DTWM_CHAR_SPACE, DTWM_CHAR_TAB, DTWM_CHAR_NEW_LINE, DTWM_CHAR_BACKSLASH, DTWM_CHAR_DIRECTORY, '\0' }; unsigned char pchParenBrk[] = { DTWM_CHAR_R_PAREN, '\0' }; unsigned char pchBraceBrk[] = { DTWM_CHAR_R_BRACE, '\0' }; /* There needs to be something to look at */ if (!pch) return (NULL); pchStart = pch; lenOriginal = strlen ((char *)pch); chlen = mblen ((char *)pch, MB_CUR_MAX); chSave = '\0'; while (*pch && (chlen > 0)) { if (chlen == 1) { bAlreadyAdvanced = False; switch (*pch) { case DTWM_CHAR_BACKSLASH: /* * Copy up to start of quoted char */ if (!pchReturn) { lenReturn = lenOriginal + 1; pchReturn = (unsigned char *) XtMalloc (lenReturn * sizeof (unsigned char)); pchReturn[0] = '\0'; } chSave = *pch; *pch = '\0'; strcat ((char *) pchReturn, (char *)pchStart); *pch = chSave; chSave = '\0'; /* * The next character is "escaped", skip over it. */ pchStart = pch += chlen; chlen = mblen ((char *)pch, MB_CUR_MAX); break; case DTWM_CHAR_ENVIRONMENT: /* save start of environment variable */ pchEnvStart = pch; pch += chlen; chlen = mblen ((char *)pch, MB_CUR_MAX); /* * Copy up to start of environment variable */ if (!pchReturn) { lenReturn = lenOriginal + 1; pchReturn = (unsigned char *) XtMalloc (lenReturn * sizeof (unsigned char)); pchReturn[0] = '\0'; lenSave = 0; } else { lenSave = strlen ((char *)pchReturn); } lenNonEnv = pchEnvStart - pchStart; memcpy (&pchReturn[lenSave], pchStart, lenNonEnv); pchReturn[lenSave+lenNonEnv] = '\0'; /* * Determine how we find the end of this * environment variable. */ bEatBreak = False; if ((chlen == 1) && (*pch == DTWM_CHAR_L_PAREN)) { pch += chlen; chlen = mblen ((char *)pch, MB_CUR_MAX); pchBreak = pchParenBrk; bEatBreak = True; } else if ((chlen == 1) && (*pch == DTWM_CHAR_L_BRACE)) { pch += chlen; chlen = mblen ((char *)pch, MB_CUR_MAX); pchBreak = pchBraceBrk; bEatBreak = True; } else if (pchBrk && *pchBrk) { pchBreak = pchBrk; } else { pchBreak = pchDefaultBrk; } /* * Look for end of environment variable */ pchNext = (unsigned char *) strpbrk ((char *)pch, (char *)pchBreak); if (!pchNext) { /* it's the rest of the string */ chSave = '\0'; bEatBreak = False; pchNext = pch + strlen ((char *) pch); } else { /* temporarily put a string terminator here */ chSave = *pchNext; *pchNext = '\0'; } /* * Lookup environment variable */ lenEnvVar = strlen ((char *)pch); pchEnvValue = (unsigned char *) getenv ((char *)pch); if (pchEnvValue) { /* * Insure there's enough room in the return string */ lenEnvValue = strlen ((char *)pchEnvValue); if (!pchReturn) { lenReturn = lenOriginal + 1 - lenEnvVar + lenEnvValue; pchReturn = (unsigned char *) XtMalloc (lenReturn * sizeof (unsigned char)); pchReturn[0] = '\0'; } else { lenReturn = lenReturn + 1 - lenEnvVar + lenEnvValue; pchReturn = (unsigned char *) XtRealloc ((char *)pchReturn, lenReturn * sizeof (unsigned char)); } /* * Tack it onto the return string */ strcat ((char *)pchReturn, (char *)pchEnvValue); } /* * Advance the pointer for the next pass */ if (chSave) { /* restore saved character */ *pchNext = chSave; chSave = '\0'; /* * If this was a closing paren, then skip it */ if (bEatBreak) { chlen = mblen ((char *)pchNext, MB_CUR_MAX); pchNext += chlen; } } pchStart = pch = pchNext; chlen = mblen ((char *)pch, MB_CUR_MAX); /* * We're already pointing at the next character * to process, don't advance again! */ bAlreadyAdvanced = True; break; default: /* this character is not interesting */ break; } /* * Move to the next character if we're not already * there. */ if (!bAlreadyAdvanced) { pch += chlen; chlen = mblen ((char *)pch, MB_CUR_MAX); } } else { pch += chlen; chlen = mblen ((char *)pch, MB_CUR_MAX); } } if (pchReturn && *pchStart) { /* * Copy remaining parts of the string */ strcat ((char *)pchReturn, (char *)pchStart); } return (pchReturn); } /* END OF FUNCTION _DtWmParseExpandEnvironmentVariables */ /******************************<->************************************* * * _DtWmParseMakeQuotedString (pchLine) * * * Description: * ----------- * Encapsulates the passed in "line" into a string argument quoted * by double quotes. Special characters are "escaped" as needed. * * Inputs: * ------ * pchLine = ptr to string to enclose in quotes * * Outputs: * ------- * Return = ptr to quoted string * * Comment: * ------- * Returned string should be freed with XtFree(). * ******************************<->***********************************/ unsigned char * _DtWmParseMakeQuotedString (unsigned char *pchLine) { unsigned char *pchRet; int iLen0, iLen1; int cSpecial; int i,j; int chlen; iLen0 = strlen ((char *)pchLine); iLen1 = iLen0 + 2; /* for starting, ending quotes */ for (i=0; i < iLen0; i++) { /* * Count special chars to get estimate of new length */ chlen = mblen ((char *) &pchLine[i], MB_CUR_MAX); if ((chlen == 1) && ((pchLine[i] == '\\') || (pchLine[i] == '"'))) { iLen1++; } else if (chlen < 1) { break; } else { i += chlen-1; } } pchRet = (unsigned char *) XtMalloc (1+iLen1); if (pchRet) { pchRet[0] = '"'; /* starting quote */ /* * Copy chars from old string to new one */ for (i=0, j=1; i < iLen0; i++, j++) { chlen = mblen ((char *) &pchLine[i], MB_CUR_MAX); if ((chlen == 1) && ((pchLine[i] == '\\') || (pchLine[i] == '"'))) { /* quote next char */ pchRet[j++] = '\\'; } else if (chlen < 1) { break; } else while (chlen > 1) { /* copy first bytes of multibyte char */ pchRet[j++] = pchLine[i++]; chlen--; } /* copy char */ pchRet[j] = pchLine[i]; } pchRet[j++] = '"'; /* ending quote */ pchRet[j] = '\0'; /* end of string */ } return (pchRet); } /* END OF FUNCTION _DtWmParseMakeQuotedString */ /*==================== END OF FILE WmParse.c ====================*/