xref: /dragonfly/contrib/dialog/argv.c (revision a8e38dc0)
15382d832SPeter Avalos /*
2*a8e38dc0SAntonio Huete Jimenez  * $Id: argv.c,v 1.14 2022/04/03 22:38:16 tom Exp $
35382d832SPeter Avalos  *
45382d832SPeter Avalos  *  argv - Reusable functions for argv-parsing.
55382d832SPeter Avalos  *
6*a8e38dc0SAntonio Huete Jimenez  *  Copyright 2011-2020,2022	Thomas E. Dickey
75382d832SPeter Avalos  *
85382d832SPeter Avalos  *  This program is free software; you can redistribute it and/or modify
95382d832SPeter Avalos  *  it under the terms of the GNU Lesser General Public License, version 2.1
105382d832SPeter Avalos  *  as published by the Free Software Foundation.
115382d832SPeter Avalos  *
125382d832SPeter Avalos  *  This program is distributed in the hope that it will be useful, but
135382d832SPeter Avalos  *  WITHOUT ANY WARRANTY; without even the implied warranty of
145382d832SPeter Avalos  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
155382d832SPeter Avalos  *  Lesser General Public License for more details.
165382d832SPeter Avalos  *
175382d832SPeter Avalos  *  You should have received a copy of the GNU Lesser General Public
185382d832SPeter Avalos  *  License along with this program; if not, write to
195382d832SPeter Avalos  *	Free Software Foundation, Inc.
205382d832SPeter Avalos  *	51 Franklin St., Fifth Floor
215382d832SPeter Avalos  *	Boston, MA 02110, USA.
225382d832SPeter Avalos  */
235382d832SPeter Avalos 
24*a8e38dc0SAntonio Huete Jimenez #include <dlg_internals.h>
255382d832SPeter Avalos 
265382d832SPeter Avalos /*
275382d832SPeter Avalos  * Convert a string to an argv[], returning a char** index (which must be
285382d832SPeter Avalos  * freed by the caller).  The string is modified (replacing gaps between
295382d832SPeter Avalos  * tokens with nulls).
305382d832SPeter Avalos  */
315382d832SPeter Avalos char **
dlg_string_to_argv(char * blob)325382d832SPeter Avalos dlg_string_to_argv(char *blob)
335382d832SPeter Avalos {
345940c9abSDaniel Fojt     size_t n, k;
355382d832SPeter Avalos     int pass;
365382d832SPeter Avalos     size_t length = strlen(blob);
375382d832SPeter Avalos     char **result = 0;
385382d832SPeter Avalos 
395940c9abSDaniel Fojt #ifdef HAVE_DLG_TRACE
405940c9abSDaniel Fojt     if (dialog_state.trace_output) {
415940c9abSDaniel Fojt 	DLG_TRACE(("# dlg_string_to_argv:\n"));
425940c9abSDaniel Fojt 	DLG_TRACE(("# given:\n"));
435940c9abSDaniel Fojt 	for (n = k = 0; n < length; ++n) {
445940c9abSDaniel Fojt 	    if (blob[n] == '\n') {
455940c9abSDaniel Fojt 		DLG_TRACE(("#%s\t%.*s\\n\n",
465940c9abSDaniel Fojt 			   k ? "+" : "",
475940c9abSDaniel Fojt 			   (int) (n - k), blob + k));
485940c9abSDaniel Fojt 		k = n + 1;
495940c9abSDaniel Fojt 	    }
505940c9abSDaniel Fojt 	}
515940c9abSDaniel Fojt 	if (n > k) {
525940c9abSDaniel Fojt 	    DLG_TRACE(("#%s\t%.*s\n",
535940c9abSDaniel Fojt 		       k ? "+" : "",
545940c9abSDaniel Fojt 		       (int) (n - k), blob + k));
555940c9abSDaniel Fojt 	}
565940c9abSDaniel Fojt 	DLG_TRACE(("# result:\n"));
575940c9abSDaniel Fojt     }
585940c9abSDaniel Fojt #endif
595382d832SPeter Avalos     for (pass = 0; pass < 2; ++pass) {
605382d832SPeter Avalos 	bool inparm = FALSE;
615382d832SPeter Avalos 	bool quoted = FALSE;
625382d832SPeter Avalos 	char *param = blob;
635382d832SPeter Avalos 	size_t count = 0;
645382d832SPeter Avalos 
655382d832SPeter Avalos 	for (n = 0; n < length; ++n) {
665382d832SPeter Avalos 	    if (quoted && blob[n] == '"') {
675382d832SPeter Avalos 		quoted = FALSE;
685382d832SPeter Avalos 	    } else if (blob[n] == '"') {
695382d832SPeter Avalos 		quoted = TRUE;
705382d832SPeter Avalos 		if (!inparm) {
715940c9abSDaniel Fojt 		    if (pass) {
725382d832SPeter Avalos 			result[count] = param;
735940c9abSDaniel Fojt 		    }
745382d832SPeter Avalos 		    ++count;
755382d832SPeter Avalos 		    inparm = TRUE;
765382d832SPeter Avalos 		}
775382d832SPeter Avalos 	    } else if (!quoted && isspace(UCH(blob[n]))) {
781ef6786aSJohn Marino 		if (inparm) {
795382d832SPeter Avalos 		    if (pass) {
805940c9abSDaniel Fojt 			*param = '\0';
815382d832SPeter Avalos 		    }
825940c9abSDaniel Fojt 		    ++param;
831ef6786aSJohn Marino 		    inparm = FALSE;
841ef6786aSJohn Marino 		}
855382d832SPeter Avalos 	    } else {
865940c9abSDaniel Fojt 		if (blob[n] == '\\') {
875940c9abSDaniel Fojt 		    size_t n1 = (n + 1);
885940c9abSDaniel Fojt 		    bool ignore = FALSE;
895940c9abSDaniel Fojt 		    if (n1 == length) {
905940c9abSDaniel Fojt 			break;	/* The string is terminated by a backslash */
915940c9abSDaniel Fojt 		    } else if ((blob[n1] == '\\') ||
925940c9abSDaniel Fojt 			       (blob[n1] == '"') ||
935940c9abSDaniel Fojt 			       (ignore = (blob[n1] == '\n'))) {
945940c9abSDaniel Fojt 			/* eat the backslash */
955940c9abSDaniel Fojt 			if (pass) {
965940c9abSDaniel Fojt 			    --length;
975940c9abSDaniel Fojt 			    for (k = n; k < length; ++k)
985940c9abSDaniel Fojt 				blob[k] = blob[k + 1];
995940c9abSDaniel Fojt 			    blob[length] = '\0';
1005940c9abSDaniel Fojt 			} else {
1015940c9abSDaniel Fojt 			    ++param;	/* pretend I ate it */
1025940c9abSDaniel Fojt 			}
1035940c9abSDaniel Fojt 			if (ignore)
1045940c9abSDaniel Fojt 			    continue;
1055940c9abSDaniel Fojt 		    }
1065940c9abSDaniel Fojt 		}
1075382d832SPeter Avalos 		if (!inparm) {
1085940c9abSDaniel Fojt 		    if (pass) {
1095382d832SPeter Avalos 			result[count] = param;
1105940c9abSDaniel Fojt 		    }
1115382d832SPeter Avalos 		    ++count;
1125382d832SPeter Avalos 		    inparm = TRUE;
1135382d832SPeter Avalos 		}
1145382d832SPeter Avalos 		if (pass) {
1155940c9abSDaniel Fojt 		    *param = blob[n];
1165382d832SPeter Avalos 		}
1175940c9abSDaniel Fojt 		++param;
1185382d832SPeter Avalos 	    }
1195382d832SPeter Avalos 	}
1205382d832SPeter Avalos 
1215940c9abSDaniel Fojt 	if (pass) {
1225940c9abSDaniel Fojt 	    *param = '\0';
1235940c9abSDaniel Fojt 	} else {
1245382d832SPeter Avalos 	    if (count) {
1255382d832SPeter Avalos 		result = dlg_calloc(char *, count + 1);
1265382d832SPeter Avalos 		assert_ptr(result, "string_to_argv");
1275382d832SPeter Avalos 	    } else {
1285382d832SPeter Avalos 		break;		/* no tokens found */
1295382d832SPeter Avalos 	    }
1305382d832SPeter Avalos 	}
1315382d832SPeter Avalos     }
1321ef6786aSJohn Marino #ifdef HAVE_DLG_TRACE
1331ef6786aSJohn Marino     if (result != 0) {
1341ef6786aSJohn Marino 	for (n = 0; result[n] != 0; ++n) {
1351ef6786aSJohn Marino 	    DLG_TRACE(("#\targv[%d] = %s\n", (int) n, result[n]));
1361ef6786aSJohn Marino 	}
1371ef6786aSJohn Marino     }
1381ef6786aSJohn Marino #endif
1395382d832SPeter Avalos     return result;
1405382d832SPeter Avalos }
1415382d832SPeter Avalos 
1425382d832SPeter Avalos /*
1435382d832SPeter Avalos  * Count the entries in an argv list.
1445382d832SPeter Avalos  */
1455382d832SPeter Avalos int
dlg_count_argv(char ** argv)1465382d832SPeter Avalos dlg_count_argv(char **argv)
1475382d832SPeter Avalos {
1485382d832SPeter Avalos     int result = 0;
1495382d832SPeter Avalos 
1505382d832SPeter Avalos     if (argv != 0) {
1515382d832SPeter Avalos 	while (argv[result] != 0)
1525382d832SPeter Avalos 	    ++result;
1535382d832SPeter Avalos     }
1545382d832SPeter Avalos     return result;
1555382d832SPeter Avalos }
1565382d832SPeter Avalos 
1575382d832SPeter Avalos int
dlg_eat_argv(int * argcp,char *** argvp,int start,int count)1585382d832SPeter Avalos dlg_eat_argv(int *argcp, char ***argvp, int start, int count)
1595382d832SPeter Avalos {
1605382d832SPeter Avalos     int k;
1615382d832SPeter Avalos 
1625382d832SPeter Avalos     *argcp -= count;
1635382d832SPeter Avalos     for (k = start; k <= *argcp; k++)
1645382d832SPeter Avalos 	(*argvp)[k] = (*argvp)[k + count];
1655382d832SPeter Avalos     (*argvp)[*argcp] = 0;
1665382d832SPeter Avalos     return TRUE;
1675382d832SPeter Avalos }
168