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
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. *
37 #include <sys/param.h>
40 #include "/sys5/usr/include/unistd.h"
48 #include <X11/Intrinsic.h>
49 #include <X11/StringDefs.h>
50 #include <Dt/Utility.h>
51 #include <Dt/DtNlUtils.h>
58 /******** Static Function Declarations ********/
60 static void SkipWhiteSpace(
67 static void GetWordWithQuotes(
72 /******** End Static Function Declarations ********/
75 /*****************************************************************************
77 * SkipWhiteSpace - takes a string and in index ("position") into the
78 * string and advances "position" until a non-whitespace character is
81 * A "whitespace" character is defined by "isspace".
85 * String string; - The string to search.
87 * int *position; - MODIFIED: Set to the location of the first
88 * non-whitespace character.
90 *****************************************************************************/
97 string += (*position);
101 (!is_multibyte || (mblen (string, MB_CUR_MAX) == 1)) &&
103 isspace ((u_char)*string)) {
109 /*****************************************************************************
111 * FillWord - parses "string" for a complete argument and puts the
114 * The algorithm was derived by empirical observation and checking the
115 * (poorly written) Bourne Shell tutorial. A BNF for the shell meta
116 * characters ", ', and \ was not availble.
118 * The algorithm - until the end of the word is found:
120 * For each character "c":
121 * If c = \, remove the \ and pass on the next char.
123 * If c = ' or ", must save this in "qchar" and loop until the
124 * ending quote is found:
126 * If c = qchar, found the ending quote, exit this loop
128 * If qchar = double quote and c2 = next char
129 * if c2 = \, ", $, or `, remove c and pass on c2
130 * otherwise, pass on both c and c2
131 * If qchar = single quote, and c2 = next char:
132 * if c2 = ', pass on c, remove the ' and exit this loop
133 * (the ' cannot be escaped)
134 * otherwise, pass on both c and c2
135 * Othewise, pass on c
137 * If c = white space, found the end of the word, return
138 * Otherwise, pass on the char
143 * char *string; - The string to search.
145 * char *word; - MODIFIED: Points to the beginning of the word.
147 * int *position - MODIFIED: Starts at the beginning of the string
148 * and gets advanced past "word".
150 *****************************************************************************/
160 Boolean found = False;
161 Boolean done = False;
165 while ((*string != '\0') && (!found)) {
167 * Check for multibyte chars. The assumption here is that if
168 * is_multibyte is true and "string" points to a multi-byte char,
169 * then that entire char should be copied to "word".
172 if (is_multibyte && ((len = mblen (string, MB_CUR_MAX)) > 1))
173 for (i=0; i < len; i++, j++, string++)
180 /* Remove the slash and add the following character. */
183 if (is_multibyte && ((len = mblen (string, MB_CUR_MAX)) > 1))
184 for (i=0; i < len; i++, j++, string++)
188 word[j++] = *(string)++;
193 if (*string == '\'') qchar = _SINGLE;
195 /* Search for the ending quote. */
197 while ((!done) && (*string != '\0')) {
199 if (is_multibyte && ((len = mblen (string, MB_CUR_MAX)) > 1))
200 for (i=0; i < len; i++, j++, string++)
205 if (*string == *qchar) {
210 if (*string == '\\') {
211 /* Must follow the rules of the single or double
212 * quote - which ever "qchar" points to.
214 if (!strcmp (qchar, _DOUBLE)) {
215 if ((DtStrcspn (string+1, "\"\\$`")) == 0) {
216 /* Skip past the '\', but fill in the
217 * following character.
222 /* Want to pass on both the '\' and the
225 word[j++] = *(string)++;
226 /* The '\' is skipped. Fill in the next char. */
228 if (is_multibyte && ((len = mblen (string, MB_CUR_MAX)) > 1))
229 for (i=0; i < len; i++, j++, string++)
233 word[j++] = *(string)++;
234 /* The \ and following char are now skipped. */
236 else if (!strcmp (qchar, _SINGLE)) {
237 /* Must be working on a _SINGLE quoted word. */
238 if ((DtStrcspn (string+1, "\'")) == 0) {
240 * Have \', which passes on the \, skips
241 * the single quote and ends the word. An
242 * assumption here is that the char following
243 * the '\' was a single byte single quote
244 * and there is no need for checking multi-byte.
246 word[j++] = *(string)++;
247 /* Now skip the quote. */
254 * Need to pass on both chars. Pass on the
257 word[j++] = *(string)++;
260 * The '\' is skipped if present. Fill in the
264 if (is_multibyte && ((len = mblen (string, MB_CUR_MAX)) > 1))
265 for (i=0; i < len; i++, j++, string++)
269 /* Pass on what ever char is there. */
270 word[j++] = *(string)++;
275 /* This char was not escaped, just add it. */
276 word[j++] = *(string)++;
282 /* Found the end of the word. */
287 word[j++] = *(string)++;
293 *position = *position + (string - pbeg);
296 /*****************************************************************************
298 * GetWordWithQuotes - takes the strings "string" and "word" and an index
299 * into "string" and fills "word" with one word from "string".
301 * A word is defined in the function "FillWord".
303 * Note that if an ending quote is not found, "position" will be advanced to
304 * the end of the string.
308 * String string; - String containing the word to be extracted.
310 * String word; - MODIFIED - contains the next word in "string".
312 * int *position; - MODIFIED - starts at beginning of word, ends
315 *****************************************************************************/
323 int len = strlen(string);
324 SkipWhiteSpace (string, position);
326 if ((*position) >= len) {
331 string += (*position);
333 FillWord (string, word, position);
336 /*****************************************************************************
338 * _DtCmdStringToArrayOfStrings - takes a string and an array of pointers
339 * to strings and breaks the string into whitespace separated words.
341 * A "word" is a sequence of characters that has no whitespace with
342 * the following exception:
344 * - A word may contain contain whitespace if it is delimited
345 * by a pair of matching single or double qotes.
347 * "Whitespace" is a tab or blank character.
352 * - The space for the "words" is malloc'd and must be free'd by
355 * - "theArray" is NULL terminated.
359 * char theString[]; - The string to parse.
361 * char *theArray[]; - MODIFIED: gets filled with pointers to
362 * the words that are parsed.
364 *****************************************************************************/
367 _DtCmdStringToArrayOfStrings(
371 int len, i, position;
373 tmp = (char *) XtMalloc (1 + strlen (theString));
375 len=strlen(theString);
376 for (position=0, i=0; (position <= len) &&
377 (theString[position] != '\0'); ) {
378 (void) strcpy (tmp, "");
379 GetWordWithQuotes (theString, tmp, &position);
380 /* Check word to see if it contains only trailing blanks. */
386 * This parameter is empty, such as "" or '' but we are
387 * not at the end of the line. Consequently, put an
388 * empty string in "theArray".
390 theArray[i] = XtNewString ("");
395 * Must be at the end of the line.
397 theArray[i] = (char *) NULL;
402 theArray[i] = XtNewString (tmp);
406 /* Null terminate the array of string pointers. */
409 XtFree ((char *) tmp);
412 /******************************************************************************
414 * _DtCmdFreeStringVector - takes an array of pointers to strings and
415 * frees the malloc'd space for the strings.
417 * This does NOT free the string vector itself; It assumes that
418 * stringv is a static i.e. char *stringv[N].
422 * char **stringv; - MODIFIED: Each string in the array is freed.
424 *****************************************************************************/
427 _DtCmdFreeStringVector(
432 for (pch = stringv; *pch != NULL; pch++) {