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
23 #ifdef VERBOSE_REV_INFO
24 static char rcsid[] = "$XConsortium: WmParse.c /main/5 1996/10/30 11:36:06 drk $";
25 #endif /* VERBOSE_REV_INFO */
26 /******************************<+>*************************************
27 **********************************************************************
31 ** Project: HP/Motif Workspace Manager (dtwm)
35 ** This file contains the generic parsing routines
38 *********************************************************************
40 ** (c) Copyright 1987, 1988, 1989, 1990, 1991 HEWLETT-PACKARD COMPANY
41 ** ALL RIGHTS RESERVED
43 **********************************************************************
44 **********************************************************************
47 **********************************************************************
48 ******************************<+>*************************************/
50 /* ANSI C definitions, This should be the first thing in WmGlobal.h */
62 #include <X11/Intrinsic.h>
68 #endif /* MULTIBYTE */
75 static DtWmpParseBuf * _DtWmpIncBuf (
76 DtWmpParseBuf *pWmPB);
81 #define MAXLINE (MAXWMPATH+1)
83 #define MAX_QUOTE_DEPTH 10
86 * This flags non-OSF code in those sections that were lifted
93 * Defines used to maintain code similarity between OSF/mwm source
94 * routines and these routines.
96 #define cfileP ((pWmPB)->pFile)
97 #define linec ((pWmPB)->lineNumber)
98 #define line ((pWmPB)->pchLine)
99 #define parseP ((pWmPB)->pchNext)
100 #define ScanWhitespace(s) (_DtWmParseSkipWhitespaceC(s))
101 #define PeekAhead(s,l) (_DtWmParsePeekAhead(s,l))
104 /*************************************<->*************************************
106 * _DtWmParseSkipWhitespace(pWmPB)
111 * Scan the current string, skipping over all white space characters.
116 * pWmPB = ptr to parse buffer
121 * pWmPB = parse buffer modified; current line ptr may be moved.
126 * Assumes there's a current line in the parse buffer
128 *************************************<->***********************************/
130 void _DtWmParseSkipWhitespace(DtWmpParseBuf *pWmPB)
132 _DtWmParseSkipWhitespaceC (&(pWmPB->pchNext));
134 } /* END OF FUNCTION _DtWmParseSkipWhitespace */
137 /*************************************<->*************************************
139 * _DtWmParseNextToken (pWmPB)
144 * Returns the next quoted or whitespace-terminated nonquoted string in the
145 * current line buffer.
150 * pWmPB = ptr to parse buffer
155 * Return = ptr to null terminated string.
156 * pWmPB = current line modified internally.
161 * May alter the line buffer contents.
162 * Handles quoted strings and characters, removing trailing whitespace from
164 * Returns NULL string if the line is empty or is a comment.
165 * Does not use session manager style algorithm for dealing with
168 *************************************<->***********************************/
171 _DtWmParseNextToken (
175 return (_DtWmParseNextTokenC (&(pWmPB->pchNext), False));
179 /*************************************<->*************************************
181 * _DtWmParseNextTokenExpand (pWmPB)
186 * Returns the next quoted or whitespace-terminated nonquoted string in the
187 * current line buffer. Environment variables found in the are expanded.
188 * Characters quoted by '\' are passed through unaffected with the
189 * quoting '\' removed.
194 * pWmPB = ptr to parse buffer
199 * Return = ptr to null terminated string.
200 * Free this string with XtFree().
201 * pWmPB = current line modified internally.
206 * May alter the line buffer contents.
207 * Handles quoted strings and characters, removing trailing whitespace from
209 * Returns NULL string if the line is empty or is a comment.
211 *************************************<->***********************************/
214 _DtWmParseNextTokenExpand (
219 unsigned char *pchReturn = NULL;
221 /* isolate the next token */
222 pch = _DtWmParseNextTokenC (&(pWmPB->pchNext), False);
224 /* expand environment variables, a copy of the string is returned */
225 pchReturn = _DtWmParseExpandEnvironmentVariables (pch, NULL);
228 * If a token was found, but no copy returned, there were no
229 * environment variables. This routine needs to return a copy,
232 if (pch && !pchReturn)
233 pchReturn = (unsigned char *) XtNewString ((String) pch);
239 /*************************************<->*************************************
241 * _DtWmParseBackUp (pWmPB, pchTok)
246 * Backs up to the previous token (the one before pchTok)
251 * pWmPB = ptr to parse buffer
252 * pchTok = ptr to a token in the parse buffer
257 * Returns = ptr to prev token
262 * Operates on the line buffer in the pWmPB structure. Backs up
263 * the next pointer and writes a space over the interpolated
266 *************************************<->***********************************/
270 DtWmpParseBuf *pWmPB,
271 unsigned char *pchTok
274 if ((pchTok > pWmPB->pchLine) &&
275 (pchTok < (pWmPB->pchLine + pWmPB->cLineSize)))
279 unsigned char *pchLast;
282 pch = pchLast = pWmPB->pchLine;
285 * Search from beginning (because of multibyte chars) to
286 * find the token before the string we're interested in.
288 while ((pch < pchTok))
290 chlen = mblen ((char *)pch, MB_CUR_MAX);
297 * Found the NULL preceding the string passed in!
298 * Replace it with a blank and return the previous
299 * token (pointed to by pchLast).
301 *(pch - 1) = DTWM_CHAR_SPACE;
307 * Remember the beginning of this token.
322 pWmPB->pchNext = pchLast;
323 #else /* MULTIBYTE */
326 * Replace preceding NULL with a space.
332 *pchTok = DTWM_CHAR_SPACE;
336 * Back up to next NULL or beginning of line.
338 while ((pchTok >= pWmPB->pchLine) && *pchTok)
343 pWmPB->pchNext = pchTok + 1;
345 #endif /* MULTIBYTE */
347 return (pWmPB->pchNext);
352 /*************************************<->*************************************
354 * _DtWmParseSkipWhitespaceC(linePP)
359 * Scan the string, skipping over all white space characters.
364 * linePP = nonNULL pointer to current line buffer pointer
369 * linePP = nonNULL pointer to revised line buffer pointer
374 * Assumes linePP is nonNULL
376 *************************************<->***********************************/
378 void _DtWmParseSkipWhitespaceC(unsigned char **linePP)
382 (mblen ((char *)*linePP, MB_CUR_MAX) == 1) &&
385 while (*linePP && isspace (**linePP))
391 } /* END OF FUNCTION _DtWmParseSkipWhitespaceC */
395 /*************************************<->*************************************
397 * _DtWmParseNextTokenC (linePP, SmBehavior)
402 * Returns the next quoted or whitespace-terminated nonquoted string in the
404 * Additional functionality added to GetString in that anything in a
405 * quoted string is considered sacred and nothing will be stripped from
406 * the middle of a quoted string.
411 * linePP = pointer to current line buffer pointer.
412 * SmBehavior = flag that enables parsing session manager hints if True.
413 * If False, this behaves as the normal OSF mwm GetString
419 * linePP = pointer to revised line buffer pointer.
425 * May alter the line buffer contents.
426 * Handles quoted strings and characters, removing trailing whitespace from
428 * Returns NULL string if the line is empty or is a comment.
429 * Code stolen from dtmwm.
431 *************************************<->***********************************/
434 _DtWmParseNextTokenC (
435 unsigned char **linePP,
439 /***********************************************************************
441 * The following code is duplicated from WmResParse.c (GetStringC)
442 * GetStringC is the HP DT version of GetString.
444 * It works here through the magic of #defines.
446 ***********************************************************************/
447 unsigned char *lineP = *linePP;
450 unsigned char *lnwsP;
451 unsigned int level = 0, checkLev, i, quoteLevel[MAX_QUOTE_DEPTH];
455 /* get rid of leading white space */
456 ScanWhitespace (&lineP);
459 * Return NULL if line is empty, whitespace, or begins with a comment.
463 ((chlen = mblen ((char *)lineP, MB_CUR_MAX)) < 1) ||
464 ((chlen == 1) && ((*lineP == '!') ||
465 ((!SmBehavior) && (*lineP == '#'))))
472 if ((chlen == 1) && (*lineP == '"'))
475 quoteLevel[level] = 1;
477 * Start beyond double quote and find the end of the quoted string.
478 * '\' quotes the next character.
479 * Otherwise, matching double quote or NULL terminates the string.
481 * We use lnwsP to point to the last non-whitespace character in the
482 * quoted string. When we have found the end of the quoted string,
483 * increment lnwsP and if lnwsP < endP, write NULL into *lnwsP.
484 * This removes any trailing whitespace without overwriting the
485 * matching quote, needed later. If the quoted string was all
486 * whitespace, then this will write a NULL at the beginning of the
487 * string that will be returned -- OK.
489 lnwsP = lineP++; /* lnwsP points to first '"' */
490 curP = endP = lineP; /* other pointers point beyond */
492 while ((*endP = *curP) &&
493 ((chlen = mblen ((char *)curP, MB_CUR_MAX)) > 0) &&
494 ((chlen > 1) || (*curP != '"')))
495 /* Haven't found matching quote yet.
496 * First byte of next character has been copied to endP.
500 if ((chlen == 1) && (*endP == '\\') &&
501 ((chlen = mblen ((char *)curP, MB_CUR_MAX)) > 0))
503 * copy first byte of quoted nonNULL character down.
504 * point curP to next byte
510 * Check to see if this is a quoted quote - if it is
511 * strip off a level - if not - it's sacred leave it alone
513 checkLev = PeekAhead((curP - 1), quoteLevel[level]);
516 if(quoteLevel[level] >= checkLev)
518 if (level > 0) level--;
520 else if (level < MAX_QUOTE_DEPTH)
523 quoteLevel[level] = checkLev;
526 for(i = 0;i < (checkLev - 2);i++)
528 *endP++ = *curP++;curP++;
540 /* Singlebyte character: character copy finished. */
543 /* whitespace character: leave lnwsP unchanged. */
548 /* non-whitespace character: point lnwsP to it. */
554 /* Multibyte (nonwhitespace) character: point lnwsP to it.
555 * Finish character byte copy.
566 #else /* MULTIBYTE */
568 /* get rid of leading white space */
569 ScanWhitespace (&lineP);
571 /* Return NULL if line is empty, whitespace, or begins with a comment. */
572 if ((lineP == NULL || *lineP == '\0') ||
573 (!SmBehavior && (*lineP == '#')))
582 quoteLevel[level] = 1;
584 * Start beyond double quote and find the end of the quoted string.
585 * '\' quotes the next character.
586 * Otherwise, matching double quote or NULL terminates the string.
588 * We use lnwsP to point to the last non-whitespace character in the
589 * quoted string. When we have found the end of the quoted string,
590 * increment lnwsP and if lnwsP < endP, write NULL into *lnwsP.
591 * This removes any trailing whitespace without overwriting the
592 * matching quote, needed later. If the quoted string was all
593 * whitespace, then this will write a NULL at the beginning of the
594 * string that will be returned -- OK.
596 lnwsP = lineP++; /* lnwsP points to first '"' */
597 curP = endP = lineP; /* other pointers point beyond */
599 while ((*endP = *curP) && (*endP != '"'))
600 /* haven't found matching quote yet */
602 /* point curP to next character */
604 if ((*endP == '\\') && (*curP != NULL))
605 /* shift quoted nonNULL character down and curP ahead */
610 * Check to see if this is a quoted quote - if it is
611 * strip off a level - if not - it's sacred leave it alone
613 checkLev = PeekAhead((curP - 1), quoteLevel[level]);
616 if(quoteLevel[level] >= checkLev)
618 if (level > 0) level--;
620 else if (level < MAX_QUOTE_DEPTH)
623 quoteLevel[level] = checkLev;
626 for(i = 0;i < (checkLev - 2);i++)
628 *endP++ = *curP++;curP++;
639 /* whitespace character: leave lnwsP unchanged. */
644 /* non-whitespace character: point lnwsP to it. */
649 #endif /* MULTIBYTE */
652 * Found matching quote or NULL.
653 * NULL out any trailing whitespace.
664 /* Unquoted string */
667 * Find the end of the nonquoted string.
668 * '\' quotes the next character.
669 * Otherwise, whitespace, NULL, or '#' terminates the string.
674 while ((*endP = *curP) &&
675 ((chlen = mblen ((char *)curP, MB_CUR_MAX)) > 0) &&
676 ((chlen > 1) || (!isspace (*curP) &&
677 (SmBehavior || (*curP != '#')))))
678 /* Haven't found whitespace or '#' yet.
679 * First byte of next character has been copied to endP.
683 if ((chlen == 1) && (*endP == '\\') &&
684 ((chlen = mblen ((char *)curP, MB_CUR_MAX)) > 0))
686 * copy first byte of quoted nonNULL character down.
687 * point curP to next byte
694 /* Multibyte character: finish character copy. */
702 #else /* MULTIBYTE */
703 while ((*endP = *curP) && !isspace (*endP) &&
704 (SmBehavior || (*endP != '#')))
706 /* point curP to next character */
708 if ((*endP == '\\') && (*curP != '\0'))
709 /* shift quoted nonNULL character down and curP ahead */
715 #endif /* MULTIBYTE */
719 * Three cases for *endP:
720 * '#' --> write NULL over # and point to NULL
722 * matching quote -> write NULL over char and point beyond
723 * NULL -> point to NULL
726 if (!SmBehavior && (*endP == '#'))
728 *endP = '\0'; /* write NULL over '#' */
729 *linePP = endP; /* point to NULL */
731 else if (*endP != '\0')
733 *endP = '\0'; /* write NULL over terminator */
734 *linePP = ++curP; /* point beyond terminator */
740 return ((unsigned char *)lineP);
742 } /* END OF FUNCTION _DtWmParseNextTokenC */
746 /*************************************<->*************************************
748 * (DtWmParseBuf *) _DtWmParseNewBuf (void)
753 * Allocates a new parse record for parsing.
762 * Return = ptr to parse buffer record, NULL if memory allocation
768 * Call this first before using the other DtWmp routines that require
769 * a parse buffer. Treat this as an opaque type; use the provided
770 * routines to create, access, and destroy this structure.
772 *************************************<->***********************************/
775 _DtWmParseNewBuf ( void )
778 DtWmpParseBuf *pWmPB;
780 pWmPB = (DtWmpParseBuf *) XtMalloc (sizeof (DtWmpParseBuf));
783 pWmPB->pchLine = (unsigned char *) XtMalloc (MAXLINE+1);
786 XtFree ((char *)pWmPB);
793 pWmPB->lineNumber = 0;
794 pWmPB->pchNext = pWmPB->pchLine;
795 pWmPB->cLineSize = MAXLINE+1;
797 *(pWmPB->pchLine) = '\0';
802 } /* END OF FUNCTION _DtWmParseNewBuf */
805 /*************************************<->*************************************
807 * (DtWmParseBuf *) _DtWmpIncBuf (pWmPB)
812 * Increases the size of the line buffer in the parse buffer
816 * pWmPB = pointer to a parse buffer
821 * Return = ptr to parse buffer record, NULL if memory allocation
828 *************************************<->***********************************/
830 static DtWmpParseBuf *
832 DtWmpParseBuf *pWmPB)
841 /* save index into old string */
842 ix = pWmPB->pchNext - pWmPB->pchLine;
845 pWmPB->pchLine = (unsigned char *)
846 XtRealloc ((char *)pWmPB->pchLine, (pWmPB->cLineSize + MAXLINE));
849 pWmPB->cLineSize += MAXLINE;
853 /* restore index into new string */
854 pWmPB->pchNext = pWmPB->pchLine + ix;
861 } /* END OF FUNCTION _DtWmpIncBuf */
864 /*************************************<->*************************************
866 * _DtWmParseDestroyBuf (pWmPB)
871 * Destroys a parse buffer record, freeing any allocated memory.
876 * pWmPB = ptr to previously allocated parse buffer
886 * Destroys parse buffers allocated by _DtWmParseNewBuf.
888 *************************************<->***********************************/
891 _DtWmParseDestroyBuf (
900 XtFree ((char *) pWmPB->pchLine);
902 XtFree ((char *) pWmPB);
905 } /* END OF FUNCTION _DtWmParseDestroyBuf */
908 /*************************************<->*************************************
910 * (unsigned char *) _DtWmParseSetLine (pWmPB, pch)
915 * Sets a line into the parse buffer structure. This is used in cases
916 * where parsing of an embedded string, usually a default, is done
917 * instead of parsing out of a file.
922 * pWmPB = previously allocated parse buffer
923 * pch = ptr to unsigned char string (zero terminated)
932 * This resets any previous setting of the file pointer. EOF wil be
933 * returned when the string pointed to by pch is exhausted.
935 * Resets line number count.
937 *************************************<->***********************************/
941 DtWmpParseBuf *pWmPB,
948 pWmPB->pchLine = pch;
949 pWmPB->pchNext = pWmPB->pchLine;
951 pWmPB->lineNumber = 0;
954 } /* END OF FUNCTION _DtWmParseSetLine */
957 /*************************************<->*************************************
959 * (FILE *) _DtWmParseSetFile (pWmPB, pFile)
964 * Sets the file pointer in a parse buffer. This is used when parsing
965 * from a file is required.
970 * pWmPB = pointer to a parse buffer
971 * pFile = pointer to an opened FILE
980 * You fopen the file first, then pass in the FILE * returned to this
983 * Resets line number count.
985 *************************************<->***********************************/
989 DtWmpParseBuf *pWmPB,
996 pWmPB->pchLine[0] = '\0';
997 pWmPB->pchNext = NULL;
998 pWmPB->pFile = pFile;
999 pWmPB->lineNumber = 0;
1002 } /* END OF FUNCTION _DtWmParseSetFile */
1005 /*************************************<->*************************************
1007 * (unsigned char *) _DtWmParseNextLine ( pWmPB )
1012 * Returns a pointer to the next line to parse.
1017 * pWmPB = pointer to a parse buffer
1022 * Return = pointer to next line to parse or NULL on EOF.
1029 *************************************<->***********************************/
1032 _DtWmParseNextLine (
1033 DtWmpParseBuf *pWmPB
1037 /***********************************************************************
1039 * The following code is duplicated from WmResParse.c (GetNextLine)
1040 * It works here through the magic of #defines.
1042 ***********************************************************************/
1044 register unsigned char *string;
1056 /* read fopened file */
1058 if ((string = (unsigned char *)
1059 fgets ((char *)line, MAXLINE, cfileP)) != NULL)
1062 if (strlen((char *)string) > (size_t)pWmPB->cLineSize)
1065 * Bump size of destination buffer
1067 pWmPB->cLineSize = 1 + strlen((char *)string);
1068 pWmPB->pchLine = (unsigned char *)
1069 XtRealloc ((char *)pWmPB->pchLine,
1070 (pWmPB->cLineSize));
1072 #endif /* PARSE_LIB */
1073 #ifndef NO_MULTIBYTE
1077 ((len = mblen((char *)string, MB_CUR_MAX)) > 0))
1079 mbtowc(&last, (char *)string, MB_CUR_MAX);
1084 mbtowc(&wdelim, &delim, MB_CUR_MAX);
1085 if (lastlen == 1 && last == wdelim)
1089 if (!fgets((char *)string, MAXLINE - (string - line), cfileP))
1094 ((len = mblen((char *)string, MB_CUR_MAX)) > 0))
1096 mbtowc(&last, (char *)string, MB_CUR_MAX);
1102 while (lastlen == 1 && last == wdelim);
1106 len = strlen((char *)string) - 2;
1107 if ((len > 0) && string[len] == '\\')
1110 string = &string[len];
1111 if (fgets((char *)string,
1112 MAXLINE - (string-line), cfileP) == NULL)
1114 len = strlen((char *)string) - 2;
1116 } while ((len >= 0) && string[len] == '\\');
1122 else if ((parseP != NULL) && (*parseP != '\0'))
1123 /* read parse string */
1126 if (strlen((char *)parseP) > (size_t)pWmPB->cLineSize)
1129 * Bump size of destination buffer
1131 pWmPB->cLineSize = 1 + strlen((char *)parseP);
1132 pWmPB->pchLine = (unsigned char *)
1133 XtRealloc ((char *)pWmPB->pchLine,
1134 (pWmPB->cLineSize));
1136 #endif /* PARSE_LIB */
1139 while ((*parseP != '\0') &&
1140 ((chlen = mblen ((char *)parseP, MB_CUR_MAX)) != 0) &&
1142 /* copy all but end-of-line and newlines to line buffer */
1150 *(string++) = *(parseP++);
1155 while ((*parseP != '\0') && (*parseP != '\n'))
1156 /* copy all but end-of-line and newlines to line buffer */
1158 *(string++) = *(parseP++);
1162 if (*parseP == '\n')
1176 /* update pchNext to get next line */
1177 pWmPB->pchNext = string;
1179 #endif /* PARSE_LIB */
1183 } /* END OF FUNCTION _DtWmParseNextLine */
1186 /*************************************<->*************************************
1188 * (unsigned char *) _DtWmParseCurrentChar (pWmPB)
1193 * Returns a pointer to the rest of the current line.
1198 * pWmPB = pointer to a parse buffer
1203 * Return = pointer to the rest of the current line
1208 * Useful in cases where you want to look at a char before getting the
1209 * next token or if you want to treat the rest of the line as a
1212 *************************************<->***********************************/
1215 _DtWmParseCurrentChar (
1216 DtWmpParseBuf *pWmPB
1220 return (pWmPB ? pWmPB->pchNext : (unsigned char *)NULL);
1222 } /* END OF FUNCTION _DtWmParseCurrentChar */
1226 /*************************************<->*************************************
1228 * (unsigned char *) _DtWmParseNextChar (pWmPB)
1233 * Advances the pointer to the next char and returns a pointer
1234 * to the new current char.
1239 * pWmPB = pointer to a parse buffer
1244 * Return = pointer to the rest of the current line
1250 *************************************<->***********************************/
1253 _DtWmParseNextChar (
1254 DtWmpParseBuf *pWmPB
1258 unsigned char *pch = NULL;
1264 (chlen = mblen((char *)pWmPB->pchNext, MB_CUR_MAX) > 0))
1266 pch = (pWmPB->pchNext += chlen);
1268 #else /* MULTIBYTE */
1269 if (pWmPB && pWmPB->pchNext && *pWmPB->pchNext)
1271 pch = ++pWmPB->pchNext;
1273 #endif /* MULTIBYTE */
1279 /*************************************<->*************************************
1281 * (int) _DtWmParseLineNumber (pWmPB)
1286 * Returns the number of the current line of what's being parsed.
1291 * pWmPB = ptr to parse buffer
1296 * Return = number of current line
1301 * Used for error reporting.
1303 * The line number is computed by counting '\n' characters.
1305 *************************************<->***********************************/
1308 _DtWmParseLineNumber (
1309 DtWmpParseBuf *pWmPB
1313 return (pWmPB ? pWmPB->lineNumber : 0);
1315 } /* END OF FUNCTION _DtWmParseLineNumber */
1318 /*************************************<->*************************************
1320 * _DtWmParseToLower (string)
1325 * Lower all characters in a string.
1330 * string = NULL-terminated character string or NULL
1335 * string = NULL-terminated lower case character string or NULL
1340 * Can handle multi-byte characters
1342 *************************************<->***********************************/
1344 void _DtWmParseToLower (unsigned char *string)
1346 unsigned char *pch = string;
1350 while ((chlen = mblen ((char *)pch, MB_CUR_MAX)) > 0)
1352 if ((chlen == 1) && (isupper (*pch)))
1354 *pch = tolower(*pch);
1359 while (*pch != NULL)
1363 *pch = tolower(*pch);
1369 } /* END OF FUNCTION _DtWmParseToLower */
1373 /*************************************<->*************************************
1375 * _DtWmParsePeekAhead (currentChar, currentLev)
1380 * Returns a new level value if this is a new nesting level of quoted string
1381 * Otherwise it returns a zero
1386 * currentChar = current position in the string
1387 * currentLev = current level of nesting
1392 * Returns either a new level of nesting or zero if the character is copied in
1398 *************************************<->***********************************/
1399 unsigned int _DtWmParsePeekAhead(unsigned char *currentChar,
1400 unsigned int currentLev)
1404 Boolean done = False;
1405 unsigned int tmpLev = 1;
1409 while (((chlen = mblen ((char *)currentChar, MB_CUR_MAX)) > 0) &&
1410 (chlen == 1) && ((*currentChar == '"') || (*currentChar == '\\'))
1415 if(((chlen = mblen ((char *)currentChar, MB_CUR_MAX)) > 0) &&
1417 ((*currentChar == '"') || (*currentChar == '\\')))
1420 if(*currentChar == '"')
1431 while((*currentChar != NULL) && (done == False) &&
1432 ((*currentChar == '"') || (*currentChar == '\\')))
1435 if((*currentChar != NULL) &&
1436 ((*currentChar == '"') || (*currentChar == '\\')))
1439 if(*currentChar == '"')
1449 #endif /*MULTIBYTE*/
1452 * Figure out if this is truly a new level of nesting - else ignore it
1453 * This section probably could do some error checking and return -1
1454 * If so, change type of routine from unsigned int to int
1464 } /* END OF FUNCTION _DtWmParsePeekAhead */
1468 /*************************************<->*************************************
1470 * (unsigned char *) _DtWmParseFilenameExpand (pchFilename)
1475 * Returns a copy of a file name with environment variables
1481 * pchFilename = ptr to a zero terminated character string (filename)
1486 * Return = ptr to a new file name with environment variables
1492 * The passed in string is temporarily modified inside here.
1494 * Free the returned string with XtFree().
1496 * Returns NULL on a memory allocation error.
1498 * Environment variables that can't be expanded are removed from
1499 * the returned copy.
1501 * If no environment variables, you get a copy of the string back.
1503 *************************************<->***********************************/
1505 _DtWmParseFilenameExpand (
1506 unsigned char *pchFilename
1510 unsigned char *pchN, *pchNew, *pchO;
1511 unsigned char *pchEnv, *pchEnv0, *pchEnv1;
1512 unsigned char chSave;
1514 unsigned char pchBrk[] = { DTWM_CHAR_ENVIRONMENT,
1515 DTWM_CHAR_DIRECTORY,
1519 len = strlen ((char *)pchFilename);
1520 pchNew = (unsigned char *) XtMalloc (1+len);
1525 while (pchNew && pchO && *pchO)
1527 /* find next environment variable */
1528 pchEnv0 = (unsigned char *)
1529 strchr ((char *)pchO, (int) DTWM_CHAR_ENVIRONMENT);
1532 /* length to this point */
1535 /* copy up to environment character */
1538 memcpy (&pchNew[ix], pchO, n);
1542 /* skip environment character */
1545 /* end of variable is at one of:
1546 * start of next variable,
1547 * start of next directory,
1550 pchEnv1 = (unsigned char *)
1551 strpbrk ((char *)pchEnv0, (char *)pchBrk);
1555 /* next string starts after this one */
1557 n = pchEnv1 - pchEnv0 + 1;
1559 /* replace this char with NULL for now */
1565 /* This environment variable is the last thing on
1566 * the line. Signal all done.
1568 n = strlen ((char *) pchO);
1572 pchEnv = (unsigned char *) getenv ((char *)pchEnv0);
1575 nx = strlen ((char *) pchEnv);
1579 pchNew = (unsigned char *)
1580 XtRealloc ((char *)pchNew, 1+len);
1584 memcpy (&pchNew[ix], pchEnv, nx);
1598 /* keep a kosher string */
1603 /* copy the rest of the string */
1604 n = strlen ((char *) pchO);
1605 memcpy (&pchNew[ix], pchO, n);
1608 /* remember the NULL! (a famous battle cry) */
1609 pchNew[ix + n] = '\0';
1615 } /* END OF FUNCTION _DtWmParseFilenameExpand */
1618 /*************************************<->*************************************
1620 * unsigned char * _DtWmParseExpandEnvironmentVariables (pch, pchBrk)
1625 * Expands environment variables in a string.
1630 * pch = ptr to a zero terminated character string
1631 * pchBrk = array of "break" characters (see strpbrk()).
1632 * defaults are used if this is NULL.
1636 * Return = string with expanded environment variables. (free with XtFree)
1637 * NULL string if no environment variables or backslashes
1638 * found in the string passed in.
1643 * Free returned string with XtFree()
1645 * Environment variables that can't be expanded are removed from
1646 * the returned copy.
1648 * Default delimiter set is [Space], [Tab], '$', [Newline], '\', '/'.
1650 * Variables of form $(..) and ${..} supported.
1652 * A backslash '\' in front of any character quotes it. The backslash
1653 * is removed in the returned string. A literal backslash needs to be
1654 * quoted with a backslash.
1656 *************************************<->***********************************/
1658 _DtWmParseExpandEnvironmentVariables (
1660 unsigned char *pchBrk
1666 #else /* MULTIBYTE */
1667 int chlen = 1; /* length of character is always '1' */
1668 #endif /* MULTIBYTE */
1669 unsigned char *pchStart;
1670 unsigned char chSave;
1671 unsigned char *pchEnvStart;
1672 unsigned char *pchEnvValue;
1673 unsigned char *pchReturn = NULL;
1674 unsigned char *pchNext;
1675 unsigned char *pchBreak;
1677 Boolean bAlreadyAdvanced;
1684 static unsigned char pchDefaultBrk[] = {
1685 DTWM_CHAR_ENVIRONMENT,
1689 DTWM_CHAR_BACKSLASH,
1690 DTWM_CHAR_DIRECTORY,
1692 unsigned char pchParenBrk[] = {
1695 unsigned char pchBraceBrk[] = {
1699 /* There needs to be something to look at */
1704 lenOriginal = strlen ((char *)pch);
1706 chlen = mblen ((char *)pch, MB_CUR_MAX);
1707 #endif /* MULTIBYTE */
1710 while (*pch && (chlen > 0))
1714 bAlreadyAdvanced = False;
1717 case DTWM_CHAR_BACKSLASH:
1719 * Copy up to start of quoted char
1723 lenReturn = lenOriginal + 1;
1724 pchReturn = (unsigned char *)
1725 XtMalloc (lenReturn * sizeof (unsigned char));
1726 pchReturn[0] = '\0';
1730 strcat ((char *) pchReturn, (char *)pchStart);
1735 * The next character is "escaped", skip over it.
1737 pchStart = pch += chlen;
1739 chlen = mblen ((char *)pch, MB_CUR_MAX);
1740 #endif /* MULTIBYTE */
1743 case DTWM_CHAR_ENVIRONMENT:
1744 /* save start of environment variable */
1748 chlen = mblen ((char *)pch, MB_CUR_MAX);
1749 #endif /* MULTIBYTE */
1752 * Copy up to start of environment variable
1756 lenReturn = lenOriginal + 1;
1757 pchReturn = (unsigned char *)
1758 XtMalloc (lenReturn * sizeof (unsigned char));
1759 pchReturn[0] = '\0';
1764 lenSave = strlen ((char *)pchReturn);
1766 lenNonEnv = pchEnvStart - pchStart;
1767 memcpy (&pchReturn[lenSave], pchStart, lenNonEnv);
1768 pchReturn[lenSave+lenNonEnv] = '\0';
1771 * Determine how we find the end of this
1772 * environment variable.
1776 (*pch == DTWM_CHAR_L_PAREN))
1780 chlen = mblen ((char *)pch, MB_CUR_MAX);
1781 #endif /* MULTIBYTE */
1782 pchBreak = pchParenBrk;
1785 else if ((chlen == 1) &&
1786 (*pch == DTWM_CHAR_L_BRACE))
1790 chlen = mblen ((char *)pch, MB_CUR_MAX);
1791 #endif /* MULTIBYTE */
1792 pchBreak = pchBraceBrk;
1795 else if (pchBrk && *pchBrk)
1801 pchBreak = pchDefaultBrk;
1805 * Look for end of environment variable
1807 pchNext = (unsigned char *)
1808 strpbrk ((char *)pch, (char *)pchBreak);
1812 /* it's the rest of the string */
1815 pchNext = pch + strlen ((char *) pch);
1819 /* temporarily put a string terminator here */
1825 * Lookup environment variable
1827 lenEnvVar = strlen ((char *)pch);
1828 pchEnvValue = (unsigned char *) getenv ((char *)pch);
1833 * Insure there's enough room in the return string
1835 lenEnvValue = strlen ((char *)pchEnvValue);
1838 lenReturn = lenOriginal + 1 - lenEnvVar +
1840 pchReturn = (unsigned char *)
1841 XtMalloc (lenReturn * sizeof (unsigned char));
1842 pchReturn[0] = '\0';
1846 lenReturn = lenReturn + 1 - lenEnvVar +
1848 pchReturn = (unsigned char *)
1849 XtRealloc ((char *)pchReturn,
1850 lenReturn * sizeof (unsigned char));
1854 * Tack it onto the return string
1856 strcat ((char *)pchReturn, (char *)pchEnvValue);
1860 * Advance the pointer for the next pass
1864 /* restore saved character */
1869 * If this was a closing paren, then skip it
1874 chlen = mblen ((char *)pchNext, MB_CUR_MAX);
1875 #endif /* MULTIBYTE */
1879 pchStart = pch = pchNext;
1881 chlen = mblen ((char *)pch, MB_CUR_MAX);
1882 #endif /* MULTIBYTE */
1884 * We're already pointing at the next character
1885 * to process, don't advance again!
1887 bAlreadyAdvanced = True;
1892 /* this character is not interesting */
1897 * Move to the next character if we're not already
1900 if (!bAlreadyAdvanced)
1904 chlen = mblen ((char *)pch, MB_CUR_MAX);
1905 #endif /* MULTIBYTE */
1912 chlen = mblen ((char *)pch, MB_CUR_MAX);
1914 #endif /* MULTIBYTE */
1917 if (pchReturn && *pchStart)
1920 * Copy remaining parts of the string
1922 strcat ((char *)pchReturn, (char *)pchStart);
1927 } /* END OF FUNCTION _DtWmParseExpandEnvironmentVariables */
1931 /******************************<->*************************************
1933 * _DtWmParseMakeQuotedString (pchLine)
1938 * Encapsulates the passed in "line" into a string argument quoted
1939 * by double quotes. Special characters are "escaped" as needed.
1943 * pchLine = ptr to string to enclose in quotes
1947 * Return = ptr to quoted string
1951 * Returned string should be freed with XtFree().
1953 ******************************<->***********************************/
1956 _DtWmParseMakeQuotedString (unsigned char *pchLine)
1958 unsigned char *pchRet;
1966 iLen0 = strlen ((char *)pchLine);
1967 iLen1 = iLen0 + 2; /* for starting, ending quotes */
1969 for (i=0; i < iLen0; i++)
1972 * Count special chars to get estimate of new length
1975 chlen = mblen ((char *) &pchLine[i], MB_CUR_MAX);
1977 ((pchLine[i] == '\\') ||
1978 (pchLine[i] == '"')))
1990 #else /* MULTIBYTE */
1991 if ((pchLine[i] == '\\') ||
1992 (pchLine[i] == '"'))
1996 #endif /* MULTIBYTE */
1999 pchRet = (unsigned char *) XtMalloc (1+iLen1);
2003 pchRet[0] = '"'; /* starting quote */
2005 * Copy chars from old string to new one
2007 for (i=0, j=1; i < iLen0; i++, j++)
2010 chlen = mblen ((char *) &pchLine[i], MB_CUR_MAX);
2012 ((pchLine[i] == '\\') ||
2013 (pchLine[i] == '"')))
2015 /* quote next char */
2022 else while (chlen > 1)
2024 /* copy first bytes of multibyte char */
2025 pchRet[j++] = pchLine[i++];
2028 #else /* MULTIBYTE */
2029 if ((pchLine[i] == '\\') ||
2030 (pchLine[i] == '"'))
2032 /* quote next char */
2035 #endif /* MULTIBYTE */
2037 pchRet[j] = pchLine[i];
2039 pchRet[j++] = '"'; /* ending quote */
2040 pchRet[j] = '\0'; /* end of string */
2045 } /* END OF FUNCTION _DtWmParseMakeQuotedString */
2048 /*==================== END OF FILE WmParse.c ====================*/