1296781Sdes/*	$Id: mandoc_xr.c,v 1.3 2017/07/02 21:18:29 schwarze Exp $ */
2225825Sdes/*
3225825Sdes * Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
4225825Sdes *
5225825Sdes * Permission to use, copy, modify, and distribute this software for any
6225825Sdes * purpose with or without fee is hereby granted, provided that the above
7225825Sdes * copyright notice and this permission notice appear in all copies.
8225825Sdes *
9225825Sdes * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10225825Sdes * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11225825Sdes * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12225825Sdes * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13225825Sdes * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14225825Sdes * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15225825Sdes * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16225825Sdes */
17225825Sdes#include <sys/types.h>
18225825Sdes
19225825Sdes#include <assert.h>
20225825Sdes#include <stddef.h>
21225825Sdes#include <stdint.h>
22225825Sdes#include <stdlib.h>
23225825Sdes#include <string.h>
24225825Sdes
25225825Sdes#include "mandoc_aux.h"
26240075Sdes#include "mandoc_ohash.h"
27225825Sdes#include "mandoc_xr.h"
28225825Sdes
29225825Sdesstatic struct ohash	 *xr_hash = NULL;
30225825Sdesstatic struct mandoc_xr	 *xr_first = NULL;
31225825Sdesstatic struct mandoc_xr	 *xr_last = NULL;
32225825Sdes
33240075Sdesstatic void		  mandoc_xr_clear(void);
34225825Sdes
35225825Sdes
36225825Sdesstatic void
37225825Sdesmandoc_xr_clear(void)
38225825Sdes{
39295367Sdes	struct mandoc_xr	*xr;
40225825Sdes	unsigned int		 slot;
41225825Sdes
42225825Sdes	if (xr_hash == NULL)
43225825Sdes		return;
44225825Sdes	for (xr = ohash_first(xr_hash, &slot); xr != NULL;
45225825Sdes	     xr = ohash_next(xr_hash, &slot))
46225825Sdes		free(xr);
47225825Sdes	ohash_delete(xr_hash);
48225825Sdes}
49225825Sdes
50225825Sdesvoid
51225825Sdesmandoc_xr_reset(void)
52225825Sdes{
53296781Sdes	if (xr_hash == NULL)
54296781Sdes		xr_hash = mandoc_malloc(sizeof(*xr_hash));
55296781Sdes	else
56296781Sdes		mandoc_xr_clear();
57296781Sdes	mandoc_ohash_init(xr_hash, 5,
58296781Sdes	    offsetof(struct mandoc_xr, hashkey));
59296781Sdes	xr_first = xr_last = NULL;
60295367Sdes}
61296781Sdes
62296781Sdesint
63296781Sdesmandoc_xr_add(const char *sec, const char *name, int line, int pos)
64295367Sdes{
65295367Sdes	struct mandoc_xr	 *xr, *oxr;
66295367Sdes	const char		 *pend;
67295367Sdes	size_t			  ssz, nsz, tsz;
68295367Sdes	unsigned int		  slot;
69295367Sdes	int			  ret;
70295367Sdes	uint32_t		  hv;
71296781Sdes
72296781Sdes	if (xr_hash == NULL)
73295367Sdes		return 0;
74296781Sdes
75225825Sdes	ssz = strlen(sec) + 1;
76225825Sdes	nsz = strlen(name) + 1;
77225825Sdes	tsz = ssz + nsz;
78240075Sdes	xr = mandoc_malloc(sizeof(*xr) + tsz);
79295367Sdes	xr->next = NULL;
80296781Sdes	xr->sec = xr->hashkey;
81225825Sdes	xr->name = xr->hashkey + ssz;
82296781Sdes	xr->line = line;
83225825Sdes	xr->pos = pos;
84296781Sdes	xr->count = 1;
85264377Sdes	memcpy(xr->sec, sec, ssz);
86296781Sdes	memcpy(xr->name, name, nsz);
87296781Sdes
88296781Sdes	pend = xr->hashkey + tsz;
89296781Sdes	hv = ohash_interval(xr->hashkey, &pend);
90225825Sdes	slot = ohash_lookup_memory(xr_hash, xr->hashkey, tsz, hv);
91225825Sdes	if ((oxr = ohash_find(xr_hash, slot)) == NULL) {
92225825Sdes		ohash_insert(xr_hash, slot, xr);
93225825Sdes		if (xr_first == NULL)
94225825Sdes			xr_first = xr;
95225825Sdes		else
96240075Sdes			xr_last->next = xr;
97225825Sdes		xr_last = xr;
98225825Sdes		return 0;
99225825Sdes	}
100262566Sdes
101225825Sdes	oxr->count++;
102225825Sdes	ret = (oxr->line == -1) ^ (xr->line == -1);
103225825Sdes	if (xr->line == -1)
104225825Sdes		oxr->line = -1;
105225825Sdes	free(xr);
106225825Sdes	return ret;
107225825Sdes}
108240075Sdes
109225825Sdesstruct mandoc_xr *
110225825Sdesmandoc_xr_get(void)
111225825Sdes{
112225825Sdes	return xr_first;
113225825Sdes}
114225825Sdes
115225825Sdesvoid
116225825Sdesmandoc_xr_free(void)
117240075Sdes{
118240075Sdes	mandoc_xr_clear();
119240075Sdes	free(xr_hash);
120225825Sdes	xr_hash = NULL;
121225825Sdes}
122225825Sdes