dtcm: Coverity 88107
[oweals/cde.git] / cde / programs / dtwm / WmParse.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
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)
10  * any later version.
11  *
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
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these libraries and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /******************************<+>*************************************
24  **********************************************************************
25  **
26  **  File:        WmParse.c
27  **
28  **  Project:     HP/Motif Workspace Manager (dtwm)
29  **
30  **  Description:
31  **  -----------
32  **  This file contains the generic parsing routines
33  **
34  **
35  *********************************************************************
36  **
37  ** (c) Copyright 1987, 1988, 1989, 1990, 1991 HEWLETT-PACKARD COMPANY
38  ** ALL RIGHTS RESERVED
39  **
40  **********************************************************************
41  **********************************************************************
42  **
43  **
44  **********************************************************************
45  ******************************<+>*************************************/
46
47 /* ANSI C definitions,  This should be the first thing in WmGlobal.h */
48 #ifdef __STDC__
49 #define Const const
50 #else
51 #define Const /**/
52 #endif
53
54
55 /*
56  * Included Files:
57  */
58 #include <stdio.h>
59 #include <X11/Intrinsic.h>
60 #include "WmGlobal.h"
61 #include "WmParse.h"
62 #include "WmParseP.h"
63 #include <stdlib.h>
64 #include <ctype.h>
65
66 /*
67  * Internal routines
68  */
69
70 static DtWmpParseBuf * _DtWmpIncBuf (
71     DtWmpParseBuf *pWmPB);
72
73
74
75 #ifndef MAXLINE
76 #define MAXLINE         (MAXWMPATH+1)
77 #endif
78 #define MAX_QUOTE_DEPTH 10
79
80 /*
81  *  This flags non-OSF code in those sections that were lifted
82  *  from mwm.
83  */
84 #define PARSE_LIB
85
86
87 /*
88  * Defines used to maintain code similarity between OSF/mwm source
89  * routines and these routines.
90  */
91 #define cfileP                  ((pWmPB)->pFile)
92 #define linec                   ((pWmPB)->lineNumber)
93 #define line                    ((pWmPB)->pchLine)
94 #define parseP                  ((pWmPB)->pchNext)
95 #define ScanWhitespace(s)       (_DtWmParseSkipWhitespaceC(s))
96 #define PeekAhead(s,l)          (_DtWmParsePeekAhead(s,l))
97
98 \f
99 /*************************************<->*************************************
100  *
101  *  _DtWmParseSkipWhitespace(pWmPB)
102  *
103  *
104  *  Description:
105  *  -----------
106  *  Scan the current string, skipping over all white space characters.
107  *
108  *
109  *  Inputs:
110  *  ------
111  *  pWmPB = ptr to parse buffer
112  *
113  * 
114  *  Outputs:
115  *  -------
116  *  pWmPB = parse buffer modified; current line ptr may be moved.
117  *
118  *
119  *  Comments:
120  *  --------
121  *  Assumes there's a current line in the parse buffer
122  * 
123  *************************************<->***********************************/
124
125 void _DtWmParseSkipWhitespace(DtWmpParseBuf *pWmPB)
126 {
127     _DtWmParseSkipWhitespaceC (&(pWmPB->pchNext));
128
129 } /* END OF FUNCTION _DtWmParseSkipWhitespace */
130
131 \f
132 /*************************************<->*************************************
133  *
134  *  _DtWmParseNextToken (pWmPB)
135  *
136  *
137  *  Description:
138  *  -----------
139  *  Returns the next quoted or whitespace-terminated nonquoted string in the
140  *  current line buffer.
141  *
142  *
143  *  Inputs:
144  *  ------
145  *  pWmPB       = ptr to parse buffer
146  *
147  * 
148  *  Outputs:
149  *  -------
150  *  Return      = ptr to null terminated string.
151  *  pWmPB       = current line modified internally.
152  *
153  *
154  *  Comments:
155  *  --------
156  *  May alter the line buffer contents.
157  *  Handles quoted strings and characters, removing trailing whitespace from
158  *  quoted strings.
159  *  Returns NULL string if the line is empty or is a comment.
160  *  Does not use session manager style algorithm for dealing with
161  *  quoted strings.
162  * 
163  *************************************<->***********************************/
164
165 unsigned char *
166 _DtWmParseNextToken (
167     DtWmpParseBuf *pWmPB 
168     )
169 {
170     return (_DtWmParseNextTokenC (&(pWmPB->pchNext), False));
171 }
172
173 \f
174 /*************************************<->*************************************
175  *
176  *  _DtWmParseNextTokenExpand (pWmPB)
177  *
178  *
179  *  Description:
180  *  -----------
181  *  Returns the next quoted or whitespace-terminated nonquoted string in the
182  *  current line buffer. Environment variables found in the are expanded.
183  *  Characters quoted by '\' are passed through unaffected with the 
184  *  quoting '\' removed.
185  *
186  *
187  *  Inputs:
188  *  ------
189  *  pWmPB       = ptr to parse buffer
190  *
191  * 
192  *  Outputs:
193  *  -------
194  *  Return      = ptr to null terminated string.
195  *                Free this string with XtFree().
196  *  pWmPB       = current line modified internally.
197  *
198  *
199  *  Comments:
200  *  --------
201  *  May alter the line buffer contents.
202  *  Handles quoted strings and characters, removing trailing whitespace from
203  *  quoted strings.
204  *  Returns NULL string if the line is empty or is a comment.
205  * 
206  *************************************<->***********************************/
207
208 unsigned char *
209 _DtWmParseNextTokenExpand (
210     DtWmpParseBuf *pWmPB 
211     )
212 {
213     unsigned char *pch;
214     unsigned char *pchReturn = NULL;
215
216     /* isolate the next token */
217     pch = _DtWmParseNextTokenC (&(pWmPB->pchNext), False);
218
219     /* expand environment variables, a copy of the string is returned */
220     pchReturn = _DtWmParseExpandEnvironmentVariables (pch, NULL);
221
222     /* 
223      * If a token was found, but no copy returned, there were no 
224      * environment variables. This routine needs to return a copy, 
225      * so make one now.
226      */
227     if (pch && !pchReturn) 
228         pchReturn = (unsigned char *) XtNewString ((String) pch);
229
230     return (pchReturn);
231 }
232
233 \f
234 /*************************************<->*************************************
235  *
236  *  _DtWmParseBackUp (pWmPB, pchTok)
237  *
238  *
239  *  Description:
240  *  -----------
241  *  Backs up to the previous token (the one before pchTok) 
242  *
243  *
244  *  Inputs:
245  *  ------
246  *  pWmPB       = ptr to parse buffer
247  *  pchTok      = ptr to a token in the parse buffer
248  *
249  * 
250  *  Outputs:
251  *  -------
252  *  Returns     = ptr to prev token
253  *
254  *
255  *  Comments:
256  *  --------
257  *  Operates on the line buffer in the pWmPB structure. Backs up
258  *  the next pointer and writes a space over the interpolated
259  *  NULL (if any).
260  * 
261  *************************************<->***********************************/
262
263 unsigned char *
264 _DtWmParseBackUp (
265     DtWmpParseBuf *pWmPB,
266     unsigned char *pchTok
267     )
268 {
269     if ((pchTok > pWmPB->pchLine) &&
270         (pchTok < (pWmPB->pchLine +  pWmPB->cLineSize)))
271     {
272         unsigned char *pch;
273         unsigned char *pchLast;
274         int chlen;
275
276         pch = pchLast = pWmPB->pchLine;
277
278         /*
279          * Search from beginning (because of multibyte chars) to
280          * find the token before the string we're interested in.
281          */
282         while ((pch < pchTok))
283         {
284             chlen = mblen ((char *)pch, MB_CUR_MAX);
285             if (*pch == '\0')
286             {
287                 pch++;
288                 if (pch == pchTok)
289                 {
290                     /*
291                      * Found the NULL preceding the string passed in!
292                      * Replace it with a blank and return the previous
293                      * token (pointed to by pchLast).
294                      */
295                     *(pch - 1) = DTWM_CHAR_SPACE;
296                     break;
297                 }
298                 else
299                 {
300                     /* 
301                      * Remember the beginning of this token.
302                      */
303                     pchLast = pch;
304                 }
305             }
306             else if (chlen < 1)
307             {
308                 break;
309             }
310             else
311             {
312                 pch += chlen;
313             }
314         }
315
316         pWmPB->pchNext = pchLast;
317     }
318     return (pWmPB->pchNext);
319 }
320
321
322 \f
323 /*************************************<->*************************************
324  *
325  *  _DtWmParseSkipWhitespaceC(linePP)
326  *
327  *
328  *  Description:
329  *  -----------
330  *  Scan the string, skipping over all white space characters.
331  *
332  *
333  *  Inputs:
334  *  ------
335  *  linePP = nonNULL pointer to current line buffer pointer
336  *
337  * 
338  *  Outputs:
339  *  -------
340  *  linePP = nonNULL pointer to revised line buffer pointer
341  *
342  *
343  *  Comments:
344  *  --------
345  *  Assumes linePP is nonNULL
346  * 
347  *************************************<->***********************************/
348
349 void _DtWmParseSkipWhitespaceC(unsigned char  **linePP)
350 {
351     while (*linePP && 
352            (mblen ((char *)*linePP, MB_CUR_MAX) == 1) && 
353            isspace (**linePP))
354     {
355         (*linePP)++;
356     }
357
358 } /* END OF FUNCTION _DtWmParseSkipWhitespaceC */
359
360
361 \f
362 /*************************************<->*************************************
363  *
364  *  _DtWmParseNextTokenC (linePP, SmBehavior)
365  *
366  *
367  *  Description:
368  *  -----------
369  *  Returns the next quoted or whitespace-terminated nonquoted string in the
370  *  line buffer.
371  *  Additional functionality added to GetString in that anything in a
372  *  quoted string is considered sacred and nothing will be stripped from
373  *  the middle of a quoted string.
374  *
375  *
376  *  Inputs:
377  *  ------
378  *  linePP =  pointer to current line buffer pointer.
379  *  SmBehavior = flag that enables parsing session manager hints  if True.
380  *               If False, this behaves as the normal OSF mwm GetString
381  *               routine.
382  *
383  * 
384  *  Outputs:
385  *  -------
386  *  linePP =  pointer to revised line buffer pointer.
387  *  Return =  string 
388  *
389  *
390  *  Comments:
391  *  --------
392  *  May alter the line buffer contents.
393  *  Handles quoted strings and characters, removing trailing whitespace from
394  *  quoted strings.
395  *  Returns NULL string if the line is empty or is a comment.
396  *  Code stolen from dtmwm.
397  * 
398  *************************************<->***********************************/
399
400 unsigned char *
401 _DtWmParseNextTokenC (
402     unsigned char **linePP, 
403     Boolean SmBehavior 
404     )
405 {
406 /***********************************************************************
407  *
408  * The following code is duplicated from WmResParse.c (GetStringC)
409  * GetStringC is the HP DT version of GetString. 
410  *
411  * It works here through the magic of #defines.
412  *
413  ***********************************************************************/
414     unsigned char *lineP = *linePP;
415     unsigned char *endP;
416     unsigned char *curP;
417     unsigned char *lnwsP;
418     unsigned int  level = 0, checkLev, i, quoteLevel[MAX_QUOTE_DEPTH];
419     int            chlen;
420
421     /* get rid of leading white space */
422     ScanWhitespace (&lineP);
423
424     /*
425      * Return NULL if line is empty, whitespace, or begins with a comment.
426      */
427     if (
428         *lineP == '\0' ||
429         ((chlen = mblen ((char *)lineP, MB_CUR_MAX)) < 1) ||
430         ((chlen == 1) && ((*lineP == '!') || 
431                           ((!SmBehavior) && (*lineP == '#'))))
432        )
433     {
434         *linePP = lineP;
435         return (NULL);
436     }
437
438     if ((chlen == 1) && (*lineP == '"'))
439     /* Quoted string */
440     {
441         quoteLevel[level] = 1;  
442         /*
443          * Start beyond double quote and find the end of the quoted string.
444          * '\' quotes the next character.
445          * Otherwise,  matching double quote or NULL terminates the string.
446          *
447          * We use lnwsP to point to the last non-whitespace character in the
448          * quoted string.  When we have found the end of the quoted string,
449          * increment lnwsP and if lnwsP < endP, write NULL into *lnwsP.
450          * This removes any trailing whitespace without overwriting the 
451          * matching quote, needed later.  If the quoted string was all 
452          * whitespace, then this will write a NULL at the beginning of the 
453          * string that will be returned -- OK.
454          */
455         lnwsP = lineP++;                /* lnwsP points to first '"' */
456         curP = endP = lineP;            /* other pointers point beyond */
457
458         while ((*endP = *curP) &&
459                ((chlen = mblen ((char *)curP, MB_CUR_MAX)) > 0) &&
460                ((chlen > 1) || (*curP != '"')))
461         /* Haven't found matching quote yet.
462          * First byte of next character has been copied to endP.
463          */
464         {
465             curP++;
466             if ((chlen == 1) && (*endP == '\\') && 
467                 ((chlen = mblen ((char *)curP, MB_CUR_MAX)) > 0))
468             /* character quote:
469              * copy first byte of quoted nonNULL character down.
470              * point curP to next byte
471              */
472             {
473                 if (SmBehavior)
474                 {
475                     /*
476                      * Check to see if this is a quoted quote - if it is
477                      * strip off a level - if not - it's sacred leave it alone
478                      */
479                     checkLev = PeekAhead((curP - 1), quoteLevel[level]);
480                     if(checkLev > 0)
481                     {
482                         if(quoteLevel[level] >= checkLev)
483                         {
484                             if (level > 0) level--;
485                         }
486                         else if (level < MAX_QUOTE_DEPTH)
487                         {
488                             level++;
489                             quoteLevel[level] = checkLev;
490                         }
491                         
492                         for(i = 0;i < (checkLev - 2);i++)
493                         {
494                             *endP++ = *curP++;curP++;
495                         }
496                         *endP = *curP++;
497                     }
498                 }
499                 else 
500                 {
501                 *endP = *curP++;
502                 }
503             }
504
505             if (chlen == 1)
506             /* Singlebyte character:  character copy finished. */
507             {
508                 if (isspace (*endP))
509                 /* whitespace character:  leave lnwsP unchanged. */
510                 {
511                     endP++;
512                 }
513                 else
514                 /* non-whitespace character:  point lnwsP to it. */
515                 {
516                     lnwsP = endP++;
517                 }
518             }
519             else if (chlen > 1)
520             /* Multibyte (nonwhitespace) character:  point lnwsP to it.
521              * Finish character byte copy.
522              */
523             {
524                 lnwsP = endP++;
525                 while (--chlen)
526                 {
527                     *endP++ = *curP++;
528                     lnwsP++;
529                 }
530             }
531         }
532
533         /*
534          *  Found matching quote or NULL.  
535          *  NULL out any trailing whitespace.
536          */
537
538         lnwsP++;
539         if (lnwsP < endP)
540         {
541             *lnwsP = '\0';
542         }
543     }
544
545     else
546     /* Unquoted string */
547     {
548         /* 
549          * Find the end of the nonquoted string.
550          * '\' quotes the next character.
551          * Otherwise,  whitespace, NULL, or '#' terminates the string.
552          */
553         curP = endP = lineP;
554
555         while ((*endP = *curP) &&
556                ((chlen = mblen ((char *)curP, MB_CUR_MAX)) > 0) &&
557                ((chlen > 1) || (!isspace (*curP) && 
558                                 (SmBehavior || (*curP != '#')))))
559         /* Haven't found whitespace or '#' yet.
560          * First byte of next character has been copied to endP.
561          */
562         {
563             curP++;
564             if ((chlen == 1) && (*endP == '\\') && 
565                 ((chlen = mblen ((char *)curP, MB_CUR_MAX)) > 0))
566             /* character quote:
567              * copy first byte of quoted nonNULL character down.
568              * point curP to next byte
569              */
570             {
571                 *endP = *curP++;
572             }
573             endP++;
574             if (chlen > 1)
575             /* Multibyte character:  finish character copy. */
576             {
577                 while (--chlen)
578                 {
579                     *endP++ = *curP++;
580                 }
581             }
582         }
583     }
584
585     /*
586      * Three cases for *endP:
587      *   '#' --> write NULL over # and point to NULL
588      *   whitespace or
589      *     matching quote -> write NULL over char and point beyond
590      *   NULL -> point to NULL 
591      */
592
593     if (!SmBehavior && (*endP == '#'))
594     {
595         *endP = '\0';       /* write NULL over '#' */
596         *linePP = endP;     /* point to NULL */
597     }
598     else if (*endP != '\0')
599     {
600         *endP = '\0';       /* write NULL over terminator */
601         *linePP = ++curP;   /* point beyond terminator */
602     }
603     else
604     {
605         *linePP = endP;
606     }
607     return ((unsigned char *)lineP);
608
609 } /* END OF FUNCTION _DtWmParseNextTokenC */
610
611
612 \f
613 /*************************************<->*************************************
614  *
615  *  (DtWmParseBuf *) _DtWmParseNewBuf (void)
616  *
617  *
618  *  Description:
619  *  -----------
620  *  Allocates a new parse record for parsing. 
621  *
622  *  Inputs:
623  *  ------
624  *  none 
625  *
626  * 
627  *  Outputs:
628  *  -------
629  *  Return      = ptr to parse buffer record, NULL if memory allocation
630  *                error.
631  *
632  *
633  *  Comments:
634  *  --------
635  *  Call this first before using the other DtWmp routines that require
636  *  a parse buffer. Treat this as an opaque type; use the provided 
637  *  routines to create, access, and destroy this structure.
638  * 
639  *************************************<->***********************************/
640
641 DtWmpParseBuf * 
642 _DtWmParseNewBuf ( void )
643
644 {
645     DtWmpParseBuf *pWmPB;
646
647     pWmPB = (DtWmpParseBuf *) XtMalloc (sizeof (DtWmpParseBuf));
648     if (pWmPB)
649     {
650         pWmPB->pchLine = (unsigned char *) XtMalloc (MAXLINE+1);
651         if (!pWmPB->pchLine)
652         {
653             XtFree ((char *)pWmPB);
654             pWmPB = NULL;
655         }
656     }
657
658     if (pWmPB)
659     {
660         pWmPB->lineNumber = 0;
661         pWmPB->pchNext = pWmPB->pchLine;
662         pWmPB->cLineSize = MAXLINE+1;
663         pWmPB->pFile = NULL;
664         *(pWmPB->pchLine) = '\0';
665     }
666
667     return (pWmPB);
668
669 } /* END OF FUNCTION _DtWmParseNewBuf */
670
671 \f
672 /*************************************<->*************************************
673  *
674  *  (DtWmParseBuf *) _DtWmpIncBuf (pWmPB)
675  *
676  *
677  *  Description:
678  *  -----------
679  *  Increases the size of the line buffer in the parse buffer
680  *
681  *  Inputs:
682  *  ------
683  *  pWmPB       = pointer to a parse buffer
684  *
685  * 
686  *  Outputs:
687  *  -------
688  *  Return      = ptr to parse buffer record, NULL if memory allocation
689  *                error.
690  *
691  *
692  *  Comments:
693  *  --------
694  * 
695  *************************************<->***********************************/
696
697 static DtWmpParseBuf * 
698 _DtWmpIncBuf (
699     DtWmpParseBuf *pWmPB)
700
701 {
702     if (pWmPB)
703     {
704         int ix;
705
706         if (pWmPB->pFile)
707         {
708             /* save index into old string */
709             ix = pWmPB->pchNext - pWmPB->pchLine;
710         }
711
712         pWmPB->pchLine = (unsigned char *) 
713             XtRealloc ((char *)pWmPB->pchLine, (pWmPB->cLineSize + MAXLINE));
714         if (pWmPB->pchLine)
715         {
716             pWmPB->cLineSize += MAXLINE;
717
718             if (pWmPB->pFile)
719             {
720                 /* restore index into new string */
721                 pWmPB->pchNext = pWmPB->pchLine + ix;
722             }
723         }
724     }
725
726     return (pWmPB);
727
728 } /* END OF FUNCTION _DtWmpIncBuf */
729
730 \f
731 /*************************************<->*************************************
732  *
733  *  _DtWmParseDestroyBuf (pWmPB)
734  *
735  *
736  *  Description:
737  *  -----------
738  *  Destroys a parse buffer record, freeing any allocated memory.
739  *
740  *
741  *  Inputs:
742  *  ------
743  *  pWmPB       = ptr to previously allocated parse buffer
744  *
745  * 
746  *  Outputs:
747  *  -------
748  *  none
749  *
750  *
751  *  Comments:
752  *  --------
753  *  Destroys parse buffers allocated by _DtWmParseNewBuf.
754  * 
755  *************************************<->***********************************/
756
757 void 
758 _DtWmParseDestroyBuf (
759     DtWmpParseBuf *pWmPB
760     )
761
762 {
763     if (pWmPB)
764     {
765         if (pWmPB->pchLine)
766         {
767             XtFree ((char *) pWmPB->pchLine);
768         }
769         XtFree ((char *) pWmPB);
770     }
771
772 } /* END OF FUNCTION _DtWmParseDestroyBuf */
773
774 \f
775 /*************************************<->*************************************
776  *
777  *  (unsigned char *) _DtWmParseSetLine (pWmPB, pch)
778  *
779  *
780  *  Description:
781  *  -----------
782  *  Sets a line into the parse buffer structure. This is used in cases
783  *  where parsing of an embedded string, usually a default, is done
784  *  instead of parsing out of a file.
785  *
786  *
787  *  Inputs:
788  *  ------
789  *  pWmPB       = previously allocated parse buffer 
790  *  pch         = ptr to unsigned char string (zero terminated)
791  * 
792  *  Outputs:
793  *  -------
794  *  Return      = pch
795  *
796  *
797  *  Comments:
798  *  --------
799  *  This resets any previous setting of the file pointer. EOF wil be 
800  *  returned when the string pointed to by pch is exhausted.
801  *
802  *  Resets line number count.
803  * 
804  *************************************<->***********************************/
805
806 void 
807 _DtWmParseSetLine (
808     DtWmpParseBuf  *pWmPB,
809     unsigned char  *pch
810     )
811
812 {
813     if (pWmPB)
814     {
815         pWmPB->pchLine = pch;
816         pWmPB->pchNext = pWmPB->pchLine;
817         pWmPB->pFile = NULL;
818         pWmPB->lineNumber = 0;
819     }
820
821 } /* END OF FUNCTION _DtWmParseSetLine */
822
823 \f
824 /*************************************<->*************************************
825  *
826  *  (FILE *) _DtWmParseSetFile (pWmPB, pFile)
827  *
828  *
829  *  Description:
830  *  -----------
831  *  Sets the file pointer in a parse buffer. This is used when parsing 
832  *  from a file is required. 
833  *
834  *
835  *  Inputs:
836  *  ------
837  *  pWmPB       = pointer to a parse buffer
838  *  pFile       = pointer to an opened FILE
839  * 
840  *  Outputs:
841  *  -------
842  *  Return      = pFile
843  *
844  *
845  *  Comments:
846  *  --------
847  *  You fopen the file first, then pass in the FILE * returned to this
848  *  routine.
849  *
850  *  Resets line number count.
851  * 
852  *************************************<->***********************************/
853
854 void 
855 _DtWmParseSetFile (
856     DtWmpParseBuf *pWmPB,
857     FILE *pFile
858     )
859
860 {
861     if (pWmPB)
862     {
863         pWmPB->pchLine[0] = '\0';
864         pWmPB->pchNext = NULL;
865         pWmPB->pFile = pFile;
866         pWmPB->lineNumber = 0;
867     }
868
869 } /* END OF FUNCTION _DtWmParseSetFile */
870
871 \f
872 /*************************************<->*************************************
873  *
874  *  (unsigned char *) _DtWmParseNextLine ( pWmPB )
875  *
876  *
877  *  Description:
878  *  -----------
879  *  Returns a pointer to the next line to parse.
880  *
881  *
882  *  Inputs:
883  *  ------
884  *  pWmPB       = pointer to a parse buffer
885  *
886  * 
887  *  Outputs:
888  *  -------
889  *  Return      = pointer to next line to parse or NULL on EOF.
890  *
891  *
892  *  Comments:
893  *  --------
894  *  
895  * 
896  *************************************<->***********************************/
897
898 unsigned char * 
899 _DtWmParseNextLine (
900     DtWmpParseBuf *pWmPB
901     )
902
903 {
904 /***********************************************************************
905  *
906  * The following code is duplicated from WmResParse.c (GetNextLine)
907  * It works here through the magic of #defines.
908  *
909  ***********************************************************************/
910
911     unsigned char       *string;
912     int                         len;
913     int   chlen;
914     wchar_t last;
915     wchar_t wdelim;
916     char delim;
917     int lastlen;
918
919     if (cfileP != NULL)
920     /* read fopened file */
921     {
922         if ((string = (unsigned char *) 
923                       fgets ((char *)line, MAXLINE, cfileP)) != NULL)
924         {
925 #ifdef PARSE_LIB
926             if (strlen((char *)string) > (size_t)pWmPB->cLineSize)
927             {
928                 /*
929                  * Bump size of destination buffer
930                  */
931                 pWmPB->cLineSize = 1 + strlen((char *)string);
932                 pWmPB->pchLine = (unsigned char *) 
933                     XtRealloc ((char *)pWmPB->pchLine, 
934                                (pWmPB->cLineSize));
935             }
936 #endif /* PARSE_LIB */
937
938             lastlen = 0;
939             while (*string &&
940                    ((len = mblen((char *)string, MB_CUR_MAX)) > 0))
941             {
942                 mbtowc(&last, (char *)string, MB_CUR_MAX);
943                 lastlen = len;
944                 string += len;
945             }
946             delim = '\\';
947             mbtowc(&wdelim, &delim, MB_CUR_MAX);
948             if (lastlen == 1 && last == wdelim)
949             {
950                 do
951                 {
952                     if (!fgets((char *)string, MAXLINE - (string - line), cfileP))
953                         break;
954
955                     lastlen = 0;
956                     while (*string &&
957                            ((len = mblen((char *)string, MB_CUR_MAX)) > 0))
958                     {
959                         mbtowc(&last, (char *)string, MB_CUR_MAX);
960                         lastlen = len;
961                         string += len;
962                     }
963                     linec++;
964                 }
965                 while (lastlen == 1 && last == wdelim);
966             }
967             string = line;
968         }
969     }
970     else if ((parseP != NULL) && (*parseP != '\0'))
971     /* read parse string */
972     {
973 #ifdef PARSE_LIB
974         if (strlen((char *)parseP) > (size_t)pWmPB->cLineSize)
975         {
976             /*
977              * Bump size of destination buffer
978              */
979             pWmPB->cLineSize = 1 + strlen((char *)parseP);
980             pWmPB->pchLine = (unsigned char *) 
981                 XtRealloc ((char *)pWmPB->pchLine, 
982                            (pWmPB->cLineSize));
983         }
984 #endif /* PARSE_LIB */
985         string = line;
986
987         while ((*parseP != '\0') &&
988                ((chlen = mblen ((char *)parseP, MB_CUR_MAX)) != 0) &&
989                (*parseP != '\n'))
990         /* copy all but end-of-line and newlines to line buffer */
991         {
992             if (chlen == -1)
993                parseP++;
994             else
995             {
996                 while (chlen--)
997                 {
998                    *(string++) = *(parseP++);
999                 }
1000             }
1001         }
1002         *string = '\0';
1003         if (*parseP == '\n')
1004         {
1005             parseP++;
1006         }
1007     }
1008     else
1009     {
1010         string = NULL;
1011     }
1012
1013     linec++;
1014 #ifdef PARSE_LIB
1015     if (cfileP)
1016     {
1017         /* update pchNext to get next line */
1018         pWmPB->pchNext = string;
1019     }
1020 #endif /* PARSE_LIB */
1021     return (string);
1022
1023
1024 } /* END OF FUNCTION _DtWmParseNextLine */
1025
1026 \f
1027 /*************************************<->*************************************
1028  *
1029  *  (unsigned char *) _DtWmParseCurrentChar (pWmPB)
1030  *
1031  *
1032  *  Description:
1033  *  -----------
1034  *  Returns a pointer to the rest of the current line.
1035  *
1036  *
1037  *  Inputs:
1038  *  ------
1039  *  pWmPB       = pointer to a parse buffer
1040  *
1041  * 
1042  *  Outputs:
1043  *  -------
1044  *  Return      = pointer to the rest of the current line
1045  *
1046  *
1047  *  Comments:
1048  *  --------
1049  *  Useful in cases where you want to look at a char before getting the
1050  *  next token or if you want to treat the rest of the line as a
1051  *  single token.
1052  * 
1053  *************************************<->***********************************/
1054
1055 unsigned char * 
1056 _DtWmParseCurrentChar (
1057     DtWmpParseBuf *pWmPB
1058     )
1059
1060 {
1061     return (pWmPB ? pWmPB->pchNext : (unsigned char *)NULL);
1062
1063 } /* END OF FUNCTION _DtWmParseCurrentChar */
1064
1065
1066 \f
1067 /*************************************<->*************************************
1068  *
1069  *  (unsigned char *) _DtWmParseNextChar (pWmPB)
1070  *
1071  *
1072  *  Description:
1073  *  -----------
1074  *  Advances the pointer to the next char and returns a pointer
1075  *  to the new current char.
1076  *
1077  *
1078  *  Inputs:
1079  *  ------
1080  *  pWmPB       = pointer to a parse buffer
1081  *
1082  * 
1083  *  Outputs:
1084  *  -------
1085  *  Return      = pointer to the rest of the current line
1086  *
1087  *
1088  *  Comments:
1089  *  --------
1090  * 
1091  *************************************<->***********************************/
1092
1093 unsigned char * 
1094 _DtWmParseNextChar (
1095     DtWmpParseBuf *pWmPB
1096     )
1097
1098 {
1099     unsigned char *pch = NULL;
1100     int chlen;
1101
1102     if (pWmPB &&
1103         pWmPB->pchNext &&
1104         (chlen = mblen((char *)pWmPB->pchNext, MB_CUR_MAX) > 0))
1105     {
1106         pch = (pWmPB->pchNext += chlen);
1107     }
1108
1109     return (pch);
1110 }
1111
1112 \f
1113 /*************************************<->*************************************
1114  *
1115  *  (int) _DtWmParseLineNumber (pWmPB)
1116  *
1117  *
1118  *  Description:
1119  *  -----------
1120  *  Returns the number of the current line of what's being parsed.
1121  *
1122  *
1123  *  Inputs:
1124  *  ------
1125  *  pWmPB       = ptr to parse buffer
1126  *
1127  * 
1128  *  Outputs:
1129  *  -------
1130  *  Return      = number of current line
1131  *
1132  *
1133  *  Comments:
1134  *  --------
1135  *  Used for error reporting.
1136  *
1137  *  The line number is computed by counting '\n' characters.
1138  * 
1139  *************************************<->***********************************/
1140
1141 int 
1142 _DtWmParseLineNumber (
1143     DtWmpParseBuf *pWmPB
1144     )
1145
1146 {
1147     return (pWmPB ? pWmPB->lineNumber : 0);
1148
1149 } /* END OF FUNCTION _DtWmParseLineNumber */
1150
1151 \f
1152 /*************************************<->*************************************
1153  *
1154  *  _DtWmParseToLower (string)
1155  *
1156  *
1157  *  Description:
1158  *  -----------
1159  *  Lower all characters in a string.
1160  *
1161  *
1162  *  Inputs:
1163  *  ------
1164  *  string = NULL-terminated character string or NULL
1165  *
1166  * 
1167  *  Outputs:
1168  *  -------
1169  *  string = NULL-terminated lower case character string or NULL
1170  *
1171  *
1172  *  Comments:
1173  *  --------
1174  *  Can handle multi-byte characters
1175  * 
1176  *************************************<->***********************************/
1177
1178 void _DtWmParseToLower (char  *string)
1179 {
1180     char *pch = string;
1181     int            chlen;
1182
1183     while ((chlen = mblen (pch, MB_CUR_MAX)) > 0)
1184     {
1185         if ((chlen == 1) && (isupper (*pch)))
1186         {
1187             *pch = tolower(*pch);
1188         }
1189         pch += chlen;
1190     }
1191
1192 } /* END OF FUNCTION _DtWmParseToLower */
1193
1194
1195 \f
1196 /*************************************<->*************************************
1197  *
1198  *  _DtWmParsePeekAhead (currentChar, currentLev)
1199  *
1200  *
1201  *  Description:
1202  *  -----------
1203  *  Returns a new level value if this is a new nesting level of quoted string
1204  *  Otherwise it returns a zero
1205  *
1206  *
1207  *  Inputs:
1208  *  ------
1209  *  currentChar = current position in the string
1210  *  currentLev = current level of nesting
1211  *
1212  * 
1213  *  Outputs:
1214  *  -------
1215  *  Returns either a new level of nesting or zero if the character is copied in
1216  *
1217  *
1218  *  Comments:
1219  *  --------
1220  * 
1221  *************************************<->***********************************/
1222 unsigned int _DtWmParsePeekAhead(unsigned char *currentChar,
1223                        unsigned int currentLev)
1224
1225
1226 {
1227     Boolean             done = False;
1228     unsigned int        tmpLev = 1;
1229     unsigned int        chlen;
1230
1231     while (((chlen = mblen ((char *)currentChar, MB_CUR_MAX)) > 0) &&
1232            (chlen == 1) && ((*currentChar == '"') || (*currentChar == '\\'))
1233            && (done == False))
1234     {
1235         currentChar++;
1236
1237         if(((chlen = mblen ((char *)currentChar, MB_CUR_MAX)) > 0) && 
1238            (chlen == 1) &&
1239            ((*currentChar == '"') || (*currentChar == '\\')))
1240         {
1241             tmpLev++;
1242             if(*currentChar == '"')
1243             {
1244                 done = True;
1245             }
1246             else
1247             {
1248                 currentChar++;
1249             }
1250         }
1251     }
1252
1253     /*
1254      * Figure out if this is truly a new level of nesting - else ignore it
1255      * This section probably could do some error checking and return -1
1256          * If so, change type of routine from unsigned int to int
1257      */
1258     if(done == True)
1259     {
1260         return(tmpLev);
1261     }
1262     else
1263     {
1264         return(0);
1265     }
1266 } /* END OF FUNCTION _DtWmParsePeekAhead */
1267
1268
1269 \f
1270 /*************************************<->*************************************
1271  *
1272  *  (unsigned char *) _DtWmParseFilenameExpand (pchFilename)
1273  *
1274  *
1275  *  Description:
1276  *  -----------
1277  *  Returns a copy of a file name with environment variables
1278  *  expanded.
1279  *
1280  *
1281  *  Inputs:
1282  *  ------
1283  *  pchFilename = ptr to a zero terminated character string (filename)
1284  *
1285  * 
1286  *  Outputs:
1287  *  -------
1288  *  Return      = ptr to a new file name with environment variables 
1289  *                expanded.
1290  *
1291  *
1292  *  Comments:
1293  *  --------
1294  *  The passed in string is temporarily modified inside here.
1295  * 
1296  *  Free the returned string with XtFree().
1297  *
1298  *  Returns NULL on a memory allocation error.
1299  *
1300  *  Environment variables that can't be expanded are removed from
1301  *  the returned copy.
1302  *
1303  *  If no environment variables, you get a copy of the string back.
1304  * 
1305  *************************************<->***********************************/
1306 unsigned char *
1307 _DtWmParseFilenameExpand (
1308     unsigned char *pchFilename
1309     )
1310
1311 {
1312     unsigned char *pchN, *pchNew, *pchO;
1313     unsigned char *pchEnv, *pchEnv0, *pchEnv1;
1314     unsigned char chSave;
1315     int len, n, nx, ix;
1316     unsigned char pchBrk[] = { DTWM_CHAR_ENVIRONMENT,
1317                                DTWM_CHAR_DIRECTORY,
1318                                '\0'
1319                              };
1320
1321     len = strlen ((char *)pchFilename);
1322     pchNew = (unsigned char *) XtMalloc (1+len);
1323     pchO = pchFilename;
1324     chSave = '\0';
1325     ix = 0;
1326
1327     while (pchNew && pchO && *pchO)
1328     {
1329         /* find next environment variable */
1330         pchEnv0 = (unsigned char *) 
1331                 strchr ((char *)pchO, (int) DTWM_CHAR_ENVIRONMENT);
1332         if (pchEnv0)
1333         {
1334             /* length to this point */
1335             n = pchEnv0 - pchO;
1336
1337             /* copy up to environment character */
1338             if (n) 
1339             {
1340                 memcpy (&pchNew[ix], pchO, n);
1341                 ix += n;
1342             }
1343
1344             /* skip environment character */
1345             pchEnv0++;  
1346
1347             /* end of variable is at one of:
1348              *   start of next variable,
1349              *   start of next directory,
1350              *   end of string 
1351              */
1352             pchEnv1 = (unsigned char *) 
1353                         strpbrk ((char *)pchEnv0, (char *)pchBrk);
1354
1355             if (pchEnv1)
1356             {
1357                 /* next string starts after this one */
1358                 pchO = pchEnv1; 
1359                 n = pchEnv1 - pchEnv0 + 1;
1360
1361                 /* replace this char with NULL for now */
1362                 chSave = *pchEnv1;
1363                 *pchEnv1 = '\0';
1364             }
1365             else
1366             {
1367                 /* This environment variable is the last thing on
1368                  * the line. Signal all done.
1369                  */
1370                 n = strlen ((char *) pchO);
1371                 pchO += n;
1372             }
1373
1374             pchEnv = (unsigned char *) getenv ((char *)pchEnv0);
1375             if (pchEnv) 
1376             {
1377                 nx = strlen ((char *) pchEnv);
1378                 if (nx > n)
1379                 {
1380                     len += nx - n;
1381                     pchNew = (unsigned char *) 
1382                         XtRealloc ((char *)pchNew, 1+len);
1383                 }
1384                 if (pchNew)
1385                 {
1386                     memcpy (&pchNew[ix], pchEnv, nx);
1387                     ix += nx;
1388                 }
1389                 else 
1390                 {
1391                     continue;
1392                 }
1393             }
1394
1395             if (chSave)
1396             {
1397                 *pchO = chSave;
1398                 chSave = '\0';
1399             }
1400             /* keep a kosher string */
1401             pchNew[ix] = '\0';
1402         }
1403         else
1404         {
1405             /* copy the rest of the string */
1406             n = strlen ((char *) pchO);
1407             memcpy (&pchNew[ix], pchO, n);
1408             pchO += n;
1409
1410             /* remember the NULL! (a famous battle cry) */
1411             pchNew[ix + n] = '\0';
1412         }
1413     }
1414
1415     return (pchNew);
1416
1417 } /* END OF FUNCTION _DtWmParseFilenameExpand */
1418
1419 \f
1420 /*************************************<->*************************************
1421  *
1422  *  unsigned char * _DtWmParseExpandEnvironmentVariables (pch, pchBrk)
1423  *
1424  *
1425  *  Description:
1426  *  -----------
1427  *  Expands environment variables in a string.
1428  *
1429  *
1430  *  Inputs:
1431  *  ------
1432  *  pch   = ptr to a zero terminated character string 
1433  *  pchBrk = array of "break" characters (see strpbrk()).
1434  *           defaults are used if this is NULL.
1435  * 
1436  *  Outputs:
1437  *  -------
1438  *  Return = string with expanded environment variables. (free with XtFree)
1439  *           NULL string if no environment variables or backslashes
1440  *           found in the string passed in.
1441  *
1442  *
1443  *  Comments:
1444  *  --------
1445  *  Free returned string with XtFree()
1446  *
1447  *  Environment variables that can't be expanded are removed from
1448  *  the returned copy.
1449  *
1450  *  Default delimiter set is [Space], [Tab], '$', [Newline], '\', '/'.
1451  *
1452  *  Variables of form $(..) and ${..} supported.
1453  *
1454  *  A backslash '\' in front of any character quotes it. The backslash 
1455  *  is removed in the returned string. A literal backslash needs to be
1456  *  quoted with a backslash.
1457  * 
1458  *************************************<->***********************************/
1459 unsigned char *
1460 _DtWmParseExpandEnvironmentVariables (
1461     unsigned char *pch,
1462     unsigned char *pchBrk
1463     )
1464
1465 {
1466     int chlen;
1467     unsigned char *pchStart;
1468     unsigned char chSave;
1469     unsigned char *pchEnvStart;
1470     unsigned char *pchEnvValue;
1471     unsigned char *pchReturn = NULL;
1472     unsigned char *pchNext;
1473     unsigned char *pchBreak;
1474     Boolean bEatBreak;
1475     Boolean bAlreadyAdvanced;
1476     int lenOriginal;
1477     int lenNonEnv;
1478     int lenEnvVar;
1479     int lenEnvValue;
1480     int lenReturn;
1481     int lenSave;
1482     static unsigned char pchDefaultBrk[] = { 
1483                                 DTWM_CHAR_ENVIRONMENT,
1484                                 DTWM_CHAR_SPACE,
1485                                 DTWM_CHAR_TAB,
1486                                 DTWM_CHAR_NEW_LINE,
1487                                 DTWM_CHAR_BACKSLASH,
1488                                 DTWM_CHAR_DIRECTORY,
1489                                 '\0' };
1490     unsigned char pchParenBrk[] = {   
1491                                 DTWM_CHAR_R_PAREN,
1492                                 '\0' };
1493     unsigned char pchBraceBrk[] = {   
1494                                 DTWM_CHAR_R_BRACE,
1495                                 '\0' };
1496
1497     /* There needs to be something to look at */
1498     if (!pch)
1499         return (NULL);
1500
1501     pchStart = pch;
1502     lenOriginal = strlen ((char *)pch);
1503     chlen = mblen ((char *)pch, MB_CUR_MAX);
1504     chSave = '\0';
1505
1506     while (*pch && (chlen > 0))
1507     {
1508         if (chlen == 1)
1509         {
1510             bAlreadyAdvanced = False;
1511             switch (*pch)
1512             {
1513                 case DTWM_CHAR_BACKSLASH:
1514                     /*
1515                      * Copy up to start of quoted char
1516                      */
1517                     if (!pchReturn)
1518                     {
1519                         lenReturn = lenOriginal + 1;
1520                         pchReturn = (unsigned char *) 
1521                             XtMalloc (lenReturn * sizeof (unsigned char));
1522                         pchReturn[0] = '\0';
1523                     }
1524                     chSave = *pch;
1525                     *pch = '\0';
1526                     strcat ((char *) pchReturn, (char *)pchStart);
1527                     *pch = chSave;
1528                     chSave = '\0';
1529
1530                     /* 
1531                      * The next character is "escaped", skip over it.
1532                      */
1533                     pchStart = pch += chlen;
1534                     chlen = mblen ((char *)pch, MB_CUR_MAX);
1535                     break;
1536
1537                 case DTWM_CHAR_ENVIRONMENT:
1538                     /* save start of environment variable */
1539                     pchEnvStart = pch;
1540                     pch += chlen;
1541                     chlen = mblen ((char *)pch, MB_CUR_MAX);
1542
1543                     /*
1544                      * Copy up to start of environment variable 
1545                      */
1546                     if (!pchReturn)
1547                     {
1548                         lenReturn = lenOriginal + 1;
1549                         pchReturn = (unsigned char *) 
1550                             XtMalloc (lenReturn * sizeof (unsigned char));
1551                         pchReturn[0] = '\0';
1552                         lenSave = 0;
1553                     }
1554                     else
1555                     {
1556                         lenSave = strlen ((char *)pchReturn);
1557                     }
1558                     lenNonEnv = pchEnvStart - pchStart;
1559                     memcpy (&pchReturn[lenSave], pchStart, lenNonEnv);
1560                     pchReturn[lenSave+lenNonEnv] = '\0';
1561
1562                     /* 
1563                      * Determine how we find the end of this 
1564                      * environment variable.
1565                      */
1566                     bEatBreak = False;
1567                     if ((chlen == 1)  &&
1568                         (*pch == DTWM_CHAR_L_PAREN))
1569                     {
1570                         pch += chlen;
1571                         chlen = mblen ((char *)pch, MB_CUR_MAX);
1572                         pchBreak = pchParenBrk;
1573                         bEatBreak = True;
1574                     }
1575                     else if ((chlen == 1)  &&
1576                         (*pch == DTWM_CHAR_L_BRACE))
1577                     {
1578                         pch += chlen;
1579                         chlen = mblen ((char *)pch, MB_CUR_MAX);
1580                         pchBreak = pchBraceBrk;
1581                         bEatBreak = True;
1582                     }
1583                     else if (pchBrk && *pchBrk)
1584                     {
1585                         pchBreak = pchBrk;
1586                     }
1587                     else
1588                     {
1589                         pchBreak = pchDefaultBrk;
1590                     }
1591
1592                     /* 
1593                      * Look for end of environment variable
1594                      */
1595                     pchNext = (unsigned char *)
1596                             strpbrk ((char *)pch, (char *)pchBreak);
1597
1598                     if (!pchNext)
1599                     {
1600                         /* it's the rest of the string */
1601                         chSave = '\0';
1602                         bEatBreak = False;
1603                         pchNext = pch + strlen ((char *) pch);
1604                     }
1605                     else
1606                     {
1607                         /* temporarily put a string terminator here */
1608                         chSave = *pchNext;
1609                         *pchNext = '\0';
1610                     }
1611
1612                     /*
1613                      * Lookup environment variable
1614                      */
1615                     lenEnvVar = strlen ((char *)pch);
1616                     pchEnvValue = (unsigned char *) getenv ((char *)pch);
1617
1618                     if (pchEnvValue)
1619                     {
1620                         /*
1621                          * Insure there's enough room in the return string
1622                          */
1623                         lenEnvValue = strlen ((char *)pchEnvValue);
1624                         if (!pchReturn)
1625                         {
1626                             lenReturn = lenOriginal + 1 - lenEnvVar +
1627                                                 lenEnvValue;
1628                             pchReturn = (unsigned char *) 
1629                                 XtMalloc (lenReturn * sizeof (unsigned char));
1630                             pchReturn[0] = '\0';
1631                         }
1632                         else
1633                         {
1634                             lenReturn = lenReturn + 1 - lenEnvVar +
1635                                                 lenEnvValue;
1636                             pchReturn = (unsigned char *) 
1637                                 XtRealloc ((char *)pchReturn, 
1638                                     lenReturn * sizeof (unsigned char));
1639                         }
1640
1641                         /*
1642                          * Tack it onto the return string
1643                          */
1644                         strcat ((char *)pchReturn, (char *)pchEnvValue);
1645                     }
1646
1647                     /*
1648                      * Advance the pointer for the next pass
1649                      */
1650                     if (chSave)
1651                     {
1652                         /* restore saved character */
1653                         *pchNext = chSave;
1654                         chSave = '\0';
1655
1656                         /* 
1657                          *  If this was a closing paren, then skip it
1658                          */
1659                         if (bEatBreak)
1660                         {
1661                             chlen = mblen ((char *)pchNext, MB_CUR_MAX);
1662                             pchNext += chlen;
1663                         }
1664                     }
1665                     pchStart = pch = pchNext;
1666                     chlen = mblen ((char *)pch, MB_CUR_MAX);
1667                     /*
1668                      * We're already pointing at the next character
1669                      * to process, don't advance again!
1670                      */
1671                     bAlreadyAdvanced = True;
1672
1673                     break;
1674
1675                 default:
1676                     /* this character is not interesting */
1677                     break;
1678             }
1679
1680             /*
1681              * Move to the next character if we're not already
1682              * there.
1683              */
1684             if (!bAlreadyAdvanced)
1685             {
1686                 pch += chlen; 
1687                 chlen = mblen ((char *)pch, MB_CUR_MAX);
1688             }
1689         }
1690         else
1691         {
1692             pch += chlen;
1693             chlen = mblen ((char *)pch, MB_CUR_MAX);
1694         }
1695     }
1696
1697     if (pchReturn && *pchStart)
1698     {
1699         /*
1700          * Copy remaining parts of the string
1701          */
1702         strcat ((char *)pchReturn, (char *)pchStart);
1703     }
1704
1705     return (pchReturn);
1706
1707 } /* END OF FUNCTION _DtWmParseExpandEnvironmentVariables */
1708
1709
1710 \f
1711 /******************************<->*************************************
1712  *
1713  *  _DtWmParseMakeQuotedString (pchLine)
1714  *
1715  *
1716  *  Description:
1717  *  -----------
1718  *  Encapsulates the passed in "line" into a string argument quoted
1719  *  by double quotes. Special characters are "escaped" as needed.
1720  *
1721  *  Inputs:
1722  *  ------
1723  *  pchLine = ptr to string to enclose in quotes
1724  *
1725  *  Outputs:
1726  *  -------
1727  *  Return = ptr to quoted string 
1728  *
1729  *  Comment:
1730  *  -------
1731  *  Returned string should be freed with XtFree().
1732  * 
1733  ******************************<->***********************************/
1734
1735 unsigned char *
1736 _DtWmParseMakeQuotedString (unsigned char *pchLine)
1737 {
1738     unsigned char *pchRet;
1739     int iLen0, iLen1;
1740     int cSpecial;
1741     int i,j;
1742     int   chlen;
1743
1744     iLen0 = strlen ((char *)pchLine);
1745     iLen1 = iLen0 + 2; /* for starting, ending quotes */
1746
1747     for (i=0; i < iLen0; i++)
1748     {
1749         /*
1750          * Count special chars to get estimate of new length
1751          */
1752         chlen = mblen ((char *) &pchLine[i], MB_CUR_MAX);
1753         if ((chlen == 1) &&
1754             ((pchLine[i] == '\\') ||
1755              (pchLine[i] == '"')))
1756         {
1757             iLen1++;
1758         }
1759         else if (chlen < 1)
1760         {
1761             break;
1762         }
1763         else 
1764         {
1765             i += chlen-1;
1766         }
1767     }
1768
1769     pchRet = (unsigned char *) XtMalloc (1+iLen1);
1770
1771     if (pchRet)
1772     {
1773         pchRet[0] = '"';        /* starting quote */
1774         /*
1775          * Copy chars from old string to new one
1776          */
1777         for (i=0, j=1; i < iLen0; i++, j++)
1778         {
1779             chlen = mblen ((char *) &pchLine[i], MB_CUR_MAX);
1780             if ((chlen == 1) &&
1781                 ((pchLine[i] == '\\') ||
1782                  (pchLine[i] == '"')))
1783             {
1784                 /* quote next char */
1785                 pchRet[j++] = '\\';
1786             }
1787             else if (chlen < 1)
1788             {
1789                 break;
1790             }
1791             else while (chlen > 1)
1792             {
1793                 /* copy first bytes of multibyte char */
1794                 pchRet[j++] = pchLine[i++];
1795                 chlen--;
1796             }
1797             /* copy char */
1798             pchRet[j] = pchLine[i];
1799         }
1800         pchRet[j++] = '"';      /* ending quote */
1801         pchRet[j] = '\0';       /* end of string */
1802     }
1803
1804     return (pchRet);
1805
1806 } /* END OF FUNCTION _DtWmParseMakeQuotedString */
1807
1808
1809 /*==================== END OF FILE   WmParse.c ====================*/