xref: /freebsd/contrib/dialog/argv.c (revision a96ef4501919d7ac08e94e98dc34b0bdd744802b)
17a1c0d96SNathan Whitehorn /*
2*a96ef450SBaptiste Daroussin  * $Id: argv.c,v 1.13 2020/03/26 02:55:37 tom Exp $
37a1c0d96SNathan Whitehorn  *
47a1c0d96SNathan Whitehorn  *  argv - Reusable functions for argv-parsing.
57a1c0d96SNathan Whitehorn  *
6*a96ef450SBaptiste Daroussin  *  Copyright 2011-2018,2020	Thomas E. Dickey
77a1c0d96SNathan Whitehorn  *
87a1c0d96SNathan Whitehorn  *  This program is free software; you can redistribute it and/or modify
97a1c0d96SNathan Whitehorn  *  it under the terms of the GNU Lesser General Public License, version 2.1
107a1c0d96SNathan Whitehorn  *  as published by the Free Software Foundation.
117a1c0d96SNathan Whitehorn  *
127a1c0d96SNathan Whitehorn  *  This program is distributed in the hope that it will be useful, but
137a1c0d96SNathan Whitehorn  *  WITHOUT ANY WARRANTY; without even the implied warranty of
147a1c0d96SNathan Whitehorn  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
157a1c0d96SNathan Whitehorn  *  Lesser General Public License for more details.
167a1c0d96SNathan Whitehorn  *
177a1c0d96SNathan Whitehorn  *  You should have received a copy of the GNU Lesser General Public
187a1c0d96SNathan Whitehorn  *  License along with this program; if not, write to
197a1c0d96SNathan Whitehorn  *	Free Software Foundation, Inc.
207a1c0d96SNathan Whitehorn  *	51 Franklin St., Fifth Floor
217a1c0d96SNathan Whitehorn  *	Boston, MA 02110, USA.
227a1c0d96SNathan Whitehorn  */
237a1c0d96SNathan Whitehorn 
247a1c0d96SNathan Whitehorn #include <dialog.h>
257a1c0d96SNathan Whitehorn #include <string.h>
267a1c0d96SNathan Whitehorn 
277a1c0d96SNathan Whitehorn /*
287a1c0d96SNathan Whitehorn  * Convert a string to an argv[], returning a char** index (which must be
297a1c0d96SNathan Whitehorn  * freed by the caller).  The string is modified (replacing gaps between
307a1c0d96SNathan Whitehorn  * tokens with nulls).
317a1c0d96SNathan Whitehorn  */
327a1c0d96SNathan Whitehorn char **
dlg_string_to_argv(char * blob)337a1c0d96SNathan Whitehorn dlg_string_to_argv(char *blob)
347a1c0d96SNathan Whitehorn {
35f4f33ea0SBaptiste Daroussin     size_t n, k;
367a1c0d96SNathan Whitehorn     int pass;
377a1c0d96SNathan Whitehorn     size_t length = strlen(blob);
387a1c0d96SNathan Whitehorn     char **result = 0;
397a1c0d96SNathan Whitehorn 
40f4f33ea0SBaptiste Daroussin #ifdef HAVE_DLG_TRACE
41f4f33ea0SBaptiste Daroussin     if (dialog_state.trace_output) {
42f4f33ea0SBaptiste Daroussin 	DLG_TRACE(("# dlg_string_to_argv:\n"));
43f4f33ea0SBaptiste Daroussin 	DLG_TRACE(("# given:\n"));
44f4f33ea0SBaptiste Daroussin 	for (n = k = 0; n < length; ++n) {
45f4f33ea0SBaptiste Daroussin 	    if (blob[n] == '\n') {
46f4f33ea0SBaptiste Daroussin 		DLG_TRACE(("#%s\t%.*s\\n\n",
47f4f33ea0SBaptiste Daroussin 			   k ? "+" : "",
48f4f33ea0SBaptiste Daroussin 			   (int) (n - k), blob + k));
49f4f33ea0SBaptiste Daroussin 		k = n + 1;
50f4f33ea0SBaptiste Daroussin 	    }
51f4f33ea0SBaptiste Daroussin 	}
52f4f33ea0SBaptiste Daroussin 	if (n > k) {
53f4f33ea0SBaptiste Daroussin 	    DLG_TRACE(("#%s\t%.*s\n",
54f4f33ea0SBaptiste Daroussin 		       k ? "+" : "",
55f4f33ea0SBaptiste Daroussin 		       (int) (n - k), blob + k));
56f4f33ea0SBaptiste Daroussin 	}
57f4f33ea0SBaptiste Daroussin 	DLG_TRACE(("# result:\n"));
58f4f33ea0SBaptiste Daroussin     }
59f4f33ea0SBaptiste Daroussin #endif
607a1c0d96SNathan Whitehorn     for (pass = 0; pass < 2; ++pass) {
617a1c0d96SNathan Whitehorn 	bool inparm = FALSE;
627a1c0d96SNathan Whitehorn 	bool quoted = FALSE;
637a1c0d96SNathan Whitehorn 	char *param = blob;
647a1c0d96SNathan Whitehorn 	size_t count = 0;
657a1c0d96SNathan Whitehorn 
667a1c0d96SNathan Whitehorn 	for (n = 0; n < length; ++n) {
67*a96ef450SBaptiste Daroussin 	    if (quoted && blob[n] == '"') {
687a1c0d96SNathan Whitehorn 		quoted = FALSE;
697a1c0d96SNathan Whitehorn 	    } else if (blob[n] == '"') {
707a1c0d96SNathan Whitehorn 		quoted = TRUE;
717a1c0d96SNathan Whitehorn 		if (!inparm) {
72*a96ef450SBaptiste Daroussin 		    if (pass) {
737a1c0d96SNathan Whitehorn 			result[count] = param;
74*a96ef450SBaptiste Daroussin 		    }
757a1c0d96SNathan Whitehorn 		    ++count;
767a1c0d96SNathan Whitehorn 		    inparm = TRUE;
777a1c0d96SNathan Whitehorn 		}
787a1c0d96SNathan Whitehorn 	    } else if (!quoted && isspace(UCH(blob[n]))) {
79f4f33ea0SBaptiste Daroussin 		if (inparm) {
807a1c0d96SNathan Whitehorn 		    if (pass) {
81*a96ef450SBaptiste Daroussin 			*param = '\0';
827a1c0d96SNathan Whitehorn 		    }
83*a96ef450SBaptiste Daroussin 		    ++param;
84f4f33ea0SBaptiste Daroussin 		    inparm = FALSE;
85f4f33ea0SBaptiste Daroussin 		}
867a1c0d96SNathan Whitehorn 	    } else {
87f4f33ea0SBaptiste Daroussin 		if (blob[n] == '\\') {
88*a96ef450SBaptiste Daroussin 		    size_t n1 = (n + 1);
89*a96ef450SBaptiste Daroussin 		    bool ignore = FALSE;
90*a96ef450SBaptiste Daroussin 		    if (n1 == length) {
91f4f33ea0SBaptiste Daroussin 			break;	/* The string is terminated by a backslash */
92*a96ef450SBaptiste Daroussin 		    } else if ((blob[n1] == '\\') ||
93*a96ef450SBaptiste Daroussin 			       (blob[n1] == '"') ||
94*a96ef450SBaptiste Daroussin 			       (ignore = (blob[n1] == '\n'))) {
95f4f33ea0SBaptiste Daroussin 			/* eat the backslash */
96f4f33ea0SBaptiste Daroussin 			if (pass) {
97f4f33ea0SBaptiste Daroussin 			    --length;
98f4f33ea0SBaptiste Daroussin 			    for (k = n; k < length; ++k)
99f4f33ea0SBaptiste Daroussin 				blob[k] = blob[k + 1];
100f4f33ea0SBaptiste Daroussin 			    blob[length] = '\0';
101f4f33ea0SBaptiste Daroussin 			} else {
102*a96ef450SBaptiste Daroussin 			    ++param;	/* pretend I ate it */
103*a96ef450SBaptiste Daroussin 			}
104*a96ef450SBaptiste Daroussin 			if (ignore)
105f4f33ea0SBaptiste Daroussin 			    continue;
106f4f33ea0SBaptiste Daroussin 		    }
107f4f33ea0SBaptiste Daroussin 		}
1087a1c0d96SNathan Whitehorn 		if (!inparm) {
109*a96ef450SBaptiste Daroussin 		    if (pass) {
1107a1c0d96SNathan Whitehorn 			result[count] = param;
111*a96ef450SBaptiste Daroussin 		    }
1127a1c0d96SNathan Whitehorn 		    ++count;
1137a1c0d96SNathan Whitehorn 		    inparm = TRUE;
1147a1c0d96SNathan Whitehorn 		}
1157a1c0d96SNathan Whitehorn 		if (pass) {
116*a96ef450SBaptiste Daroussin 		    *param = blob[n];
1177a1c0d96SNathan Whitehorn 		}
118*a96ef450SBaptiste Daroussin 		++param;
1197a1c0d96SNathan Whitehorn 	    }
1207a1c0d96SNathan Whitehorn 	}
1217a1c0d96SNathan Whitehorn 
122*a96ef450SBaptiste Daroussin 	if (pass) {
123*a96ef450SBaptiste Daroussin 	    *param = '\0';
124*a96ef450SBaptiste Daroussin 	} else {
1257a1c0d96SNathan Whitehorn 	    if (count) {
1267a1c0d96SNathan Whitehorn 		result = dlg_calloc(char *, count + 1);
1277a1c0d96SNathan Whitehorn 		assert_ptr(result, "string_to_argv");
1287a1c0d96SNathan Whitehorn 	    } else {
1297a1c0d96SNathan Whitehorn 		break;		/* no tokens found */
1307a1c0d96SNathan Whitehorn 	    }
1317a1c0d96SNathan Whitehorn 	}
1327a1c0d96SNathan Whitehorn     }
133f4f33ea0SBaptiste Daroussin #ifdef HAVE_DLG_TRACE
134f4f33ea0SBaptiste Daroussin     if (result != 0) {
135f4f33ea0SBaptiste Daroussin 	for (n = 0; result[n] != 0; ++n) {
136f4f33ea0SBaptiste Daroussin 	    DLG_TRACE(("#\targv[%d] = %s\n", (int) n, result[n]));
137f4f33ea0SBaptiste Daroussin 	}
138f4f33ea0SBaptiste Daroussin     }
139f4f33ea0SBaptiste Daroussin #endif
1407a1c0d96SNathan Whitehorn     return result;
1417a1c0d96SNathan Whitehorn }
1427a1c0d96SNathan Whitehorn 
1437a1c0d96SNathan Whitehorn /*
1447a1c0d96SNathan Whitehorn  * Count the entries in an argv list.
1457a1c0d96SNathan Whitehorn  */
1467a1c0d96SNathan Whitehorn int
dlg_count_argv(char ** argv)1477a1c0d96SNathan Whitehorn dlg_count_argv(char **argv)
1487a1c0d96SNathan Whitehorn {
1497a1c0d96SNathan Whitehorn     int result = 0;
1507a1c0d96SNathan Whitehorn 
1517a1c0d96SNathan Whitehorn     if (argv != 0) {
1527a1c0d96SNathan Whitehorn 	while (argv[result] != 0)
1537a1c0d96SNathan Whitehorn 	    ++result;
1547a1c0d96SNathan Whitehorn     }
1557a1c0d96SNathan Whitehorn     return result;
1567a1c0d96SNathan Whitehorn }
1577a1c0d96SNathan Whitehorn 
1587a1c0d96SNathan Whitehorn int
dlg_eat_argv(int * argcp,char *** argvp,int start,int count)1597a1c0d96SNathan Whitehorn dlg_eat_argv(int *argcp, char ***argvp, int start, int count)
1607a1c0d96SNathan Whitehorn {
1617a1c0d96SNathan Whitehorn     int k;
1627a1c0d96SNathan Whitehorn 
1637a1c0d96SNathan Whitehorn     *argcp -= count;
1647a1c0d96SNathan Whitehorn     for (k = start; k <= *argcp; k++)
1657a1c0d96SNathan Whitehorn 	(*argvp)[k] = (*argvp)[k + count];
1667a1c0d96SNathan Whitehorn     (*argvp)[*argcp] = 0;
1677a1c0d96SNathan Whitehorn     return TRUE;
1687a1c0d96SNathan Whitehorn }
169