fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
at master 364 lines 6.4 kB view raw
1/***************************************************************************** 2 * pce * 3 *****************************************************************************/ 4 5/***************************************************************************** 6 * File name: src/lib/getopt.c * 7 * Created: 2009-14-21 by Hampa Hug <hampa@hampa.ch> * 8 * Copyright: (C) 2009-2020 Hampa Hug <hampa@hampa.ch> * 9 *****************************************************************************/ 10 11/***************************************************************************** 12 * This program is free software. You can redistribute it and / or modify it * 13 * under the terms of the GNU General Public License version 2 as published * 14 * by the Free Software Foundation. * 15 * * 16 * This program is distributed in the hope that it will be useful, but * 17 * WITHOUT ANY WARRANTY, without even the implied warranty of * 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * 19 * Public License for more details. * 20 *****************************************************************************/ 21 22 23#include <ctype.h> 24#include <stdio.h> 25#include <stdlib.h> 26#include <string.h> 27 28#include <lib/getopt.h> 29 30 31static int atend = 0; 32static int index1 = -1; 33static int index2 = -1; 34static const char *curopt = NULL; 35 36 37static 38int opt_cmp (const pce_option_t *opt1, const pce_option_t *opt2) 39{ 40 int c1, c2; 41 42 c1 = (opt1->name1 <= 255) ? tolower (opt1->name1) : opt1->name1; 43 c2 = (opt2->name1 <= 255) ? tolower (opt2->name1) : opt2->name1; 44 45 if (c1 < c2) { 46 return (-1); 47 } 48 else if (c1 > c2) { 49 return (1); 50 } 51 else if (opt1->name1 < opt2->name1) { 52 return (1); 53 } 54 else if (opt1->name1 > opt2->name1) { 55 return (-1); 56 } 57 58 return (0); 59} 60 61static 62unsigned opt_get_width (const pce_option_t *opt) 63{ 64 unsigned n; 65 66 if (opt->optdesc == NULL) { 67 return (0); 68 } 69 70 n = 0; 71 72 if (opt->name1 <= 255) { 73 n += 2; 74 75 if (opt->name2 != NULL) { 76 n += 2; 77 } 78 } 79 80 if (opt->name2 != NULL) { 81 n += 2 + strlen (opt->name2); 82 } 83 84 if (opt->argdesc != NULL) { 85 n += 1 + strlen (opt->argdesc); 86 } 87 88 return (n); 89} 90 91static 92unsigned opt_max_width (const pce_option_t *opt) 93{ 94 unsigned i, n, w; 95 96 w = 0; 97 98 i = 0; 99 while (opt[i].name1 >= 0) { 100 n = opt_get_width (&opt[i]); 101 102 if (n > w) { 103 w = n; 104 } 105 106 i += 1; 107 } 108 109 return (w); 110} 111 112static 113void sort_options (pce_option_t *opt) 114{ 115 unsigned i, j; 116 pce_option_t tmp; 117 118 if (opt[0].name1 < 0) { 119 return; 120 } 121 122 i = 1; 123 while (opt[i].name1 >= 0) { 124 if (opt_cmp (&opt[i], &opt[i - 1]) >= 0) { 125 i += 1; 126 continue; 127 } 128 129 j = i - 1; 130 131 tmp = opt[i]; 132 opt[i] = opt[j]; 133 134 while ((j > 0) && (opt_cmp (&tmp, &opt[j - 1]) < 0)) { 135 opt[j] = opt[j - 1]; 136 j -= 1; 137 } 138 139 opt[j] = tmp; 140 141 i += 1; 142 } 143} 144 145static 146void print_option (const pce_option_t *opt, unsigned w) 147{ 148 unsigned n; 149 150 n = 0; 151 152 if (opt->name1 <= 255) { 153 printf (" -%c", opt->name1); 154 n += 2; 155 156 if (opt->name2 != NULL) { 157 printf (", "); 158 n += 2; 159 } 160 } 161 else { 162 printf (" "); 163 } 164 165 if (opt->name2 != NULL) { 166 printf ("--%s", opt->name2); 167 n += 2 + strlen (opt->name2); 168 } 169 170 if (opt->argdesc != NULL) { 171 printf (" %s", opt->argdesc); 172 n += 1 + strlen (opt->argdesc); 173 } 174 175 while (n < w) { 176 fputc (' ', stdout); 177 n += 1; 178 } 179 180 printf ("%s\n", opt->optdesc); 181} 182 183void pce_getopt_help (const char *tag, const char *usage, pce_option_t *opt) 184{ 185 unsigned w; 186 187 sort_options (opt); 188 189 w = opt_max_width (opt); 190 191 if (tag != NULL) { 192 printf ("%s\n\n", tag); 193 } 194 195 if (usage != NULL) { 196 printf ("%s\n", usage); 197 } 198 199 while (opt->name1 >= 0) { 200 print_option (opt, w + 2); 201 opt += 1; 202 } 203} 204 205static 206pce_option_t *find_option_name1 (pce_option_t *opt, int name1) 207{ 208 while (opt->name1 >= 0) { 209 if (opt->name1 == name1) { 210 return (opt); 211 } 212 213 opt += 1; 214 } 215 216 return (NULL); 217} 218 219static 220pce_option_t *find_option_name2 (pce_option_t *opt, const char *name2) 221{ 222 while (opt->name1 >= 0) { 223 if (strcmp (opt->name2, name2) == 0) { 224 return (opt); 225 } 226 227 opt += 1; 228 } 229 230 return (NULL); 231} 232 233int pce_getoptarg (int argc, char **argv, char ***optarg, unsigned cnt) 234{ 235 if (index1 < 0) { 236 atend = 0; 237 index1 = 0; 238 index2 = 1; 239 curopt = NULL; 240 } 241 242 if ((index2 + cnt) > argc) { 243 return (GETOPT_MISSING); 244 } 245 246 index1 = index2; 247 index2 += cnt; 248 249 *optarg = argv + index1; 250 251 return (0); 252} 253 254int pce_getopt (int argc, char **argv, char ***optarg, pce_option_t *opt) 255{ 256 pce_option_t *ret; 257 258 if ((argc == 0) && (argv == NULL)) { 259 index1 = -1; 260 return (0); 261 } 262 263 if (index1 < 0) { 264 atend = 0; 265 index1 = 0; 266 index2 = 1; 267 curopt = NULL; 268 } 269 270 if (atend || (opt == NULL)) { 271 if (index2 >= argc) { 272 return (GETOPT_DONE); 273 } 274 275 index1 = index2; 276 index2 += 1; 277 278 *optarg = argv + index1; 279 280 return (0); 281 } 282 283 if ((curopt == NULL) || (*curopt == 0)) { 284 if (index2 >= argc) { 285 return (GETOPT_DONE); 286 } 287 288 index1 = index2; 289 index2 += 1; 290 291 curopt = argv[index1]; 292 293 if ((curopt[0] != '-') || (curopt[1] == 0)) { 294 *optarg = argv + index1; 295 curopt = NULL; 296 return (0); 297 } 298 299 if (curopt[1] == '-') { 300 if (curopt[2] == 0) { 301 atend = 1; 302 303 if (index2 >= argc) { 304 return (GETOPT_DONE); 305 } 306 307 index1 = index2; 308 index2 += 1; 309 310 *optarg = argv + index1; 311 312 return (0); 313 } 314 315 ret = find_option_name2 (opt, curopt + 2); 316 317 if (ret == NULL) { 318 fprintf (stderr, "%s: unknown option (%s)\n", 319 argv[0], curopt 320 ); 321 return (GETOPT_UNKNOWN); 322 } 323 324 if ((index2 + ret->argcnt) > argc) { 325 fprintf (stderr, 326 "%s: missing option argument (%s)\n", 327 argv[0], curopt 328 ); 329 return (GETOPT_MISSING); 330 } 331 332 *optarg = argv + index2; 333 index2 += ret->argcnt; 334 curopt = NULL; 335 336 return (ret->name1); 337 } 338 339 curopt += 1; 340 } 341 342 ret = find_option_name1 (opt, *curopt); 343 344 if (ret == NULL) { 345 fprintf (stderr, "%s: unknown option (-%c)\n", 346 argv[0], *curopt 347 ); 348 return (GETOPT_UNKNOWN); 349 } 350 351 if ((index2 + ret->argcnt) > argc) { 352 fprintf (stderr, 353 "%s: missing option argument (-%c)\n", 354 argv[0], *curopt 355 ); 356 return (GETOPT_MISSING); 357 } 358 359 *optarg = argv + index2; 360 index2 += ret->argcnt; 361 curopt += 1; 362 363 return (ret->name1); 364}