xref: /openbsd-src/regress/usr.bin/mandoc/db/dbm_dump/dbm_dump.c (revision 5dea098c4cfaecce9ae6586a5a65b55e2cfefa58)
1*5dea098cSschwarze /*	$OpenBSD: dbm_dump.c,v 1.3 2024/05/14 00:31:48 schwarze Exp $ */
2264ca280Sschwarze /*
3264ca280Sschwarze  * Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org>
4264ca280Sschwarze  *
5264ca280Sschwarze  * Permission to use, copy, modify, and distribute this software for any
6264ca280Sschwarze  * purpose with or without fee is hereby granted, provided that the above
7264ca280Sschwarze  * copyright notice and this permission notice appear in all copies.
8264ca280Sschwarze  *
9264ca280Sschwarze  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10264ca280Sschwarze  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11264ca280Sschwarze  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12264ca280Sschwarze  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13264ca280Sschwarze  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14264ca280Sschwarze  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15264ca280Sschwarze  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16264ca280Sschwarze  *
17264ca280Sschwarze  * Function to dump an on-disk read-only mandoc database
18264ca280Sschwarze  * in diff(1)able format for debugging purposes.
19264ca280Sschwarze  */
20264ca280Sschwarze #include <err.h>
21264ca280Sschwarze #include <regex.h>
22264ca280Sschwarze #include <stdint.h>
23264ca280Sschwarze #include <stdio.h>
24264ca280Sschwarze #include <string.h>
25264ca280Sschwarze 
26264ca280Sschwarze #include "mansearch.h"
27264ca280Sschwarze #include "dbm_map.h"
28264ca280Sschwarze #include "dbm.h"
29264ca280Sschwarze 
30264ca280Sschwarze union ptr {
31264ca280Sschwarze 	const char	*c;
32264ca280Sschwarze 	const int32_t	*i;
33264ca280Sschwarze };
34264ca280Sschwarze 
35264ca280Sschwarze static void		 dump(void);
36264ca280Sschwarze static const char	*dump_macro(union ptr, int32_t);
37264ca280Sschwarze static const char	*dump_macros(union ptr);
38264ca280Sschwarze static const char	*dump_pages(union ptr);
39264ca280Sschwarze static void		 dump_str(const char **);
40264ca280Sschwarze static void		 dump_lst(const char **);
41264ca280Sschwarze static void		 pchk(const char *, const char **, const char *, int);
42264ca280Sschwarze 
43264ca280Sschwarze 
44264ca280Sschwarze int
main(int argc,char * argv[])45264ca280Sschwarze main(int argc, char *argv[])
46264ca280Sschwarze {
47264ca280Sschwarze 	if (argc != 2)
48264ca280Sschwarze 		errx(1, "usage: dump filename");
49264ca280Sschwarze 	if (dbm_open(argv[1]) == -1)
50264ca280Sschwarze 		err(1, "%s", argv[1]);
51264ca280Sschwarze 	dump();
52264ca280Sschwarze 	dbm_close();
53264ca280Sschwarze 	return 0;
54264ca280Sschwarze }
55264ca280Sschwarze 
56264ca280Sschwarze static void
dump(void)57264ca280Sschwarze dump(void)
58264ca280Sschwarze {
59264ca280Sschwarze 	union ptr	 p, macros, end;
60264ca280Sschwarze 
61264ca280Sschwarze 	p.i = dbm_getint(0);
62264ca280Sschwarze 	printf("initial magic 0x%08x\n", be32toh(*p.i++));
63264ca280Sschwarze 	printf("version       0x%08x\n", be32toh(*p.i++));
64264ca280Sschwarze 	printf("macros offset 0x%08x\n", be32toh(*p.i));
65264ca280Sschwarze 	macros.i = dbm_get(*p.i++);
66264ca280Sschwarze 	printf("end offset    0x%08x\n", be32toh(*p.i));
67264ca280Sschwarze 	end.i = dbm_get(*p.i++);
68264ca280Sschwarze 	p.c = dump_pages(p);
69264ca280Sschwarze 	pchk(macros.c, &p.c, "macros", 3);
70264ca280Sschwarze 	p.c = dump_macros(p);
71264ca280Sschwarze 	pchk(end.c, &p.c, "end", 0);
72264ca280Sschwarze 	printf("final magic   0x%08x\n", be32toh(*p.i));
73264ca280Sschwarze }
74264ca280Sschwarze 
75264ca280Sschwarze static const char *
dump_pages(union ptr p)76264ca280Sschwarze dump_pages(union ptr p)
77264ca280Sschwarze {
78264ca280Sschwarze 	const char	*name0, *sect0, *arch0, *desc0, *file0;
79264ca280Sschwarze 	const char	*namep, *sectp, *archp, *descp, *filep;
80264ca280Sschwarze 	int32_t		 i, npages;
81264ca280Sschwarze 
82264ca280Sschwarze 	npages = be32toh(*p.i++);
83264ca280Sschwarze 	printf("page count    %d\n", npages);
84264ca280Sschwarze 	if (npages == 0)
85264ca280Sschwarze 		return p.c;
86264ca280Sschwarze 	namep = name0 = dbm_get(p.i[0]);
87264ca280Sschwarze 	sectp = sect0 = dbm_get(p.i[1]);
88264ca280Sschwarze 	archp = arch0 = p.i[2] == 0 ? NULL : dbm_get(p.i[2]);
89264ca280Sschwarze 	descp = desc0 = dbm_get(p.i[3]);
90264ca280Sschwarze 	filep = file0 = dbm_get(p.i[4]);
91264ca280Sschwarze 	printf("=== PAGES ===\n");
92264ca280Sschwarze 	for (i = 0; i < npages; i++) {
93264ca280Sschwarze 		pchk(dbm_get(*p.i++), &namep, "name", 0);
94264ca280Sschwarze 		printf("page name ");
95264ca280Sschwarze 		dump_lst(&namep);
96264ca280Sschwarze 		pchk(dbm_get(*p.i++), &sectp, "sect", 0);
97264ca280Sschwarze 		printf("page sect ");
98264ca280Sschwarze 		dump_lst(&sectp);
99264ca280Sschwarze 		if (*p.i++) {
100264ca280Sschwarze 			if (arch0 == NULL)
101264ca280Sschwarze 				archp = arch0 = dbm_get(p.i[-1]);
102264ca280Sschwarze 			else
103264ca280Sschwarze 				pchk(dbm_get(p.i[-1]), &archp, "arch", 0);
104264ca280Sschwarze 			printf("page arch ");
105264ca280Sschwarze 			dump_lst(&archp);
106264ca280Sschwarze 		}
107264ca280Sschwarze 		pchk(dbm_get(*p.i++), &descp, "desc", 0);
108264ca280Sschwarze 		printf("page desc # ");
109264ca280Sschwarze 		dump_str(&descp);
110264ca280Sschwarze 		printf("\npage file ");
111264ca280Sschwarze 		pchk(dbm_get(*p.i++), &filep, "file", 0);
112998de4a5Sschwarze 		if (filep == NULL) {
113998de4a5Sschwarze 			printf("# (NULL)\n");
114998de4a5Sschwarze 			continue;
115998de4a5Sschwarze 		}
116264ca280Sschwarze 		switch(*filep++) {
117264ca280Sschwarze 		case 1:
118264ca280Sschwarze 			printf("src ");
119264ca280Sschwarze 			break;
120264ca280Sschwarze 		case 2:
121264ca280Sschwarze 			printf("cat ");
122264ca280Sschwarze 			break;
123264ca280Sschwarze 		default:
124264ca280Sschwarze 			printf("UNKNOWN FORMAT %d ", filep[-1]);
125264ca280Sschwarze 			break;
126264ca280Sschwarze 		}
127264ca280Sschwarze 		dump_lst(&filep);
128264ca280Sschwarze 	}
129264ca280Sschwarze 	printf("=== END OF PAGES ===\n");
130264ca280Sschwarze 	pchk(name0, &p.c, "name0", 0);
131264ca280Sschwarze 	pchk(sect0, &namep, "sect0", 0);
132264ca280Sschwarze 	if (arch0 != NULL) {
133264ca280Sschwarze 		pchk(arch0, &sectp, "arch0", 0);
134264ca280Sschwarze 		pchk(desc0, &archp, "desc0", 0);
135264ca280Sschwarze 	} else
136264ca280Sschwarze 		pchk(desc0, &sectp, "desc0", 0);
137264ca280Sschwarze 	pchk(file0, &descp, "file0", 0);
138264ca280Sschwarze 	return filep;
139264ca280Sschwarze }
140264ca280Sschwarze 
141264ca280Sschwarze static const char *
dump_macros(union ptr p)142264ca280Sschwarze dump_macros(union ptr p)
143264ca280Sschwarze {
144264ca280Sschwarze 	union ptr	 macro0, macrop;
145264ca280Sschwarze 	int32_t		 i, nmacros;
146264ca280Sschwarze 
147264ca280Sschwarze 	nmacros = be32toh(*p.i++);
148264ca280Sschwarze 	printf("macros count  %d\n", nmacros);
149264ca280Sschwarze 	if (nmacros == 0)
150264ca280Sschwarze 		return p.c;
151264ca280Sschwarze 	macrop.i = macro0.i = dbm_get(*p.i);
152264ca280Sschwarze 	printf("=== MACROS ===\n");
153264ca280Sschwarze 	for (i = 0; i < nmacros; i++) {
154264ca280Sschwarze 		pchk(dbm_get(*p.i++), &macrop.c, "macro", 0);
155264ca280Sschwarze 		macrop.c = dump_macro(macrop, i);
156264ca280Sschwarze 	}
157264ca280Sschwarze 	printf("=== END OF MACROS ===\n");
158264ca280Sschwarze 	pchk(macro0.c, &p.c, "macro0", 0);
159264ca280Sschwarze 	return macrop.c;
160264ca280Sschwarze }
161264ca280Sschwarze 
162264ca280Sschwarze static const char *
dump_macro(union ptr p,int32_t im)163264ca280Sschwarze dump_macro(union ptr p, int32_t im)
164264ca280Sschwarze {
165264ca280Sschwarze 	union ptr	 page0, pagep;
166264ca280Sschwarze 	const char	*val0, *valp;
167264ca280Sschwarze 	int32_t		 i, nentries;
168264ca280Sschwarze 
169264ca280Sschwarze 	nentries = be32toh(*p.i++);
170264ca280Sschwarze 	printf("macro %02d entry count %d\n", im, nentries);
171264ca280Sschwarze 	if (nentries == 0)
172264ca280Sschwarze 		return p.c;
173264ca280Sschwarze 	valp = val0 = dbm_get(p.i[0]);
174264ca280Sschwarze 	pagep.i = page0.i = dbm_get(p.i[1]);
175264ca280Sschwarze 	printf("=== MACRO %02d ===\n", im);
176264ca280Sschwarze 	for (i = 0; i < nentries; i++) {
177264ca280Sschwarze 		pchk(dbm_get(*p.i++), &valp, "value", 0);
178264ca280Sschwarze 		printf("macro %02d # ", im);
179264ca280Sschwarze 		dump_str(&valp);
180264ca280Sschwarze 		pchk(dbm_get(*p.i++), &pagep.c, "pages", 0);
181264ca280Sschwarze 		while (*pagep.i++ != 0)
182264ca280Sschwarze 			printf("# %s ", (char *)dbm_get(
183264ca280Sschwarze 			    *(int32_t *)dbm_get(pagep.i[-1])) + 1);
184264ca280Sschwarze 		printf("\n");
185264ca280Sschwarze 	}
186264ca280Sschwarze 	printf("=== END OF MACRO %02d ===\n", im);
187264ca280Sschwarze 	pchk(val0, &p.c, "value0", 0);
188264ca280Sschwarze 	pchk(page0.c, &valp, "page0", 3);
189264ca280Sschwarze 	return pagep.c;
190264ca280Sschwarze }
191264ca280Sschwarze 
192264ca280Sschwarze static void
dump_str(const char ** cp)193264ca280Sschwarze dump_str(const char **cp)
194264ca280Sschwarze {
195998de4a5Sschwarze 	if (*cp == NULL) {
196998de4a5Sschwarze 		printf("(NULL)");
197998de4a5Sschwarze 		return;
198998de4a5Sschwarze 	}
199*5dea098cSschwarze 	if ((unsigned char)**cp <= NAME_MASK) {
200264ca280Sschwarze 		putchar('[');
201264ca280Sschwarze 		if (**cp & NAME_FILE)
202264ca280Sschwarze 			putchar('f');
203264ca280Sschwarze 		if (**cp & NAME_HEAD)
204264ca280Sschwarze 			putchar('h');
205264ca280Sschwarze 		if (**cp & NAME_FIRST)
206264ca280Sschwarze 			putchar('1');
207264ca280Sschwarze 		if (**cp & NAME_TITLE)
208264ca280Sschwarze 			putchar('t');
209264ca280Sschwarze 		if (**cp & NAME_SYN)
210264ca280Sschwarze 			putchar('s');
211264ca280Sschwarze 		putchar(']');
212264ca280Sschwarze 		(*cp)++;
213264ca280Sschwarze 	}
214264ca280Sschwarze 	while (**cp != '\0')
215264ca280Sschwarze 		putchar(*(*cp)++);
216264ca280Sschwarze 	putchar(' ');
217264ca280Sschwarze 	(*cp)++;
218264ca280Sschwarze }
219264ca280Sschwarze 
220264ca280Sschwarze static void
dump_lst(const char ** cp)221264ca280Sschwarze dump_lst(const char **cp)
222264ca280Sschwarze {
223998de4a5Sschwarze 	if (*cp == NULL) {
224998de4a5Sschwarze 		printf("# (NULL)\n");
225998de4a5Sschwarze 		return;
226998de4a5Sschwarze 	}
227264ca280Sschwarze 	while (**cp != '\0') {
228264ca280Sschwarze 		printf("# ");
229264ca280Sschwarze 		dump_str(cp);
230264ca280Sschwarze 	}
231264ca280Sschwarze 	(*cp)++;
232264ca280Sschwarze 	printf("\n");
233264ca280Sschwarze }
234264ca280Sschwarze 
235264ca280Sschwarze static void
pchk(const char * want,const char ** got,const char * name,int fuzz)236264ca280Sschwarze pchk(const char *want, const char **got, const char *name, int fuzz)
237264ca280Sschwarze {
238998de4a5Sschwarze 	if (want == NULL) {
239998de4a5Sschwarze 		warnx("%s wants (NULL), ignoring", name);
240998de4a5Sschwarze 		return;
241998de4a5Sschwarze 	}
242998de4a5Sschwarze 	if (*got == NULL)
243998de4a5Sschwarze 		warnx("%s jumps from (NULL) to 0x%x", name,
244998de4a5Sschwarze 		    be32toh(dbm_addr(want)));
245998de4a5Sschwarze 	else if (*got > want || *got + fuzz < want)
246264ca280Sschwarze 		warnx("%s jumps from 0x%x to 0x%x", name,
247264ca280Sschwarze 		    be32toh(dbm_addr(*got)), be32toh(dbm_addr(want)));
248264ca280Sschwarze 	*got = want;
249264ca280Sschwarze }
250