-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgetopt.c
148 lines (126 loc) · 3.14 KB
/
getopt.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/*
* This file is part of John the Ripper password cracker,
* Copyright (c) 1996-2000,2003 by Solar Designer
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* There's ABSOLUTELY NO WARRANTY, express or implied.
*/
#include <stdio.h>
#include <string.h>
#include "misc.h"
#include "memory.h"
#include "list.h"
#include "getopt.h"
static char *opt_errors[] = {
NULL, /* No error */
"Unknown option",
"Option requires a parameter",
"Invalid option parameter",
"Extra parameter for option",
"Invalid options combination or duplicate option"
};
static char *opt_find(struct opt_entry *list, char *opt,
struct opt_entry **entry)
{
char *name, *param;
size_t length;
struct opt_entry *found;
if (opt[0] == '-') {
if (*(name = opt + 1) == '-') name++;
if (!(param = strchr(name, '=')))
param = strchr(name, ':');
if (param) {
length = param - name;
if (!*++param) param = NULL;
} else
length = strlen(name);
found = NULL;
do {
if (length <= strlen(list->name))
if (!strncmp(name, list->name, length)) {
if (!found)
found = list;
else {
*entry = NULL;
return NULL;
}
}
} while ((++list)->name);
if ((*entry = found))
return param;
else
return NULL;
} else {
*entry = list;
return opt;
}
}
static int opt_process_param(char *param, char *format, void *buffer)
{
if (format[0] == OPT_FMT_STR_ALLOC[0]) {
*(char **)buffer = str_alloc_copy(param);
return 0;
} else
if (format[0] == OPT_FMT_ADD_LIST[0]) {
list_add(*(struct list_main **)buffer, param);
return 0;
} else
if (format[0] == OPT_FMT_ADD_LIST_MULTI[0]) {
list_add_multi(*(struct list_main **)buffer, param);
return 0;
} else
return sscanf(param, format, buffer) != 1;
}
static int opt_process_one(struct opt_entry *list, opt_flags *flg, char *opt)
{
char *param;
struct opt_entry *entry;
param = opt_find(list, opt, &entry);
if (!entry) return OPT_ERROR_UNKNOWN;
if (*flg & entry->flg_set & entry->flg_clr) return OPT_ERROR_COMB;
*flg &= ~entry->flg_clr;
*flg |= entry->flg_set;
if (entry->format) {
if (!param) {
if (entry->req_clr & OPT_REQ_PARAM)
return OPT_ERROR_PARAM_REQ;
} else
if (opt_process_param(param, entry->format, entry->param))
return OPT_ERROR_PARAM_INV;
} else
if (param) return OPT_ERROR_PARAM_EXT;
return OPT_ERROR_NONE;
}
static int opt_check_one(struct opt_entry *list, opt_flags flg, char *opt)
{
struct opt_entry *entry;
opt_find(list, opt, &entry);
if (!entry) return OPT_ERROR_UNKNOWN;
if ((flg & entry->req_set) != entry->req_set || (flg & entry->req_clr))
return OPT_ERROR_COMB;
return OPT_ERROR_NONE;
}
void opt_process(struct opt_entry *list, opt_flags *flg, char **argv)
{
char **opt;
int res;
if (*(opt = argv))
while (*++opt)
if ((res = opt_process_one(list, flg, *opt))) {
fprintf(stderr, "%s: \"%s\"\n", opt_errors[res], *opt);
error();
}
}
void opt_check(struct opt_entry *list, opt_flags flg, char **argv)
{
char **opt;
int res;
if (*(opt = argv))
while (*++opt)
if ((res = opt_check_one(list, flg, *opt))) {
fprintf(stderr, "%s: \"%s\"\n", opt_errors[res], *opt);
error();
}
}