1 /* 2 * $Id: argv.c,v 1.13 2020/03/26 02:55:37 tom Exp $ 3 * 4 * argv - Reusable functions for argv-parsing. 5 * 6 * Copyright 2011-2018,2020 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 <dialog.h> 25 #include <string.h> 26 27 /* 28 * Convert a string to an argv[], returning a char** index (which must be 29 * freed by the caller). The string is modified (replacing gaps between 30 * tokens with nulls). 31 */ 32 char ** 33 dlg_string_to_argv(char *blob) 34 { 35 size_t n, k; 36 int pass; 37 size_t length = strlen(blob); 38 char **result = 0; 39 40 #ifdef HAVE_DLG_TRACE 41 if (dialog_state.trace_output) { 42 DLG_TRACE(("# dlg_string_to_argv:\n")); 43 DLG_TRACE(("# given:\n")); 44 for (n = k = 0; n < length; ++n) { 45 if (blob[n] == '\n') { 46 DLG_TRACE(("#%s\t%.*s\\n\n", 47 k ? "+" : "", 48 (int) (n - k), blob + k)); 49 k = n + 1; 50 } 51 } 52 if (n > k) { 53 DLG_TRACE(("#%s\t%.*s\n", 54 k ? "+" : "", 55 (int) (n - k), blob + k)); 56 } 57 DLG_TRACE(("# result:\n")); 58 } 59 #endif 60 for (pass = 0; pass < 2; ++pass) { 61 bool inparm = FALSE; 62 bool quoted = FALSE; 63 char *param = blob; 64 size_t count = 0; 65 66 for (n = 0; n < length; ++n) { 67 if (quoted && blob[n] == '"') { 68 quoted = FALSE; 69 } else if (blob[n] == '"') { 70 quoted = TRUE; 71 if (!inparm) { 72 if (pass) { 73 result[count] = param; 74 } 75 ++count; 76 inparm = TRUE; 77 } 78 } else if (!quoted && isspace(UCH(blob[n]))) { 79 if (inparm) { 80 if (pass) { 81 *param = '\0'; 82 } 83 ++param; 84 inparm = FALSE; 85 } 86 } else { 87 if (blob[n] == '\\') { 88 size_t n1 = (n + 1); 89 bool ignore = FALSE; 90 if (n1 == length) { 91 break; /* The string is terminated by a backslash */ 92 } else if ((blob[n1] == '\\') || 93 (blob[n1] == '"') || 94 (ignore = (blob[n1] == '\n'))) { 95 /* eat the backslash */ 96 if (pass) { 97 --length; 98 for (k = n; k < length; ++k) 99 blob[k] = blob[k + 1]; 100 blob[length] = '\0'; 101 } else { 102 ++param; /* pretend I ate it */ 103 } 104 if (ignore) 105 continue; 106 } 107 } 108 if (!inparm) { 109 if (pass) { 110 result[count] = param; 111 } 112 ++count; 113 inparm = TRUE; 114 } 115 if (pass) { 116 *param = blob[n]; 117 } 118 ++param; 119 } 120 } 121 122 if (pass) { 123 *param = '\0'; 124 } else { 125 if (count) { 126 result = dlg_calloc(char *, count + 1); 127 assert_ptr(result, "string_to_argv"); 128 } else { 129 break; /* no tokens found */ 130 } 131 } 132 } 133 #ifdef HAVE_DLG_TRACE 134 if (result != 0) { 135 for (n = 0; result[n] != 0; ++n) { 136 DLG_TRACE(("#\targv[%d] = %s\n", (int) n, result[n])); 137 } 138 } 139 #endif 140 return result; 141 } 142 143 /* 144 * Count the entries in an argv list. 145 */ 146 int 147 dlg_count_argv(char **argv) 148 { 149 int result = 0; 150 151 if (argv != 0) { 152 while (argv[result] != 0) 153 ++result; 154 } 155 return result; 156 } 157 158 int 159 dlg_eat_argv(int *argcp, char ***argvp, int start, int count) 160 { 161 int k; 162 163 *argcp -= count; 164 for (k = start; k <= *argcp; k++) 165 (*argvp)[k] = (*argvp)[k + count]; 166 (*argvp)[*argcp] = 0; 167 return TRUE; 168 } 169