1/*	$NetBSD: parse_cross.c,v 1.1.1.1 2024/06/11 09:15:38 wiz Exp $	*/
2
3#if HAVE_CONFIG_H
4#include "config.h"
5#endif
6#include <nbcompat.h>
7#if HAVE_SYS_CDEFS_H
8#include <sys/cdefs.h>
9#endif
10__RCSID("$NetBSD: parse_cross.c,v 1.1.1.1 2024/06/11 09:15:38 wiz Exp $");
11
12#if HAVE_ERR_H
13#include <err.h>
14#endif
15#include "lib.h"
16#include "add.h"
17
18/*
19 * ${OPSYS}/${MACHINE_ARCH} ${OS_VERSION}
20 *
21 * or just
22 *
23 * ${MACHINE_ARCH}
24 */
25void
26parse_cross(const char *text, char **machine_arch, char **opsys,
27    char **os_version)
28{
29	static const char safeset[] = /* XXX */
30	    "abcdefghijklmnopqrstuvwxyz"
31	    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
32	    "0123456789"
33	    "-._";
34	char *copy = xstrdup(text);
35	char *p = copy, *q, *r;
36
37	/*
38	 * If there's no /, treat it as a single MACHINE_ARCH.
39	 */
40	if ((q = strchr(p, '/')) == NULL) {
41		*machine_arch = copy;
42		*opsys = NULL;
43		*os_version = NULL;
44	} else {
45		/*
46		 * NUL-terminate at the slash so p := text[0..slash)
47		 * is the OPSYS.
48		 */
49		*q++ = '\0';
50
51		/*
52		 * If there's no SPC, fail.
53		 */
54		if (*(r = strchr(q, ' ')) == '\0') {
55			goto fail;
56		}
57
58		/*
59		 * NUL-terminate at the space so
60		 *
61		 *	q := text(slash..space)
62		 *
63		 * is the MACHINE_ARCH.
64		 */
65		*r++ = '\0';
66
67		/*
68		 * The rest is already NUL-terminated, so
69		 *
70		 *	r := text(space..NUL)
71		 *
72		 * is the OS_VERSION.
73		 */
74		*opsys = p;
75		*machine_arch = q;
76		*os_version = r;
77	}
78
79	/*
80	 * Verify that MACHINE_ARCH, and, if specified, OPSYS and
81	 * OS_VERSION lie within the safe set, so we can reserve large
82	 * amounts of the space of inputs for additional syntax.
83	 * Ideally we would impose more constraints here with a
84	 * regular expression to restrict the space even more, but
85	 * this'll do for now.
86	 */
87	if ((*machine_arch)[strspn(*machine_arch, safeset)] != '\0') {
88		goto fail;
89	}
90	if (*opsys != NULL && (*opsys)[strspn(*opsys, safeset)] != '\0') {
91		goto fail;
92	}
93	if (*os_version != NULL &&
94	    (*os_version)[strspn(*os_version, safeset)] != '\0') {
95		goto fail;
96	}
97	return;
98
99fail:	errx(1, "Invalid -m argument: ${OPSYS}/${MACHINE_ARCH} ${OS_VERSION}");
100}
101