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>
45 #include <X11/Intrinsic.h>
46 #include <X11/StringDefs.h>
47 #include <Dt/Utility.h>
48 #include <Dt/DtNlUtils.h>
55 /******** Static Function Declarations ********/
57 static void SkipWhiteSpace(
64 static void GetWordWithQuotes(
69 /******** End Static Function Declarations ********/
72 /*****************************************************************************
74 * SkipWhiteSpace - takes a string and in index ("position") into the
75 * string and advances "position" until a non-whitespace character is
78 * A "whitespace" character is defined by "isspace".
82 * String string; - The string to search.
84 * int *position; - MODIFIED: Set to the location of the first
85 * non-whitespace character.
87 *****************************************************************************/
94 string += (*position);
98 (!is_multibyte || (mblen (string, MB_CUR_MAX) == 1)) &&
100 isspace ((u_char)*string)) {
106 /*****************************************************************************
108 * FillWord - parses "string" for a complete argument and puts the
111 * The algorithm was derived by empirical observation and checking the
112 * (poorly written) Bourne Shell tutorial. A BNF for the shell meta
113 * characters ", ', and \ was not availble.
115 * The algorithm - until the end of the word is found:
117 * For each character "c":
118 * If c = \, remove the \ and pass on the next char.
120 * If c = ' or ", must save this in "qchar" and loop until the
121 * ending quote is found:
123 * If c = qchar, found the ending quote, exit this loop
125 * If qchar = double quote and c2 = next char
126 * if c2 = \, ", $, or `, remove c and pass on c2
127 * otherwise, pass on both c and c2
128 * If qchar = single quote, and c2 = next char:
129 * if c2 = ', pass on c, remove the ' and exit this loop
130 * (the ' cannot be escaped)
131 * otherwise, pass on both c and c2
132 * Othewise, pass on c
134 * If c = white space, found the end of the word, return
135 * Otherwise, pass on the char
140 * char *string; - The string to search.
142 * char *word; - MODIFIED: Points to the beginning of the word.
144 * int *position - MODIFIED: Starts at the beginning of the string
145 * and gets advanced past "word".
147 *****************************************************************************/
157 Boolean found = False;
158 Boolean done = False;
162 while ((*string != '\0') && (!found)) {
164 * Check for multibyte chars. The assumption here is that if
165 * is_multibyte is true and "string" points to a multi-byte char,
166 * then that entire char should be copied to "word".
169 if (is_multibyte && ((len = mblen (string, MB_CUR_MAX)) > 1))
170 for (i=0; i < len; i++, j++, string++)
177 /* Remove the slash and add the following character. */
180 if (is_multibyte && ((len = mblen (string, MB_CUR_MAX)) > 1))
181 for (i=0; i < len; i++, j++, string++)
185 word[j++] = *(string)++;
190 if (*string == '\'') qchar = _SINGLE;
192 /* Search for the ending quote. */
194 while ((!done) && (*string != '\0')) {
196 if (is_multibyte && ((len = mblen (string, MB_CUR_MAX)) > 1))
197 for (i=0; i < len; i++, j++, string++)
202 if (*string == *qchar) {
207 if (*string == '\\') {
208 /* Must follow the rules of the single or double
209 * quote - which ever "qchar" points to.
211 if (!strcmp (qchar, _DOUBLE)) {
212 if ((DtStrcspn (string+1, "\"\\$`")) == 0) {
213 /* Skip past the '\', but fill in the
214 * following character.
219 /* Want to pass on both the '\' and the
222 word[j++] = *(string)++;
223 /* The '\' is skipped. Fill in the next char. */
225 if (is_multibyte && ((len = mblen (string, MB_CUR_MAX)) > 1))
226 for (i=0; i < len; i++, j++, string++)
230 word[j++] = *(string)++;
231 /* The \ and following char are now skipped. */
233 else if (!strcmp (qchar, _SINGLE)) {
234 /* Must be working on a _SINGLE quoted word. */
235 if ((DtStrcspn (string+1, "\'")) == 0) {
237 * Have \', which passes on the \, skips
238 * the single quote and ends the word. An
239 * assumption here is that the char following
240 * the '\' was a single byte single quote
241 * and there is no need for checking multi-byte.
243 word[j++] = *(string)++;
244 /* Now skip the quote. */
251 * Need to pass on both chars. Pass on the
254 word[j++] = *(string)++;
257 * The '\' is skipped if present. Fill in the
261 if (is_multibyte && ((len = mblen (string, MB_CUR_MAX)) > 1))
262 for (i=0; i < len; i++, j++, string++)
266 /* Pass on what ever char is there. */
267 word[j++] = *(string)++;
272 /* This char was not escaped, just add it. */
273 word[j++] = *(string)++;
279 /* Found the end of the word. */
284 word[j++] = *(string)++;
290 *position = *position + (string - pbeg);
293 /*****************************************************************************
295 * GetWordWithQuotes - takes the strings "string" and "word" and an index
296 * into "string" and fills "word" with one word from "string".
298 * A word is defined in the function "FillWord".
300 * Note that if an ending quote is not found, "position" will be advanced to
301 * the end of the string.
305 * String string; - String containing the word to be extracted.
307 * String word; - MODIFIED - contains the next word in "string".
309 * int *position; - MODIFIED - starts at beginning of word, ends
312 *****************************************************************************/
320 int len = strlen(string);
321 SkipWhiteSpace (string, position);
323 if ((*position) >= len) {
328 string += (*position);
330 FillWord (string, word, position);
333 /*****************************************************************************
335 * _DtCmdStringToArrayOfStrings - takes a string and an array of pointers
336 * to strings and breaks the string into whitespace separated words.
338 * A "word" is a sequence of characters that has no whitespace with
339 * the following exception:
341 * - A word may contain contain whitespace if it is delimited
342 * by a pair of matching single or double qotes.
344 * "Whitespace" is a tab or blank character.
349 * - The space for the "words" is malloc'd and must be free'd by
352 * - "theArray" is NULL terminated.
356 * char theString[]; - The string to parse.
358 * char *theArray[]; - MODIFIED: gets filled with pointers to
359 * the words that are parsed.
361 *****************************************************************************/
364 _DtCmdStringToArrayOfStrings(
368 int len, i, position;
370 tmp = (char *) XtMalloc (1 + strlen (theString));
372 len=strlen(theString);
373 for (position=0, i=0; (position <= len) &&
374 (theString[position] != '\0'); ) {
375 (void) strcpy (tmp, "");
376 GetWordWithQuotes (theString, tmp, &position);
377 /* Check word to see if it contains only trailing blanks. */
383 * This parameter is empty, such as "" or '' but we are
384 * not at the end of the line. Consequently, put an
385 * empty string in "theArray".
387 theArray[i] = XtNewString ("");
392 * Must be at the end of the line.
394 theArray[i] = (char *) NULL;
399 theArray[i] = XtNewString (tmp);
403 /* Null terminate the array of string pointers. */
406 XtFree ((char *) tmp);
409 /******************************************************************************
411 * _DtCmdFreeStringVector - takes an array of pointers to strings and
412 * frees the malloc'd space for the strings.
414 * This does NOT free the string vector itself; It assumes that
415 * stringv is a static i.e. char *stringv[N].
419 * char **stringv; - MODIFIED: Each string in the array is freed.
421 *****************************************************************************/
424 _DtCmdFreeStringVector(
429 for (pch = stringv; *pch != NULL; pch++) {