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 */
74 static DtWmpParseBuf * _DtWmpIncBuf (
75 DtWmpParseBuf *pWmPB);
80 #define MAXLINE (MAXWMPATH+1)
82 #define MAX_QUOTE_DEPTH 10
85 * This flags non-OSF code in those sections that were lifted
92 * Defines used to maintain code similarity between OSF/mwm source
93 * routines and these routines.
95 #define cfileP ((pWmPB)->pFile)
96 #define linec ((pWmPB)->lineNumber)
97 #define line ((pWmPB)->pchLine)
98 #define parseP ((pWmPB)->pchNext)
99 #define ScanWhitespace(s) (_DtWmParseSkipWhitespaceC(s))
100 #define PeekAhead(s,l) (_DtWmParsePeekAhead(s,l))
103 /*************************************<->*************************************
105 * _DtWmParseSkipWhitespace(pWmPB)
110 * Scan the current string, skipping over all white space characters.
115 * pWmPB = ptr to parse buffer
120 * pWmPB = parse buffer modified; current line ptr may be moved.
125 * Assumes there's a current line in the parse buffer
127 *************************************<->***********************************/
129 void _DtWmParseSkipWhitespace(DtWmpParseBuf *pWmPB)
131 _DtWmParseSkipWhitespaceC (&(pWmPB->pchNext));
133 } /* END OF FUNCTION _DtWmParseSkipWhitespace */
136 /*************************************<->*************************************
138 * _DtWmParseNextToken (pWmPB)
143 * Returns the next quoted or whitespace-terminated nonquoted string in the
144 * current line buffer.
149 * pWmPB = ptr to parse buffer
154 * Return = ptr to null terminated string.
155 * pWmPB = current line modified internally.
160 * May alter the line buffer contents.
161 * Handles quoted strings and characters, removing trailing whitespace from
163 * Returns NULL string if the line is empty or is a comment.
164 * Does not use session manager style algorithm for dealing with
167 *************************************<->***********************************/
170 _DtWmParseNextToken (
174 return (_DtWmParseNextTokenC (&(pWmPB->pchNext), False));
178 /*************************************<->*************************************
180 * _DtWmParseNextTokenExpand (pWmPB)
185 * Returns the next quoted or whitespace-terminated nonquoted string in the
186 * current line buffer. Environment variables found in the are expanded.
187 * Characters quoted by '\' are passed through unaffected with the
188 * quoting '\' removed.
193 * pWmPB = ptr to parse buffer
198 * Return = ptr to null terminated string.
199 * Free this string with XtFree().
200 * pWmPB = current line modified internally.
205 * May alter the line buffer contents.
206 * Handles quoted strings and characters, removing trailing whitespace from
208 * Returns NULL string if the line is empty or is a comment.
210 *************************************<->***********************************/
213 _DtWmParseNextTokenExpand (
218 unsigned char *pchReturn = NULL;
220 /* isolate the next token */
221 pch = _DtWmParseNextTokenC (&(pWmPB->pchNext), False);
223 /* expand environment variables, a copy of the string is returned */
224 pchReturn = _DtWmParseExpandEnvironmentVariables (pch, NULL);
227 * If a token was found, but no copy returned, there were no
228 * environment variables. This routine needs to return a copy,
231 if (pch && !pchReturn)
232 pchReturn = (unsigned char *) XtNewString ((String) pch);
238 /*************************************<->*************************************
240 * _DtWmParseBackUp (pWmPB, pchTok)
245 * Backs up to the previous token (the one before pchTok)
250 * pWmPB = ptr to parse buffer
251 * pchTok = ptr to a token in the parse buffer
256 * Returns = ptr to prev token
261 * Operates on the line buffer in the pWmPB structure. Backs up
262 * the next pointer and writes a space over the interpolated
265 *************************************<->***********************************/
269 DtWmpParseBuf *pWmPB,
270 unsigned char *pchTok
273 if ((pchTok > pWmPB->pchLine) &&
274 (pchTok < (pWmPB->pchLine + pWmPB->cLineSize)))
278 unsigned char *pchLast;
281 pch = pchLast = pWmPB->pchLine;
284 * Search from beginning (because of multibyte chars) to
285 * find the token before the string we're interested in.
287 while ((pch < pchTok))
289 chlen = mblen ((char *)pch, MB_CUR_MAX);
296 * Found the NULL preceding the string passed in!
297 * Replace it with a blank and return the previous
298 * token (pointed to by pchLast).
300 *(pch - 1) = DTWM_CHAR_SPACE;
306 * Remember the beginning of this token.
321 pWmPB->pchNext = pchLast;
322 #else /* MULTIBYTE */
325 * Replace preceding NULL with a space.
331 *pchTok = DTWM_CHAR_SPACE;
335 * Back up to next NULL or beginning of line.
337 while ((pchTok >= pWmPB->pchLine) && *pchTok)
342 pWmPB->pchNext = pchTok + 1;
344 #endif /* MULTIBYTE */
346 return (pWmPB->pchNext);
351 /*************************************<->*************************************
353 * _DtWmParseSkipWhitespaceC(linePP)
358 * Scan the string, skipping over all white space characters.
363 * linePP = nonNULL pointer to current line buffer pointer
368 * linePP = nonNULL pointer to revised line buffer pointer
373 * Assumes linePP is nonNULL
375 *************************************<->***********************************/
377 void _DtWmParseSkipWhitespaceC(unsigned char **linePP)
381 (mblen ((char *)*linePP, MB_CUR_MAX) == 1) &&
384 while (*linePP && isspace (**linePP))
390 } /* END OF FUNCTION _DtWmParseSkipWhitespaceC */
394 /*************************************<->*************************************
396 * _DtWmParseNextTokenC (linePP, SmBehavior)
401 * Returns the next quoted or whitespace-terminated nonquoted string in the
403 * Additional functionality added to GetString in that anything in a
404 * quoted string is considered sacred and nothing will be stripped from
405 * the middle of a quoted string.
410 * linePP = pointer to current line buffer pointer.
411 * SmBehavior = flag that enables parsing session manager hints if True.
412 * If False, this behaves as the normal OSF mwm GetString
418 * linePP = pointer to revised line buffer pointer.
424 * May alter the line buffer contents.
425 * Handles quoted strings and characters, removing trailing whitespace from
427 * Returns NULL string if the line is empty or is a comment.
428 * Code stolen from dtmwm.
430 *************************************<->***********************************/
433 _DtWmParseNextTokenC (
434 unsigned char **linePP,
438 /***********************************************************************
440 * The following code is duplicated from WmResParse.c (GetStringC)
441 * GetStringC is the HP DT version of GetString.
443 * It works here through the magic of #defines.
445 ***********************************************************************/
446 unsigned char *lineP = *linePP;
449 unsigned char *lnwsP;
450 unsigned int level = 0, checkLev, i, quoteLevel[MAX_QUOTE_DEPTH];
454 /* get rid of leading white space */
455 ScanWhitespace (&lineP);
458 * Return NULL if line is empty, whitespace, or begins with a comment.
462 ((chlen = mblen ((char *)lineP, MB_CUR_MAX)) < 1) ||
463 ((chlen == 1) && ((*lineP == '!') ||
464 ((!SmBehavior) && (*lineP == '#'))))
471 if ((chlen == 1) && (*lineP == '"'))
474 quoteLevel[level] = 1;
476 * Start beyond double quote and find the end of the quoted string.
477 * '\' quotes the next character.
478 * Otherwise, matching double quote or NULL terminates the string.
480 * We use lnwsP to point to the last non-whitespace character in the
481 * quoted string. When we have found the end of the quoted string,
482 * increment lnwsP and if lnwsP < endP, write NULL into *lnwsP.
483 * This removes any trailing whitespace without overwriting the
484 * matching quote, needed later. If the quoted string was all
485 * whitespace, then this will write a NULL at the beginning of the
486 * string that will be returned -- OK.
488 lnwsP = lineP++; /* lnwsP points to first '"' */
489 curP = endP = lineP; /* other pointers point beyond */
491 while ((*endP = *curP) &&
492 ((chlen = mblen ((char *)curP, MB_CUR_MAX)) > 0) &&
493 ((chlen > 1) || (*curP != '"')))
494 /* Haven't found matching quote yet.
495 * First byte of next character has been copied to endP.
499 if ((chlen == 1) && (*endP == '\\') &&
500 ((chlen = mblen ((char *)curP, MB_CUR_MAX)) > 0))
502 * copy first byte of quoted nonNULL character down.
503 * point curP to next byte
509 * Check to see if this is a quoted quote - if it is
510 * strip off a level - if not - it's sacred leave it alone
512 checkLev = PeekAhead((curP - 1), quoteLevel[level]);
515 if(quoteLevel[level] >= checkLev)
517 if (level > 0) level--;
519 else if (level < MAX_QUOTE_DEPTH)
522 quoteLevel[level] = checkLev;
525 for(i = 0;i < (checkLev - 2);i++)
527 *endP++ = *curP++;curP++;
539 /* Singlebyte character: character copy finished. */
542 /* whitespace character: leave lnwsP unchanged. */
547 /* non-whitespace character: point lnwsP to it. */
553 /* Multibyte (nonwhitespace) character: point lnwsP to it.
554 * Finish character byte copy.
565 #else /* MULTIBYTE */
567 /* get rid of leading white space */
568 ScanWhitespace (&lineP);
570 /* Return NULL if line is empty, whitespace, or begins with a comment. */
571 if ((lineP == NULL || *lineP == '\0') ||
572 (!SmBehavior && (*lineP == '#')))
581 quoteLevel[level] = 1;
583 * Start beyond double quote and find the end of the quoted string.
584 * '\' quotes the next character.
585 * Otherwise, matching double quote or NULL terminates the string.
587 * We use lnwsP to point to the last non-whitespace character in the
588 * quoted string. When we have found the end of the quoted string,
589 * increment lnwsP and if lnwsP < endP, write NULL into *lnwsP.
590 * This removes any trailing whitespace without overwriting the
591 * matching quote, needed later. If the quoted string was all
592 * whitespace, then this will write a NULL at the beginning of the
593 * string that will be returned -- OK.
595 lnwsP = lineP++; /* lnwsP points to first '"' */
596 curP = endP = lineP; /* other pointers point beyond */
598 while ((*endP = *curP) && (*endP != '"'))
599 /* haven't found matching quote yet */
601 /* point curP to next character */
603 if ((*endP == '\\') && (*curP != NULL))
604 /* shift quoted nonNULL character down and curP ahead */
609 * Check to see if this is a quoted quote - if it is
610 * strip off a level - if not - it's sacred leave it alone
612 checkLev = PeekAhead((curP - 1), quoteLevel[level]);
615 if(quoteLevel[level] >= checkLev)
617 if (level > 0) level--;
619 else if (level < MAX_QUOTE_DEPTH)
622 quoteLevel[level] = checkLev;
625 for(i = 0;i < (checkLev - 2);i++)
627 *endP++ = *curP++;curP++;
638 /* whitespace character: leave lnwsP unchanged. */
643 /* non-whitespace character: point lnwsP to it. */
648 #endif /* MULTIBYTE */
651 * Found matching quote or NULL.
652 * NULL out any trailing whitespace.
663 /* Unquoted string */
666 * Find the end of the nonquoted string.
667 * '\' quotes the next character.
668 * Otherwise, whitespace, NULL, or '#' terminates the string.
673 while ((*endP = *curP) &&
674 ((chlen = mblen ((char *)curP, MB_CUR_MAX)) > 0) &&
675 ((chlen > 1) || (!isspace (*curP) &&
676 (SmBehavior || (*curP != '#')))))
677 /* Haven't found whitespace or '#' yet.
678 * First byte of next character has been copied to endP.
682 if ((chlen == 1) && (*endP == '\\') &&
683 ((chlen = mblen ((char *)curP, MB_CUR_MAX)) > 0))
685 * copy first byte of quoted nonNULL character down.
686 * point curP to next byte
693 /* Multibyte character: finish character copy. */
701 #else /* MULTIBYTE */
702 while ((*endP = *curP) && !isspace (*endP) &&
703 (SmBehavior || (*endP != '#')))
705 /* point curP to next character */
707 if ((*endP == '\\') && (*curP != '\0'))
708 /* shift quoted nonNULL character down and curP ahead */
714 #endif /* MULTIBYTE */
718 * Three cases for *endP:
719 * '#' --> write NULL over # and point to NULL
721 * matching quote -> write NULL over char and point beyond
722 * NULL -> point to NULL
725 if (!SmBehavior && (*endP == '#'))
727 *endP = '\0'; /* write NULL over '#' */
728 *linePP = endP; /* point to NULL */
730 else if (*endP != '\0')
732 *endP = '\0'; /* write NULL over terminator */
733 *linePP = ++curP; /* point beyond terminator */
739 return ((unsigned char *)lineP);
741 } /* END OF FUNCTION _DtWmParseNextTokenC */
745 /*************************************<->*************************************
747 * (DtWmParseBuf *) _DtWmParseNewBuf (void)
752 * Allocates a new parse record for parsing.
761 * Return = ptr to parse buffer record, NULL if memory allocation
767 * Call this first before using the other DtWmp routines that require
768 * a parse buffer. Treat this as an opaque type; use the provided
769 * routines to create, access, and destroy this structure.
771 *************************************<->***********************************/
774 _DtWmParseNewBuf ( void )
777 DtWmpParseBuf *pWmPB;
779 pWmPB = (DtWmpParseBuf *) XtMalloc (sizeof (DtWmpParseBuf));
782 pWmPB->pchLine = (unsigned char *) XtMalloc (MAXLINE+1);
785 XtFree ((char *)pWmPB);
792 pWmPB->lineNumber = 0;
793 pWmPB->pchNext = pWmPB->pchLine;
794 pWmPB->cLineSize = MAXLINE+1;
796 *(pWmPB->pchLine) = '\0';
801 } /* END OF FUNCTION _DtWmParseNewBuf */
804 /*************************************<->*************************************
806 * (DtWmParseBuf *) _DtWmpIncBuf (pWmPB)
811 * Increases the size of the line buffer in the parse buffer
815 * pWmPB = pointer to a parse buffer
820 * Return = ptr to parse buffer record, NULL if memory allocation
827 *************************************<->***********************************/
829 static DtWmpParseBuf *
831 DtWmpParseBuf *pWmPB)
840 /* save index into old string */
841 ix = pWmPB->pchNext - pWmPB->pchLine;
844 pWmPB->pchLine = (unsigned char *)
845 XtRealloc ((char *)pWmPB->pchLine, (pWmPB->cLineSize + MAXLINE));
848 pWmPB->cLineSize += MAXLINE;
852 /* restore index into new string */
853 pWmPB->pchNext = pWmPB->pchLine + ix;
860 } /* END OF FUNCTION _DtWmpIncBuf */
863 /*************************************<->*************************************
865 * _DtWmParseDestroyBuf (pWmPB)
870 * Destroys a parse buffer record, freeing any allocated memory.
875 * pWmPB = ptr to previously allocated parse buffer
885 * Destroys parse buffers allocated by _DtWmParseNewBuf.
887 *************************************<->***********************************/
890 _DtWmParseDestroyBuf (
899 XtFree ((char *) pWmPB->pchLine);
901 XtFree ((char *) pWmPB);
904 } /* END OF FUNCTION _DtWmParseDestroyBuf */
907 /*************************************<->*************************************
909 * (unsigned char *) _DtWmParseSetLine (pWmPB, pch)
914 * Sets a line into the parse buffer structure. This is used in cases
915 * where parsing of an embedded string, usually a default, is done
916 * instead of parsing out of a file.
921 * pWmPB = previously allocated parse buffer
922 * pch = ptr to unsigned char string (zero terminated)
931 * This resets any previous setting of the file pointer. EOF wil be
932 * returned when the string pointed to by pch is exhausted.
934 * Resets line number count.
936 *************************************<->***********************************/
940 DtWmpParseBuf *pWmPB,
947 pWmPB->pchLine = pch;
948 pWmPB->pchNext = pWmPB->pchLine;
950 pWmPB->lineNumber = 0;
953 } /* END OF FUNCTION _DtWmParseSetLine */
956 /*************************************<->*************************************
958 * (FILE *) _DtWmParseSetFile (pWmPB, pFile)
963 * Sets the file pointer in a parse buffer. This is used when parsing
964 * from a file is required.
969 * pWmPB = pointer to a parse buffer
970 * pFile = pointer to an opened FILE
979 * You fopen the file first, then pass in the FILE * returned to this
982 * Resets line number count.
984 *************************************<->***********************************/
988 DtWmpParseBuf *pWmPB,
995 pWmPB->pchLine[0] = '\0';
996 pWmPB->pchNext = NULL;
997 pWmPB->pFile = pFile;
998 pWmPB->lineNumber = 0;
1001 } /* END OF FUNCTION _DtWmParseSetFile */
1004 /*************************************<->*************************************
1006 * (unsigned char *) _DtWmParseNextLine ( pWmPB )
1011 * Returns a pointer to the next line to parse.
1016 * pWmPB = pointer to a parse buffer
1021 * Return = pointer to next line to parse or NULL on EOF.
1028 *************************************<->***********************************/
1031 _DtWmParseNextLine (
1032 DtWmpParseBuf *pWmPB
1036 /***********************************************************************
1038 * The following code is duplicated from WmResParse.c (GetNextLine)
1039 * It works here through the magic of #defines.
1041 ***********************************************************************/
1043 register unsigned char *string;
1055 /* read fopened file */
1057 if ((string = (unsigned char *)
1058 fgets ((char *)line, MAXLINE, cfileP)) != NULL)
1061 if (strlen((char *)string) > (size_t)pWmPB->cLineSize)
1064 * Bump size of destination buffer
1066 pWmPB->cLineSize = 1 + strlen((char *)string);
1067 pWmPB->pchLine = (unsigned char *)
1068 XtRealloc ((char *)pWmPB->pchLine,
1069 (pWmPB->cLineSize));
1071 #endif /* PARSE_LIB */
1072 #ifndef NO_MULTIBYTE
1076 ((len = mblen((char *)string, MB_CUR_MAX)) > 0))
1078 mbtowc(&last, (char *)string, MB_CUR_MAX);
1083 mbtowc(&wdelim, &delim, MB_CUR_MAX);
1084 if (lastlen == 1 && last == wdelim)
1088 if (!fgets((char *)string, MAXLINE - (string - line), cfileP))
1093 ((len = mblen((char *)string, MB_CUR_MAX)) > 0))
1095 mbtowc(&last, (char *)string, MB_CUR_MAX);
1101 while (lastlen == 1 && last == wdelim);
1105 len = strlen((char *)string) - 2;
1106 if ((len > 0) && string[len] == '\\')
1109 string = &string[len];
1110 if (fgets((char *)string,
1111 MAXLINE - (string-line), cfileP) == NULL)
1113 len = strlen((char *)string) - 2;
1115 } while ((len >= 0) && string[len] == '\\');
1121 else if ((parseP != NULL) && (*parseP != '\0'))
1122 /* read parse string */
1125 if (strlen((char *)parseP) > (size_t)pWmPB->cLineSize)
1128 * Bump size of destination buffer
1130 pWmPB->cLineSize = 1 + strlen((char *)parseP);
1131 pWmPB->pchLine = (unsigned char *)
1132 XtRealloc ((char *)pWmPB->pchLine,
1133 (pWmPB->cLineSize));
1135 #endif /* PARSE_LIB */
1138 while ((*parseP != '\0') &&
1139 ((chlen = mblen ((char *)parseP, MB_CUR_MAX)) != 0) &&
1141 /* copy all but end-of-line and newlines to line buffer */
1149 *(string++) = *(parseP++);
1154 while ((*parseP != '\0') && (*parseP != '\n'))
1155 /* copy all but end-of-line and newlines to line buffer */
1157 *(string++) = *(parseP++);
1161 if (*parseP == '\n')
1175 /* update pchNext to get next line */
1176 pWmPB->pchNext = string;
1178 #endif /* PARSE_LIB */
1182 } /* END OF FUNCTION _DtWmParseNextLine */
1185 /*************************************<->*************************************
1187 * (unsigned char *) _DtWmParseCurrentChar (pWmPB)
1192 * Returns a pointer to the rest of the current line.
1197 * pWmPB = pointer to a parse buffer
1202 * Return = pointer to the rest of the current line
1207 * Useful in cases where you want to look at a char before getting the
1208 * next token or if you want to treat the rest of the line as a
1211 *************************************<->***********************************/
1214 _DtWmParseCurrentChar (
1215 DtWmpParseBuf *pWmPB
1219 return (pWmPB ? pWmPB->pchNext : (unsigned char *)NULL);
1221 } /* END OF FUNCTION _DtWmParseCurrentChar */
1225 /*************************************<->*************************************
1227 * (unsigned char *) _DtWmParseNextChar (pWmPB)
1232 * Advances the pointer to the next char and returns a pointer
1233 * to the new current char.
1238 * pWmPB = pointer to a parse buffer
1243 * Return = pointer to the rest of the current line
1249 *************************************<->***********************************/
1252 _DtWmParseNextChar (
1253 DtWmpParseBuf *pWmPB
1257 unsigned char *pch = NULL;
1263 (chlen = mblen((char *)pWmPB->pchNext, MB_CUR_MAX) > 0))
1265 pch = (pWmPB->pchNext += chlen);
1267 #else /* MULTIBYTE */
1268 if (pWmPB && pWmPB->pchNext && *pWmPB->pchNext)
1270 pch = ++pWmPB->pchNext;
1272 #endif /* MULTIBYTE */
1278 /*************************************<->*************************************
1280 * (int) _DtWmParseLineNumber (pWmPB)
1285 * Returns the number of the current line of what's being parsed.
1290 * pWmPB = ptr to parse buffer
1295 * Return = number of current line
1300 * Used for error reporting.
1302 * The line number is computed by counting '\n' characters.
1304 *************************************<->***********************************/
1307 _DtWmParseLineNumber (
1308 DtWmpParseBuf *pWmPB
1312 return (pWmPB ? pWmPB->lineNumber : 0);
1314 } /* END OF FUNCTION _DtWmParseLineNumber */
1317 /*************************************<->*************************************
1319 * _DtWmParseToLower (string)
1324 * Lower all characters in a string.
1329 * string = NULL-terminated character string or NULL
1334 * string = NULL-terminated lower case character string or NULL
1339 * Can handle multi-byte characters
1341 *************************************<->***********************************/
1343 void _DtWmParseToLower (unsigned char *string)
1345 unsigned char *pch = string;
1349 while ((chlen = mblen ((char *)pch, MB_CUR_MAX)) > 0)
1351 if ((chlen == 1) && (isupper (*pch)))
1353 *pch = tolower(*pch);
1358 while (*pch != NULL)
1362 *pch = tolower(*pch);
1368 } /* END OF FUNCTION _DtWmParseToLower */
1372 /*************************************<->*************************************
1374 * _DtWmParsePeekAhead (currentChar, currentLev)
1379 * Returns a new level value if this is a new nesting level of quoted string
1380 * Otherwise it returns a zero
1385 * currentChar = current position in the string
1386 * currentLev = current level of nesting
1391 * Returns either a new level of nesting or zero if the character is copied in
1397 *************************************<->***********************************/
1398 unsigned int _DtWmParsePeekAhead(unsigned char *currentChar,
1399 unsigned int currentLev)
1403 Boolean done = False;
1404 unsigned int tmpLev = 1;
1408 while (((chlen = mblen ((char *)currentChar, MB_CUR_MAX)) > 0) &&
1409 (chlen == 1) && ((*currentChar == '"') || (*currentChar == '\\'))
1414 if(((chlen = mblen ((char *)currentChar, MB_CUR_MAX)) > 0) &&
1416 ((*currentChar == '"') || (*currentChar == '\\')))
1419 if(*currentChar == '"')
1430 while((*currentChar != NULL) && (done == False) &&
1431 ((*currentChar == '"') || (*currentChar == '\\')))
1434 if((*currentChar != NULL) &&
1435 ((*currentChar == '"') || (*currentChar == '\\')))
1438 if(*currentChar == '"')
1448 #endif /*MULTIBYTE*/
1451 * Figure out if this is truly a new level of nesting - else ignore it
1452 * This section probably could do some error checking and return -1
1453 * If so, change type of routine from unsigned int to int
1463 } /* END OF FUNCTION _DtWmParsePeekAhead */
1467 /*************************************<->*************************************
1469 * (unsigned char *) _DtWmParseFilenameExpand (pchFilename)
1474 * Returns a copy of a file name with environment variables
1480 * pchFilename = ptr to a zero terminated character string (filename)
1485 * Return = ptr to a new file name with environment variables
1491 * The passed in string is temporarily modified inside here.
1493 * Free the returned string with XtFree().
1495 * Returns NULL on a memory allocation error.
1497 * Environment variables that can't be expanded are removed from
1498 * the returned copy.
1500 * If no environment variables, you get a copy of the string back.
1502 *************************************<->***********************************/
1504 _DtWmParseFilenameExpand (
1505 unsigned char *pchFilename
1509 unsigned char *pchN, *pchNew, *pchO;
1510 unsigned char *pchEnv, *pchEnv0, *pchEnv1;
1511 unsigned char chSave;
1513 unsigned char pchBrk[] = { DTWM_CHAR_ENVIRONMENT,
1514 DTWM_CHAR_DIRECTORY,
1518 len = strlen ((char *)pchFilename);
1519 pchNew = (unsigned char *) XtMalloc (1+len);
1524 while (pchNew && pchO && *pchO)
1526 /* find next environment variable */
1527 pchEnv0 = (unsigned char *)
1528 strchr ((char *)pchO, (int) DTWM_CHAR_ENVIRONMENT);
1531 /* length to this point */
1534 /* copy up to environment character */
1537 memcpy (&pchNew[ix], pchO, n);
1541 /* skip environment character */
1544 /* end of variable is at one of:
1545 * start of next variable,
1546 * start of next directory,
1549 pchEnv1 = (unsigned char *)
1550 strpbrk ((char *)pchEnv0, (char *)pchBrk);
1554 /* next string starts after this one */
1556 n = pchEnv1 - pchEnv0 + 1;
1558 /* replace this char with NULL for now */
1564 /* This environment variable is the last thing on
1565 * the line. Signal all done.
1567 n = strlen ((char *) pchO);
1571 pchEnv = (unsigned char *) getenv ((char *)pchEnv0);
1574 nx = strlen ((char *) pchEnv);
1578 pchNew = (unsigned char *)
1579 XtRealloc ((char *)pchNew, 1+len);
1583 memcpy (&pchNew[ix], pchEnv, nx);
1597 /* keep a kosher string */
1602 /* copy the rest of the string */
1603 n = strlen ((char *) pchO);
1604 memcpy (&pchNew[ix], pchO, n);
1607 /* remember the NULL! (a famous battle cry) */
1608 pchNew[ix + n] = '\0';
1614 } /* END OF FUNCTION _DtWmParseFilenameExpand */
1617 /*************************************<->*************************************
1619 * unsigned char * _DtWmParseExpandEnvironmentVariables (pch, pchBrk)
1624 * Expands environment variables in a string.
1629 * pch = ptr to a zero terminated character string
1630 * pchBrk = array of "break" characters (see strpbrk()).
1631 * defaults are used if this is NULL.
1635 * Return = string with expanded environment variables. (free with XtFree)
1636 * NULL string if no environment variables or backslashes
1637 * found in the string passed in.
1642 * Free returned string with XtFree()
1644 * Environment variables that can't be expanded are removed from
1645 * the returned copy.
1647 * Default delimiter set is [Space], [Tab], '$', [Newline], '\', '/'.
1649 * Variables of form $(..) and ${..} supported.
1651 * A backslash '\' in front of any character quotes it. The backslash
1652 * is removed in the returned string. A literal backslash needs to be
1653 * quoted with a backslash.
1655 *************************************<->***********************************/
1657 _DtWmParseExpandEnvironmentVariables (
1659 unsigned char *pchBrk
1665 #else /* MULTIBYTE */
1666 int chlen = 1; /* length of character is always '1' */
1667 #endif /* MULTIBYTE */
1668 unsigned char *pchStart;
1669 unsigned char chSave;
1670 unsigned char *pchEnvStart;
1671 unsigned char *pchEnvValue;
1672 unsigned char *pchReturn = NULL;
1673 unsigned char *pchNext;
1674 unsigned char *pchBreak;
1676 Boolean bAlreadyAdvanced;
1683 static unsigned char pchDefaultBrk[] = {
1684 DTWM_CHAR_ENVIRONMENT,
1688 DTWM_CHAR_BACKSLASH,
1689 DTWM_CHAR_DIRECTORY,
1691 unsigned char pchParenBrk[] = {
1694 unsigned char pchBraceBrk[] = {
1698 /* There needs to be something to look at */
1703 lenOriginal = strlen ((char *)pch);
1705 chlen = mblen ((char *)pch, MB_CUR_MAX);
1706 #endif /* MULTIBYTE */
1709 while (*pch && (chlen > 0))
1713 bAlreadyAdvanced = False;
1716 case DTWM_CHAR_BACKSLASH:
1718 * Copy up to start of quoted char
1722 lenReturn = lenOriginal + 1;
1723 pchReturn = (unsigned char *)
1724 XtMalloc (lenReturn * sizeof (unsigned char));
1725 pchReturn[0] = '\0';
1729 strcat ((char *) pchReturn, (char *)pchStart);
1734 * The next character is "escaped", skip over it.
1736 pchStart = pch += chlen;
1738 chlen = mblen ((char *)pch, MB_CUR_MAX);
1739 #endif /* MULTIBYTE */
1742 case DTWM_CHAR_ENVIRONMENT:
1743 /* save start of environment variable */
1747 chlen = mblen ((char *)pch, MB_CUR_MAX);
1748 #endif /* MULTIBYTE */
1751 * Copy up to start of environment variable
1755 lenReturn = lenOriginal + 1;
1756 pchReturn = (unsigned char *)
1757 XtMalloc (lenReturn * sizeof (unsigned char));
1758 pchReturn[0] = '\0';
1763 lenSave = strlen ((char *)pchReturn);
1765 lenNonEnv = pchEnvStart - pchStart;
1766 memcpy (&pchReturn[lenSave], pchStart, lenNonEnv);
1767 pchReturn[lenSave+lenNonEnv] = '\0';
1770 * Determine how we find the end of this
1771 * environment variable.
1775 (*pch == DTWM_CHAR_L_PAREN))
1779 chlen = mblen ((char *)pch, MB_CUR_MAX);
1780 #endif /* MULTIBYTE */
1781 pchBreak = pchParenBrk;
1784 else if ((chlen == 1) &&
1785 (*pch == DTWM_CHAR_L_BRACE))
1789 chlen = mblen ((char *)pch, MB_CUR_MAX);
1790 #endif /* MULTIBYTE */
1791 pchBreak = pchBraceBrk;
1794 else if (pchBrk && *pchBrk)
1800 pchBreak = pchDefaultBrk;
1804 * Look for end of environment variable
1806 pchNext = (unsigned char *)
1807 strpbrk ((char *)pch, (char *)pchBreak);
1811 /* it's the rest of the string */
1814 pchNext = pch + strlen ((char *) pch);
1818 /* temporarily put a string terminator here */
1824 * Lookup environment variable
1826 lenEnvVar = strlen ((char *)pch);
1827 pchEnvValue = (unsigned char *) getenv ((char *)pch);
1832 * Insure there's enough room in the return string
1834 lenEnvValue = strlen ((char *)pchEnvValue);
1837 lenReturn = lenOriginal + 1 - lenEnvVar +
1839 pchReturn = (unsigned char *)
1840 XtMalloc (lenReturn * sizeof (unsigned char));
1841 pchReturn[0] = '\0';
1845 lenReturn = lenReturn + 1 - lenEnvVar +
1847 pchReturn = (unsigned char *)
1848 XtRealloc ((char *)pchReturn,
1849 lenReturn * sizeof (unsigned char));
1853 * Tack it onto the return string
1855 strcat ((char *)pchReturn, (char *)pchEnvValue);
1859 * Advance the pointer for the next pass
1863 /* restore saved character */
1868 * If this was a closing paren, then skip it
1873 chlen = mblen ((char *)pchNext, MB_CUR_MAX);
1874 #endif /* MULTIBYTE */
1878 pchStart = pch = pchNext;
1880 chlen = mblen ((char *)pch, MB_CUR_MAX);
1881 #endif /* MULTIBYTE */
1883 * We're already pointing at the next character
1884 * to process, don't advance again!
1886 bAlreadyAdvanced = True;
1891 /* this character is not interesting */
1896 * Move to the next character if we're not already
1899 if (!bAlreadyAdvanced)
1903 chlen = mblen ((char *)pch, MB_CUR_MAX);
1904 #endif /* MULTIBYTE */
1911 chlen = mblen ((char *)pch, MB_CUR_MAX);
1913 #endif /* MULTIBYTE */
1916 if (pchReturn && *pchStart)
1919 * Copy remaining parts of the string
1921 strcat ((char *)pchReturn, (char *)pchStart);
1926 } /* END OF FUNCTION _DtWmParseExpandEnvironmentVariables */
1930 /******************************<->*************************************
1932 * _DtWmParseMakeQuotedString (pchLine)
1937 * Encapsulates the passed in "line" into a string argument quoted
1938 * by double quotes. Special characters are "escaped" as needed.
1942 * pchLine = ptr to string to enclose in quotes
1946 * Return = ptr to quoted string
1950 * Returned string should be freed with XtFree().
1952 ******************************<->***********************************/
1955 _DtWmParseMakeQuotedString (unsigned char *pchLine)
1957 unsigned char *pchRet;
1965 iLen0 = strlen ((char *)pchLine);
1966 iLen1 = iLen0 + 2; /* for starting, ending quotes */
1968 for (i=0; i < iLen0; i++)
1971 * Count special chars to get estimate of new length
1974 chlen = mblen ((char *) &pchLine[i], MB_CUR_MAX);
1976 ((pchLine[i] == '\\') ||
1977 (pchLine[i] == '"')))
1989 #else /* MULTIBYTE */
1990 if ((pchLine[i] == '\\') ||
1991 (pchLine[i] == '"'))
1995 #endif /* MULTIBYTE */
1998 pchRet = (unsigned char *) XtMalloc (1+iLen1);
2002 pchRet[0] = '"'; /* starting quote */
2004 * Copy chars from old string to new one
2006 for (i=0, j=1; i < iLen0; i++, j++)
2009 chlen = mblen ((char *) &pchLine[i], MB_CUR_MAX);
2011 ((pchLine[i] == '\\') ||
2012 (pchLine[i] == '"')))
2014 /* quote next char */
2021 else while (chlen > 1)
2023 /* copy first bytes of multibyte char */
2024 pchRet[j++] = pchLine[i++];
2027 #else /* MULTIBYTE */
2028 if ((pchLine[i] == '\\') ||
2029 (pchLine[i] == '"'))
2031 /* quote next char */
2034 #endif /* MULTIBYTE */
2036 pchRet[j] = pchLine[i];
2038 pchRet[j++] = '"'; /* ending quote */
2039 pchRet[j] = '\0'; /* end of string */
2044 } /* END OF FUNCTION _DtWmParseMakeQuotedString */
2047 /*==================== END OF FILE WmParse.c ====================*/