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 libraries and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
24 * File: CmdUtility.c $XConsortium: CmdUtility.c /main/4 1995/10/26 15:18:41 rswiston $
27 * (c) Copyright 1988, Hewlett-Packard Company, all rights reserved.
29 * (c) Copyright 1993, 1994 Hewlett-Packard Company *
30 * (c) Copyright 1993, 1994 International Business Machines Corp. *
31 * (c) Copyright 1993, 1994 Sun Microsystems, Inc. *
32 * (c) Copyright 1993, 1994 Novell, Inc. *
38 #include <sys/param.h>
41 #include "/sys5/usr/include/unistd.h"
49 #include <X11/Intrinsic.h>
50 #include <X11/StringDefs.h>
51 #include <Dt/Utility.h>
52 #include <Dt/DtNlUtils.h>
59 /******** Static Function Declarations ********/
61 static void SkipWhiteSpace(
68 static void GetWordWithQuotes(
73 /******** End Static Function Declarations ********/
76 /*****************************************************************************
78 * SkipWhiteSpace - takes a string and in index ("position") into the
79 * string and advances "position" until a non-whitespace character is
82 * A "whitespace" character is defined by "isspace".
86 * String string; - The string to search.
88 * int *position; - MODIFIED: Set to the location of the first
89 * non-whitespace character.
91 *****************************************************************************/
98 string += (*position);
102 (!is_multibyte || (mblen (string, MB_CUR_MAX) == 1)) &&
104 isspace ((u_char)*string)) {
110 /*****************************************************************************
112 * FillWord - parses "string" for a complete argument and puts the
115 * The algorithm was derived by empirical observation and checking the
116 * (poorly written) Bourne Shell tutorial. A BNF for the shell meta
117 * characters ", ', and \ was not availble.
119 * The algorithm - until the end of the word is found:
121 * For each character "c":
122 * If c = \, remove the \ and pass on the next char.
124 * If c = ' or ", must save this in "qchar" and loop until the
125 * ending quote is found:
127 * If c = qchar, found the ending quote, exit this loop
129 * If qchar = double quote and c2 = next char
130 * if c2 = \, ", $, or `, remove c and pass on c2
131 * otherwise, pass on both c and c2
132 * If qchar = single quote, and c2 = next char:
133 * if c2 = ', pass on c, remove the ' and exit this loop
134 * (the ' cannot be escaped)
135 * otherwise, pass on both c and c2
136 * Othewise, pass on c
138 * If c = white space, found the end of the word, return
139 * Otherwise, pass on the char
144 * char *string; - The string to search.
146 * char *word; - MODIFIED: Points to the beginning of the word.
148 * int *position - MODIFIED: Starts at the beginning of the string
149 * and gets advanced past "word".
151 *****************************************************************************/
161 Boolean found = False;
162 Boolean done = False;
166 while ((*string != '\0') && (!found)) {
168 * Check for multibyte chars. The assumption here is that if
169 * is_multibyte is true and "string" points to a multi-byte char,
170 * then that entire char should be copied to "word".
173 if (is_multibyte && ((len = mblen (string, MB_CUR_MAX)) > 1))
174 for (i=0; i < len; i++, j++, string++)
181 /* Remove the slash and add the following character. */
184 if (is_multibyte && ((len = mblen (string, MB_CUR_MAX)) > 1))
185 for (i=0; i < len; i++, j++, string++)
189 word[j++] = *(string)++;
194 if (*string == '\'') qchar = _SINGLE;
196 /* Search for the ending quote. */
198 while ((!done) && (*string != '\0')) {
200 if (is_multibyte && ((len = mblen (string, MB_CUR_MAX)) > 1))
201 for (i=0; i < len; i++, j++, string++)
206 if (*string == *qchar) {
211 if (*string == '\\') {
212 /* Must follow the rules of the single or double
213 * quote - which ever "qchar" points to.
215 if (!strcmp (qchar, _DOUBLE)) {
216 if ((DtStrcspn (string+1, "\"\\$`")) == 0) {
217 /* Skip past the '\', but fill in the
218 * following character.
223 /* Want to pass on both the '\' and the
226 word[j++] = *(string)++;
227 /* The '\' is skipped. Fill in the next char. */
229 if (is_multibyte && ((len = mblen (string, MB_CUR_MAX)) > 1))
230 for (i=0; i < len; i++, j++, string++)
234 word[j++] = *(string)++;
235 /* The \ and following char are now skipped. */
237 else if (!strcmp (qchar, _SINGLE)) {
238 /* Must be working on a _SINGLE quoted word. */
239 if ((DtStrcspn (string+1, "\'")) == 0) {
241 * Have \', which passes on the \, skips
242 * the single quote and ends the word. An
243 * assumption here is that the char following
244 * the '\' was a single byte single quote
245 * and there is no need for checking multi-byte.
247 word[j++] = *(string)++;
248 /* Now skip the quote. */
255 * Need to pass on both chars. Pass on the
258 word[j++] = *(string)++;
261 * The '\' is skipped if present. Fill in the
265 if (is_multibyte && ((len = mblen (string, MB_CUR_MAX)) > 1))
266 for (i=0; i < len; i++, j++, string++)
270 /* Pass on what ever char is there. */
271 word[j++] = *(string)++;
276 /* This char was not escaped, just add it. */
277 word[j++] = *(string)++;
283 /* Found the end of the word. */
288 word[j++] = *(string)++;
294 *position = *position + (string - pbeg);
297 /*****************************************************************************
299 * GetWordWithQuotes - takes the strings "string" and "word" and an index
300 * into "string" and fills "word" with one word from "string".
302 * A word is defined in the function "FillWord".
304 * Note that if an ending quote is not found, "position" will be advanced to
305 * the end of the string.
309 * String string; - String containing the word to be extracted.
311 * String word; - MODIFIED - contains the next word in "string".
313 * int *position; - MODIFIED - starts at beginning of word, ends
316 *****************************************************************************/
324 int len = strlen(string);
325 SkipWhiteSpace (string, position);
327 if ((*position) >= len) {
332 string += (*position);
334 FillWord (string, word, position);
337 /*****************************************************************************
339 * _DtCmdStringToArrayOfStrings - takes a string and an array of pointers
340 * to strings and breaks the string into whitespace separated words.
342 * A "word" is a sequence of characters that has no whitespace with
343 * the following exception:
345 * - A word may contain contain whitespace if it is delimited
346 * by a pair of matching single or double qotes.
348 * "Whitespace" is a tab or blank character.
353 * - The space for the "words" is malloc'd and must be free'd by
356 * - "theArray" is NULL terminated.
360 * char theString[]; - The string to parse.
362 * char *theArray[]; - MODIFIED: gets filled with pointers to
363 * the words that are parsed.
365 *****************************************************************************/
368 _DtCmdStringToArrayOfStrings(
372 int len, i, position;
374 tmp = (char *) XtMalloc (1 + strlen (theString));
376 len=strlen(theString);
377 for (position=0, i=0; (position <= len) &&
378 (theString[position] != '\0'); ) {
379 (void) strcpy (tmp, "");
380 GetWordWithQuotes (theString, tmp, &position);
381 /* Check word to see if it contains only trailing blanks. */
387 * This parameter is empty, such as "" or '' but we are
388 * not at the end of the line. Consequently, put an
389 * empty string in "theArray".
391 theArray[i] = XtNewString ("");
396 * Must be at the end of the line.
398 theArray[i] = (char *) NULL;
403 theArray[i] = XtNewString (tmp);
407 /* Null terminate the array of string pointers. */
410 XtFree ((char *) tmp);
413 /******************************************************************************
415 * _DtCmdFreeStringVector - takes an array of pointers to strings and
416 * frees the malloc'd space for the strings.
418 * This does NOT free the string vector itself; It assumes that
419 * stringv is a static i.e. char *stringv[N].
423 * char **stringv; - MODIFIED: Each string in the array is freed.
425 *****************************************************************************/
428 _DtCmdFreeStringVector(
433 for (pch = stringv; *pch != NULL; pch++) {