1 /* 2 * $Id: argv.c,v 1.14 2022/04/03 22:38:16 tom Exp $ 3 * 4 * argv - Reusable functions for argv-parsing. 5 * 6 * Copyright 2011-2020,2022 Thomas E. Dickey 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU Lesser General Public License, version 2.1 10 * as published by the Free Software Foundation. 11 * 12 * This program is distributed in the hope that it will be useful, but 13 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this program; if not, write to 19 * Free Software Foundation, Inc. 20 * 51 Franklin St., Fifth Floor 21 * Boston, MA 02110, USA. 22 */ 23 24 #include <dlg_internals.h> 25 26 /* 27 * Convert a string to an argv[], returning a char** index (which must be 28 * freed by the caller). The string is modified (replacing gaps between 29 * tokens with nulls). 30 */ 31 char ** 32 dlg_string_to_argv(char *blob) 33 { 34 size_t n, k; 35 int pass; 36 size_t length = strlen(blob); 37 char **result = 0; 38 39 #ifdef HAVE_DLG_TRACE 40 if (dialog_state.trace_output) { 41 DLG_TRACE(("# dlg_string_to_argv:\n")); 42 DLG_TRACE(("# given:\n")); 43 for (n = k = 0; n < length; ++n) { 44 if (blob[n] == '\n') { 45 DLG_TRACE(("#%s\t%.*s\\n\n", 46 k ? "+" : "", 47 (int) (n - k), blob + k)); 48 k = n + 1; 49 } 50 } 51 if (n > k) { 52 DLG_TRACE(("#%s\t%.*s\n", 53 k ? "+" : "", 54 (int) (n - k), blob + k)); 55 } 56 DLG_TRACE(("# result:\n")); 57 } 58 #endif 59 for (pass = 0; pass < 2; ++pass) { 60 bool inparm = FALSE; 61 bool quoted = FALSE; 62 char *param = blob; 63 size_t count = 0; 64 65 for (n = 0; n < length; ++n) { 66 if (quoted && blob[n] == '"') { 67 quoted = FALSE; 68 } else if (blob[n] == '"') { 69 quoted = TRUE; 70 if (!inparm) { 71 if (pass) { 72 result[count] = param; 73 } 74 ++count; 75 inparm = TRUE; 76 } 77 } else if (!quoted && isspace(UCH(blob[n]))) { 78 if (inparm) { 79 if (pass) { 80 *param = '\0'; 81 } 82 ++param; 83 inparm = FALSE; 84 } 85 } else { 86 if (blob[n] == '\\') { 87 size_t n1 = (n + 1); 88 bool ignore = FALSE; 89 if (n1 == length) { 90 break; /* The string is terminated by a backslash */ 91 } else if ((blob[n1] == '\\') || 92 (blob[n1] == '"') || 93 (ignore = (blob[n1] == '\n'))) { 94 /* eat the backslash */ 95 if (pass) { 96 --length; 97 for (k = n; k < length; ++k) 98 blob[k] = blob[k + 1]; 99 blob[length] = '\0'; 100 } else { 101 ++param; /* pretend I ate it */ 102 } 103 if (ignore) 104 continue; 105 } 106 } 107 if (!inparm) { 108 if (pass) { 109 result[count] = param; 110 } 111 ++count; 112 inparm = TRUE; 113 } 114 if (pass) { 115 *param = blob[n]; 116 } 117 ++param; 118 } 119 } 120 121 if (pass) { 122 *param = '\0'; 123 } else { 124 if (count) { 125 result = dlg_calloc(char *, count + 1); 126 assert_ptr(result, "string_to_argv"); 127 } else { 128 break; /* no tokens found */ 129 } 130 } 131 } 132 #ifdef HAVE_DLG_TRACE 133 if (result != 0) { 134 for (n = 0; result[n] != 0; ++n) { 135 DLG_TRACE(("#\targv[%d] = %s\n", (int) n, result[n])); 136 } 137 } 138 #endif 139 return result; 140 } 141 142 /* 143 * Count the entries in an argv list. 144 */ 145 int 146 dlg_count_argv(char **argv) 147 { 148 int result = 0; 149 150 if (argv != 0) { 151 while (argv[result] != 0) 152 ++result; 153 } 154 return result; 155 } 156 157 int 158 dlg_eat_argv(int *argcp, char ***argvp, int start, int count) 159 { 160 int k; 161 162 *argcp -= count; 163 for (k = start; k <= *argcp; k++) 164 (*argvp)[k] = (*argvp)[k + count]; 165 (*argvp)[*argcp] = 0; 166 return TRUE; 167 } 168