CmdUtility.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  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. * File: CmdUtility.c $XConsortium: CmdUtility.c /main/4 1995/10/26 15:18:41 rswiston $
  25. * Language: C
  26. *
  27. * (c) Copyright 1988, Hewlett-Packard Company, all rights reserved.
  28. *
  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. *
  33. */
  34. #include <ctype.h>
  35. #include <stdio.h>
  36. #include <string.h>
  37. #include <sys/param.h>
  38. #include <unistd.h>
  39. #include <limits.h>
  40. #include <sys/stat.h>
  41. #include <X11/Xlib.h>
  42. #include <X11/Intrinsic.h>
  43. #include <X11/StringDefs.h>
  44. #include <Dt/Utility.h>
  45. #include <Dt/DtNlUtils.h>
  46. #define _SINGLE "\'"
  47. #define _DOUBLE "\""
  48. /******** Static Function Declarations ********/
  49. static void SkipWhiteSpace(
  50. String string,
  51. int *position) ;
  52. static void FillWord(
  53. char *string,
  54. char *word,
  55. int *position) ;
  56. static void GetWordWithQuotes(
  57. String string,
  58. String word,
  59. int *position) ;
  60. /******** End Static Function Declarations ********/
  61. /*****************************************************************************
  62. *
  63. * SkipWhiteSpace - takes a string and in index ("position") into the
  64. * string and advances "position" until a non-whitespace character is
  65. * encountered.
  66. *
  67. * A "whitespace" character is defined by "isspace".
  68. *
  69. * PARAMETERS:
  70. *
  71. * String string; - The string to search.
  72. *
  73. * int *position; - MODIFIED: Set to the location of the first
  74. * non-whitespace character.
  75. *
  76. *****************************************************************************/
  77. static void
  78. SkipWhiteSpace(
  79. String string,
  80. int *position )
  81. {
  82. string += (*position);
  83. while (
  84. #ifdef NLS16
  85. (!is_multibyte || (mblen (string, MB_CUR_MAX) == 1)) &&
  86. #endif
  87. isspace ((u_char)*string)) {
  88. string++;
  89. (*position)++;
  90. }
  91. }
  92. /*****************************************************************************
  93. *
  94. * FillWord - parses "string" for a complete argument and puts the
  95. * result in "word".
  96. *
  97. * The algorithm was derived by empirical observation and checking the
  98. * (poorly written) Bourne Shell tutorial. A BNF for the shell meta
  99. * characters ", ', and \ was not availble.
  100. *
  101. * The algorithm - until the end of the word is found:
  102. *
  103. * For each character "c":
  104. * If c = \, remove the \ and pass on the next char.
  105. *
  106. * If c = ' or ", must save this in "qchar" and loop until the
  107. * ending quote is found:
  108. * c = the next char
  109. * If c = qchar, found the ending quote, exit this loop
  110. * If c = \
  111. * If qchar = double quote and c2 = next char
  112. * if c2 = \, ", $, or `, remove c and pass on c2
  113. * otherwise, pass on both c and c2
  114. * If qchar = single quote, and c2 = next char:
  115. * if c2 = ', pass on c, remove the ' and exit this loop
  116. * (the ' cannot be escaped)
  117. * otherwise, pass on both c and c2
  118. * Othewise, pass on c
  119. *
  120. * If c = white space, found the end of the word, return
  121. * Otherwise, pass on the char
  122. *
  123. *
  124. * PARAMETERS:
  125. *
  126. * char *string; - The string to search.
  127. *
  128. * char *word; - MODIFIED: Points to the beginning of the word.
  129. *
  130. * int *position - MODIFIED: Starts at the beginning of the string
  131. * and gets advanced past "word".
  132. *
  133. *****************************************************************************/
  134. static void
  135. FillWord(
  136. char *string,
  137. char *word,
  138. int *position )
  139. {
  140. char *qchar;
  141. int len, i;
  142. Boolean found = False;
  143. Boolean done = False;
  144. int j = 0;
  145. char *pbeg = string;
  146. while ((*string != '\0') && (!found)) {
  147. /*
  148. * Check for multibyte chars. The assumption here is that if
  149. * is_multibyte is true and "string" points to a multi-byte char,
  150. * then that entire char should be copied to "word".
  151. */
  152. #ifdef NLS16
  153. if (is_multibyte && ((len = mblen (string, MB_CUR_MAX)) > 1))
  154. for (i=0; i < len; i++, j++, string++)
  155. word[j] = *string;
  156. else
  157. #endif
  158. {
  159. switch (*string) {
  160. case '\\':
  161. /* Remove the slash and add the following character. */
  162. string++;
  163. #ifdef NLS16
  164. if (is_multibyte && ((len = mblen (string, MB_CUR_MAX)) > 1))
  165. for (i=0; i < len; i++, j++, string++)
  166. word[j] = *string;
  167. else
  168. #endif
  169. word[j++] = *(string)++;
  170. break;
  171. case '\'':
  172. case '\"':
  173. qchar = _DOUBLE;
  174. if (*string == '\'') qchar = _SINGLE;
  175. string++;
  176. /* Search for the ending quote. */
  177. done = False;
  178. while ((!done) && (*string != '\0')) {
  179. #ifdef NLS16
  180. if (is_multibyte && ((len = mblen (string, MB_CUR_MAX)) > 1))
  181. for (i=0; i < len; i++, j++, string++)
  182. word[j] = *string;
  183. else
  184. #endif
  185. {
  186. if (*string == *qchar) {
  187. done = True;
  188. string++;
  189. break;
  190. }
  191. if (*string == '\\') {
  192. /* Must follow the rules of the single or double
  193. * quote - which ever "qchar" points to.
  194. */
  195. if (!strcmp (qchar, _DOUBLE)) {
  196. if ((DtStrcspn (string+1, "\"\\$`")) == 0) {
  197. /* Skip past the '\', but fill in the
  198. * following character.
  199. */
  200. string++;
  201. }
  202. else
  203. /* Want to pass on both the '\' and the
  204. * following char.
  205. */
  206. word[j++] = *(string)++;
  207. /* The '\' is skipped. Fill in the next char. */
  208. #ifdef NLS16
  209. if (is_multibyte && ((len = mblen (string, MB_CUR_MAX)) > 1))
  210. for (i=0; i < len; i++, j++, string++)
  211. word[j] = *string;
  212. else
  213. #endif
  214. word[j++] = *(string)++;
  215. /* The \ and following char are now skipped. */
  216. }
  217. else if (!strcmp (qchar, _SINGLE)) {
  218. /* Must be working on a _SINGLE quoted word. */
  219. if ((DtStrcspn (string+1, "\'")) == 0) {
  220. /*
  221. * Have \', which passes on the \, skips
  222. * the single quote and ends the word. An
  223. * assumption here is that the char following
  224. * the '\' was a single byte single quote
  225. * and there is no need for checking multi-byte.
  226. */
  227. word[j++] = *(string)++;
  228. /* Now skip the quote. */
  229. string++;
  230. done = True;
  231. break;
  232. }
  233. else {
  234. /*
  235. * Need to pass on both chars. Pass on the
  236. * first char here.
  237. */
  238. word[j++] = *(string)++;
  239. /*
  240. * The '\' is skipped if present. Fill in the
  241. * next char.
  242. */
  243. #ifdef NLS16
  244. if (is_multibyte && ((len = mblen (string, MB_CUR_MAX)) > 1))
  245. for (i=0; i < len; i++, j++, string++)
  246. word[j] = *string;
  247. else
  248. #endif
  249. /* Pass on what ever char is there. */
  250. word[j++] = *(string)++;
  251. }
  252. }
  253. }
  254. else
  255. /* This char was not escaped, just add it. */
  256. word[j++] = *(string)++;
  257. }
  258. }
  259. break;
  260. case ' ':
  261. case '\t':
  262. /* Found the end of the word. */
  263. found = True;
  264. string++;
  265. break;
  266. default: {
  267. word[j++] = *(string)++;
  268. }
  269. }
  270. }
  271. }
  272. word [j] = '\0';
  273. *position = *position + (string - pbeg);
  274. }
  275. /*****************************************************************************
  276. *
  277. * GetWordWithQuotes - takes the strings "string" and "word" and an index
  278. * into "string" and fills "word" with one word from "string".
  279. *
  280. * A word is defined in the function "FillWord".
  281. *
  282. * Note that if an ending quote is not found, "position" will be advanced to
  283. * the end of the string.
  284. *
  285. * PARAMETERS:
  286. *
  287. * String string; - String containing the word to be extracted.
  288. *
  289. * String word; - MODIFIED - contains the next word in "string".
  290. *
  291. * int *position; - MODIFIED - starts at beginning of word, ends
  292. * at end of word.
  293. *
  294. *****************************************************************************/
  295. static void
  296. GetWordWithQuotes(
  297. String string,
  298. String word,
  299. int *position )
  300. {
  301. int len = strlen(string);
  302. SkipWhiteSpace (string, position);
  303. if ((*position) >= len) {
  304. word[0] = '\0';
  305. return;
  306. }
  307. string += (*position);
  308. FillWord (string, word, position);
  309. }
  310. /*****************************************************************************
  311. *
  312. * _DtCmdStringToArrayOfStrings - takes a string and an array of pointers
  313. * to strings and breaks the string into whitespace separated words.
  314. *
  315. * A "word" is a sequence of characters that has no whitespace with
  316. * the following exception:
  317. *
  318. * - A word may contain contain whitespace if it is delimited
  319. * by a pair of matching single or double qotes.
  320. *
  321. * "Whitespace" is a tab or blank character.
  322. *
  323. *
  324. * NOTES:
  325. *
  326. * - The space for the "words" is malloc'd and must be free'd by
  327. * the caller.
  328. *
  329. * - "theArray" is NULL terminated.
  330. *
  331. * PARAMETERS:
  332. *
  333. * char theString[]; - The string to parse.
  334. *
  335. * char *theArray[]; - MODIFIED: gets filled with pointers to
  336. * the words that are parsed.
  337. *
  338. *****************************************************************************/
  339. void
  340. _DtCmdStringToArrayOfStrings(
  341. char theString[],
  342. char *theArray[] )
  343. {
  344. int len, i, position;
  345. char *tmp;
  346. tmp = (char *) XtMalloc (1 + strlen (theString));
  347. len=strlen(theString);
  348. for (position=0, i=0; (position <= len) &&
  349. (theString[position] != '\0'); ) {
  350. (void) strcpy (tmp, "");
  351. GetWordWithQuotes (theString, tmp, &position);
  352. /* Check word to see if it contains only trailing blanks. */
  353. if (tmp[0] == '\0')
  354. {
  355. if (position < len)
  356. {
  357. /*
  358. * This parameter is empty, such as "" or '' but we are
  359. * not at the end of the line. Consequently, put an
  360. * empty string in "theArray".
  361. */
  362. theArray[i] = XtNewString ("");
  363. }
  364. else
  365. {
  366. /*
  367. * Must be at the end of the line.
  368. */
  369. theArray[i] = (char *) NULL;
  370. break;
  371. }
  372. }
  373. else
  374. theArray[i] = XtNewString (tmp);
  375. i++;
  376. }
  377. /* Null terminate the array of string pointers. */
  378. theArray[i]=NULL;
  379. XtFree ((char *) tmp);
  380. }
  381. /******************************************************************************
  382. *
  383. * _DtCmdFreeStringVector - takes an array of pointers to strings and
  384. * frees the malloc'd space for the strings.
  385. *
  386. * This does NOT free the string vector itself; It assumes that
  387. * stringv is a static i.e. char *stringv[N].
  388. *
  389. * PARAMETERS:
  390. *
  391. * char **stringv; - MODIFIED: Each string in the array is freed.
  392. *
  393. *****************************************************************************/
  394. void
  395. _DtCmdFreeStringVector(
  396. char **stringv )
  397. {
  398. char **pch;
  399. for (pch = stringv; *pch != NULL; pch++) {
  400. XtFree (*pch);
  401. *pch = NULL;
  402. }
  403. }