1 1.1 pgoyette /* $NetBSD: h_getopt_long.c,v 1.1 2011/01/01 23:56:49 pgoyette Exp $ */ 2 1.1 pgoyette 3 1.1 pgoyette /*- 4 1.1 pgoyette * Copyright (c) 2007 The NetBSD Foundation, Inc. 5 1.1 pgoyette * All rights reserved. 6 1.1 pgoyette * 7 1.1 pgoyette * This code is derived from software contributed to The NetBSD Foundation 8 1.1 pgoyette * by Christos Zoulas. 9 1.1 pgoyette * 10 1.1 pgoyette * Redistribution and use in source and binary forms, with or without 11 1.1 pgoyette * modification, are permitted provided that the following conditions 12 1.1 pgoyette * are met: 13 1.1 pgoyette * 1. Redistributions of source code must retain the above copyright 14 1.1 pgoyette * notice, this list of conditions and the following disclaimer. 15 1.1 pgoyette * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 pgoyette * notice, this list of conditions and the following disclaimer in the 17 1.1 pgoyette * documentation and/or other materials provided with the distribution. 18 1.1 pgoyette * 19 1.1 pgoyette * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 pgoyette * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 pgoyette * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 pgoyette * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 pgoyette * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 pgoyette * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 pgoyette * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 pgoyette * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 pgoyette * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 pgoyette * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 pgoyette * POSSIBILITY OF SUCH DAMAGE. 30 1.1 pgoyette */ 31 1.1 pgoyette 32 1.1 pgoyette #include <ctype.h> 33 1.1 pgoyette #include <err.h> 34 1.1 pgoyette #include <getopt.h> 35 1.1 pgoyette #include <stdio.h> 36 1.1 pgoyette #include <string.h> 37 1.1 pgoyette #include <stdlib.h> 38 1.1 pgoyette #include <unistd.h> 39 1.1 pgoyette 40 1.1 pgoyette #define SKIPWS(p) while (isspace((int)(*p))) p++ 41 1.1 pgoyette #define WS "\t\n " 42 1.1 pgoyette 43 1.1 pgoyette int 44 1.1 pgoyette main(int argc, char *argv[]) 45 1.1 pgoyette { 46 1.1 pgoyette size_t len, lineno = 0; 47 1.1 pgoyette char *line, *eptr, *longopt, *ptr, *optstring = NULL, *result = NULL; 48 1.1 pgoyette char buf[1024]; 49 1.1 pgoyette char *args[128]; 50 1.1 pgoyette char arg[256]; 51 1.1 pgoyette int nargs = -1; 52 1.1 pgoyette int c; 53 1.1 pgoyette int nlongopts = 0; 54 1.1 pgoyette int maxnlongopts = 0; 55 1.1 pgoyette int *longopt_flags = NULL; 56 1.1 pgoyette struct option *longopts = NULL; 57 1.1 pgoyette 58 1.1 pgoyette while ((line = fparseln(stdin, &len, &lineno, NULL, 0)) != NULL) { 59 1.1 pgoyette if (strncmp(line, "optstring:", 10) == 0) { 60 1.1 pgoyette if (optstring) 61 1.1 pgoyette free(optstring); 62 1.1 pgoyette optstring = strtok(&line[11], WS); 63 1.1 pgoyette if (optstring == NULL) 64 1.1 pgoyette errx(1, "missing optstring at line %ld", 65 1.1 pgoyette (unsigned long)lineno); 66 1.1 pgoyette optstring = strdup(optstring); 67 1.1 pgoyette } else if (strncmp(line, "longopts:", 9) == 0) { 68 1.1 pgoyette if (longopts) { 69 1.1 pgoyette int i; 70 1.1 pgoyette for (i = 0; i < nlongopts; i++) 71 1.1 pgoyette if (longopts[i].name != NULL) 72 1.1 pgoyette free(__UNCONST(longopts[i].name)); 73 1.1 pgoyette free(longopts); 74 1.1 pgoyette } 75 1.1 pgoyette if (longopt_flags) 76 1.1 pgoyette free(longopt_flags); 77 1.1 pgoyette nlongopts = 0; 78 1.1 pgoyette ptr = strtok(&line[10], WS); 79 1.1 pgoyette if (ptr == NULL) 80 1.1 pgoyette errx(1, "missing longopts at line %ld", 81 1.1 pgoyette (unsigned long)lineno); 82 1.1 pgoyette maxnlongopts = strtoul(ptr, &eptr, 10); 83 1.1 pgoyette if (*eptr != '\0') 84 1.1 pgoyette warnx("garbage in longopts at line %ld", 85 1.1 pgoyette (unsigned long)lineno); 86 1.1 pgoyette maxnlongopts++; /* space for trailer */ 87 1.1 pgoyette longopts = 88 1.1 pgoyette (struct option *)calloc(sizeof(struct option), 89 1.1 pgoyette maxnlongopts); 90 1.1 pgoyette if (longopts == NULL) 91 1.1 pgoyette err(1, "calloc"); 92 1.1 pgoyette longopt_flags = (int *)calloc(sizeof(int), maxnlongopts); 93 1.1 pgoyette if (longopt_flags == NULL) 94 1.1 pgoyette err(1, "calloc"); 95 1.1 pgoyette } else if (strncmp(line, "longopt:", 8) == 0) { 96 1.1 pgoyette if (longopts == NULL) 97 1.1 pgoyette errx(1, "longopt: without longopts at line %ld", 98 1.1 pgoyette (unsigned long)lineno); 99 1.1 pgoyette if (nlongopts >= maxnlongopts) 100 1.1 pgoyette errx(1, "longopt: too many options at line %ld", 101 1.1 pgoyette (unsigned long)lineno); 102 1.1 pgoyette /* name */ 103 1.1 pgoyette ptr = &line[9]; 104 1.1 pgoyette SKIPWS(ptr); 105 1.1 pgoyette longopt = strsep(&ptr, ","); 106 1.1 pgoyette if (longopt == NULL) 107 1.1 pgoyette errx(1, "missing longopt at line %ld", 108 1.1 pgoyette (unsigned long)lineno); 109 1.1 pgoyette longopts[nlongopts].name = strdup(longopt); 110 1.1 pgoyette /* has_arg */ 111 1.1 pgoyette SKIPWS(ptr); 112 1.1 pgoyette longopt = strsep(&ptr, ","); 113 1.1 pgoyette if (*longopt != '\0') { 114 1.1 pgoyette if (strncmp(longopt, "0", 1) == 0 || 115 1.1 pgoyette strncmp(longopt, "no_argument", 2) == 0) 116 1.1 pgoyette longopts[nlongopts].has_arg = no_argument; 117 1.1 pgoyette else if (strncmp(longopt, "1", 1) == 0 || 118 1.1 pgoyette strncmp(longopt, "required_argument", 8) == 0) 119 1.1 pgoyette longopts[nlongopts].has_arg = required_argument; 120 1.1 pgoyette else if (strncmp(longopt, "2", 1) == 0 || 121 1.1 pgoyette strncmp(longopt, "optional_argument", 8) == 0) 122 1.1 pgoyette longopts[nlongopts].has_arg = optional_argument; 123 1.1 pgoyette else 124 1.1 pgoyette errx(1, "unknown has_arg %s at line %ld", 125 1.1 pgoyette longopt, (unsigned long)lineno); 126 1.1 pgoyette } 127 1.1 pgoyette /* flag */ 128 1.1 pgoyette SKIPWS(ptr); 129 1.1 pgoyette longopt = strsep(&ptr, ","); 130 1.1 pgoyette if (*longopt != '\0' && 131 1.1 pgoyette strncmp(longopt, "NULL", 4) != 0) 132 1.1 pgoyette longopts[nlongopts].flag = &longopt_flags[nlongopts]; 133 1.1 pgoyette /* val */ 134 1.1 pgoyette SKIPWS(ptr); 135 1.1 pgoyette longopt = strsep(&ptr, ","); 136 1.1 pgoyette if (*longopt == '\0') 137 1.1 pgoyette errx(1, "missing val at line %ld", 138 1.1 pgoyette (unsigned long)lineno); 139 1.1 pgoyette if (*longopt != '\'') { 140 1.1 pgoyette longopts[nlongopts].val = 141 1.1 pgoyette (int)strtoul(longopt, &eptr, 10); 142 1.1 pgoyette if (*eptr != '\0') 143 1.1 pgoyette errx(1, "invalid val at line %ld", 144 1.1 pgoyette (unsigned long)lineno); 145 1.1 pgoyette } else 146 1.1 pgoyette longopts[nlongopts].val = (int)longopt[1]; 147 1.1 pgoyette nlongopts++; 148 1.1 pgoyette } else if (strncmp(line, "args:", 5) == 0) { 149 1.1 pgoyette for (; nargs >= 0; nargs--) { 150 1.1 pgoyette if (args[nargs] != NULL) 151 1.1 pgoyette free(args[nargs]); 152 1.1 pgoyette } 153 1.1 pgoyette args[nargs = 0] = strtok(&line[6], WS); 154 1.1 pgoyette if (args[nargs] == NULL) 155 1.1 pgoyette errx(1, "Missing args"); 156 1.1 pgoyette 157 1.1 pgoyette args[nargs] = strdup(args[nargs]); 158 1.1 pgoyette while ((args[++nargs] = strtok(NULL, WS)) != NULL) 159 1.1 pgoyette args[nargs] = strdup(args[nargs]); 160 1.1 pgoyette } else if (strncmp(line, "result:", 7) == 0) { 161 1.1 pgoyette int li; 162 1.1 pgoyette buf[0] = '\0'; 163 1.1 pgoyette optind = optreset = 1; 164 1.1 pgoyette if (result) 165 1.1 pgoyette free(result); 166 1.1 pgoyette result = strtok(&line[8], WS); 167 1.1 pgoyette if (result == NULL) 168 1.1 pgoyette errx(1, "missing result at line %ld", 169 1.1 pgoyette (unsigned long)lineno); 170 1.1 pgoyette if (optstring == NULL) 171 1.1 pgoyette errx(1, "result: without optstring"); 172 1.1 pgoyette if (longopts == NULL || nlongopts == 0) 173 1.1 pgoyette errx(1, "result: without longopts"); 174 1.1 pgoyette result = strdup(result); 175 1.1 pgoyette if (nargs == -1) 176 1.1 pgoyette errx(1, "result: without args"); 177 1.1 pgoyette li = -2; 178 1.1 pgoyette while ((c = getopt_long(nargs, args, optstring, 179 1.1 pgoyette longopts, &li)) != -1) { 180 1.1 pgoyette if (c == ':') 181 1.1 pgoyette errx(1, "`:' found as argument char"); 182 1.1 pgoyette if (li == -2) { 183 1.1 pgoyette ptr = strchr(optstring, c); 184 1.1 pgoyette if (ptr == NULL) { 185 1.1 pgoyette snprintf(arg, sizeof(arg), 186 1.1 pgoyette "!%c,", c); 187 1.1 pgoyette strcat(buf, arg); 188 1.1 pgoyette continue; 189 1.1 pgoyette } 190 1.1 pgoyette if (ptr[1] != ':') 191 1.1 pgoyette snprintf(arg, sizeof(arg), 192 1.1 pgoyette "%c,", c); 193 1.1 pgoyette else 194 1.1 pgoyette snprintf(arg, sizeof(arg), 195 1.1 pgoyette "%c=%s,", c, optarg); 196 1.1 pgoyette } else { 197 1.1 pgoyette switch (longopts[li].has_arg) { 198 1.1 pgoyette case no_argument: 199 1.1 pgoyette snprintf(arg, sizeof(arg), "-%s,", 200 1.1 pgoyette longopts[li].name); 201 1.1 pgoyette break; 202 1.1 pgoyette case required_argument: 203 1.1 pgoyette snprintf(arg, sizeof(arg), 204 1.1 pgoyette "-%s=%s,", 205 1.1 pgoyette longopts[li].name, optarg); 206 1.1 pgoyette break; 207 1.1 pgoyette case optional_argument: 208 1.1 pgoyette snprintf(arg, sizeof(arg), 209 1.1 pgoyette "-%s%s%s,", 210 1.1 pgoyette longopts[li].name, 211 1.1 pgoyette (optarg)? "=" : "", 212 1.1 pgoyette (optarg)? optarg : ""); 213 1.1 pgoyette break; 214 1.1 pgoyette default: 215 1.1 pgoyette errx(1, "internal error"); 216 1.1 pgoyette } 217 1.1 pgoyette } 218 1.1 pgoyette strcat(buf, arg); 219 1.1 pgoyette li = -2; 220 1.1 pgoyette } 221 1.1 pgoyette len = strlen(buf); 222 1.1 pgoyette if (len > 0) { 223 1.1 pgoyette buf[len - 1] = '|'; 224 1.1 pgoyette buf[len] = '\0'; 225 1.1 pgoyette } else { 226 1.1 pgoyette buf[0] = '|'; 227 1.1 pgoyette buf[1] = '\0'; 228 1.1 pgoyette } 229 1.1 pgoyette snprintf(arg, sizeof(arg), "%d", nargs - optind); 230 1.1 pgoyette strcat(buf, arg); 231 1.1 pgoyette if (strcmp(buf, result) != 0) 232 1.1 pgoyette errx(1, "`%s' != `%s'", buf, result); 233 1.1 pgoyette } else 234 1.1 pgoyette errx(1, "unknown directive at line %ld", 235 1.1 pgoyette (unsigned long)lineno); 236 1.1 pgoyette free(line); 237 1.1 pgoyette } 238 1.1 pgoyette return 0; 239 1.1 pgoyette } 240