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
74int isc_commandline_index = 1; /* Index into parent argv vector. */
75int isc_commandline_option;    /* Character checked for validity. */
76
77char *isc_commandline_argument; /* Argument associated with option. */
78char *isc_commandline_progname; /* For printing error messages. */
79
80bool isc_commandline_errprint = true; /* Print error messages. */
81bool isc_commandline_reset = true;    /* Reset processing. */
82
83#define BADOPT '?'
84#define BADARG ':'
85#define ENDOPT ""
86
87ISC_LANG_BEGINDECLS
88
89/*
90 * getopt --
91 *	Parse argc/argv argument vector.
92 */
93int
94isc_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
214typedef struct {
215	HANDLE handle;
216	WIN32_FIND_DATA find_data;
217	bool first_file;
218	char *filename;
219} isc_dir_t;
220
221bool
222start_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
257bool
258next_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
278void
279end_directory(isc_dir_t *dir) {
280	if (dir->handle != INVALID_HANDLE_VALUE) {
281		FindClose(dir->handle);
282	}
283}
284
285inline struct tm *
286gmtime_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
295ISC_LANG_ENDDECLS
296
297#endif /* DNS_GEN_WIN32_H */
298