1 /* $NetBSD: gen-win32.h,v 1.1 2024/02/18 20:57:31 christos Exp $ */
2
3 /*
4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5 *
6 * SPDX-License-Identifier: MPL-2.0
7 *
8 * This Source Code Form is subject to the terms of the Mozilla Public
9 * License, v. 2.0. If a copy of the MPL was not distributed with this
10 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11 *
12 * See the COPYRIGHT file distributed with this work for additional
13 * information regarding copyright ownership.
14 */
15
16 /*
17 * Copyright (c) 1987, 1993, 1994
18 * The Regents of the University of California. All rights reserved.
19 *
20 * Redistribution and use in source and binary forms, with or without
21 * modification, are permitted provided that the following conditions
22 * are met:
23 * 1. Redistributions of source code must retain the above copyright
24 * notice, this list of conditions and the following disclaimer.
25 * 2. Redistributions in binary form must reproduce the above copyright
26 * notice, this list of conditions and the following disclaimer in the
27 * documentation and/or other materials provided with the distribution.
28 * 3. Neither the name of the University nor the names of its contributors
29 * may be used to endorse or promote products derived from this software
30 * without specific prior written permission.
31 *
32 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
33 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
36 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42 * SUCH DAMAGE.
43 */
44
45 /*
46 * \note This file was adapted from the NetBSD project's source tree, RCS ID:
47 * NetBSD: getopt.c,v 1.15 1999/09/20 04:39:37 lukem Exp
48 *
49 * The primary change has been to rename items to the ISC namespace
50 * and format in the ISC coding style.
51 *
52 * This file is responsible for defining two operations that are not
53 * directly portable between Unix-like systems and Windows NT, option
54 * parsing and directory scanning. It is here because it was decided
55 * that the "gen" build utility was not to depend on libisc.a, so
56 * the functions declared in isc/commandline.h and isc/dir.h could not
57 * be used.
58 *
59 * The commandline stuff is pretty much a straight copy from the initial
60 * isc/commandline.c. The dir stuff was shrunk to fit the needs of gen.c.
61 */
62
63 #ifndef DNS_GEN_WIN32_H
64 #define DNS_GEN_WIN32_H 1
65
66 #include <stdbool.h>
67 #include <stdio.h>
68 #include <string.h>
69 #include <time.h>
70 #include <windows.h>
71
72 #include <isc/lang.h>
73
74 int isc_commandline_index = 1; /* Index into parent argv vector. */
75 int isc_commandline_option; /* Character checked for validity. */
76
77 char *isc_commandline_argument; /* Argument associated with option. */
78 char *isc_commandline_progname; /* For printing error messages. */
79
80 bool isc_commandline_errprint = true; /* Print error messages. */
81 bool isc_commandline_reset = true; /* Reset processing. */
82
83 #define BADOPT '?'
84 #define BADARG ':'
85 #define ENDOPT ""
86
87 ISC_LANG_BEGINDECLS
88
89 /*
90 * getopt --
91 * Parse argc/argv argument vector.
92 */
93 int
isc_commandline_parse(int argc,char * const * argv,const char * options)94 isc_commandline_parse(int argc, char *const *argv, const char *options) {
95 static char *place = ENDOPT;
96 char *option; /* Index into *options of option. */
97
98 /*
99 * Update scanning pointer, either because a reset was requested or
100 * the previous argv was finished.
101 */
102 if (isc_commandline_reset || *place == '\0') {
103 isc_commandline_reset = false;
104
105 if (isc_commandline_progname == NULL) {
106 isc_commandline_progname = argv[0];
107 }
108
109 if (isc_commandline_index >= argc ||
110 *(place = argv[isc_commandline_index]) != '-')
111 {
112 /*
113 * Index out of range or points to non-option.
114 */
115 place = ENDOPT;
116 return (-1);
117 }
118
119 if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
120 /*
121 * Found '--' to signal end of options. Advance
122 * index to next argv, the first non-option.
123 */
124 isc_commandline_index++;
125 place = ENDOPT;
126 return (-1);
127 }
128 }
129
130 isc_commandline_option = *place++;
131 option = strchr(options, isc_commandline_option);
132
133 /*
134 * Ensure valid option has been passed as specified by options string.
135 * '-:' is never a valid command line option because it could not
136 * distinguish ':' from the argument specifier in the options string.
137 */
138 if (isc_commandline_option == ':' || option == NULL) {
139 if (*place == '\0') {
140 isc_commandline_index++;
141 }
142
143 if (isc_commandline_errprint && *options != ':') {
144 fprintf(stderr, "%s: illegal option -- %c\n",
145 isc_commandline_progname,
146 isc_commandline_option);
147 }
148
149 return (BADOPT);
150 }
151
152 if (*++option != ':') {
153 /*
154 * Option does not take an argument.
155 */
156 isc_commandline_argument = NULL;
157
158 /*
159 * Skip to next argv if at the end of the current argv.
160 */
161 if (*place == '\0') {
162 ++isc_commandline_index;
163 }
164 } else {
165 /*
166 * Option needs an argument.
167 */
168 if (*place != '\0') {
169 /*
170 * Option is in this argv, -D1 style.
171 */
172 isc_commandline_argument = place;
173 } else if (argc > ++isc_commandline_index) {
174 /*
175 * Option is next argv, -D 1 style.
176 */
177 isc_commandline_argument = argv[isc_commandline_index];
178 } else {
179 /*
180 * Argument needed, but no more argv.
181 */
182 place = ENDOPT;
183
184 /*
185 * Silent failure with "missing argument" return
186 * when ':' starts options string, per historical spec.
187 */
188 if (*options == ':') {
189 return (BADARG);
190 }
191
192 if (isc_commandline_errprint) {
193 fprintf(stderr,
194 "%s: option requires an argument -- "
195 "%c\n",
196 isc_commandline_progname,
197 isc_commandline_option);
198 }
199
200 return (BADOPT);
201 }
202
203 place = ENDOPT;
204
205 /*
206 * Point to argv that follows argument.
207 */
208 isc_commandline_index++;
209 }
210
211 return (isc_commandline_option);
212 }
213
214 typedef struct {
215 HANDLE handle;
216 WIN32_FIND_DATA find_data;
217 bool first_file;
218 char *filename;
219 } isc_dir_t;
220
221 bool
start_directory(const char * path,isc_dir_t * dir)222 start_directory(const char *path, isc_dir_t *dir) {
223 char pattern[_MAX_PATH], *p;
224
225 /*
226 * Need space for slash-splat and final NUL.
227 */
228 if (strlen(path) + 3 > sizeof(pattern)) {
229 return (false);
230 }
231
232 strcpy(pattern, path);
233
234 /*
235 * Append slash (if needed) and splat.
236 */
237 p = pattern + strlen(pattern);
238 if (p != pattern && p[-1] != '\\' && p[-1] != ':') {
239 *p++ = '\\';
240 }
241 *p++ = '*';
242 *p++ = '\0';
243
244 dir->first_file = true;
245
246 dir->handle = FindFirstFile(pattern, &dir->find_data);
247
248 if (dir->handle == INVALID_HANDLE_VALUE) {
249 dir->filename = NULL;
250 return (false);
251 } else {
252 dir->filename = dir->find_data.cFileName;
253 return (true);
254 }
255 }
256
257 bool
next_file(isc_dir_t * dir)258 next_file(isc_dir_t *dir) {
259 if (dir->first_file) {
260 dir->first_file = false;
261 } else if (dir->handle != INVALID_HANDLE_VALUE) {
262 if (FindNextFile(dir->handle, &dir->find_data) == TRUE) {
263 dir->filename = dir->find_data.cFileName;
264 } else {
265 dir->filename = NULL;
266 }
267 } else {
268 dir->filename = NULL;
269 }
270
271 if (dir->filename != NULL) {
272 return (true);
273 } else {
274 return (false);
275 }
276 }
277
278 void
end_directory(isc_dir_t * dir)279 end_directory(isc_dir_t *dir) {
280 if (dir->handle != INVALID_HANDLE_VALUE) {
281 FindClose(dir->handle);
282 }
283 }
284
285 inline struct tm *
gmtime_r(const time_t * clock,struct tm * result)286 gmtime_r(const time_t *clock, struct tm *result) {
287 errno_t ret = gmtime_s(result, clock);
288 if (ret != 0) {
289 errno = ret;
290 return (NULL);
291 }
292 return (result);
293 }
294
295 ISC_LANG_ENDDECLS
296
297 #endif /* DNS_GEN_WIN32_H */
298