xref: /openbsd/usr.bin/mandoc/tag.c (revision c4f5c5f1)
1*c4f5c5f1Sschwarze /*      $OpenBSD: tag.c,v 1.5 2015/07/25 14:28:40 schwarze Exp $    */
2c0a657b3Sschwarze /*
3c0a657b3Sschwarze  * Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
4c0a657b3Sschwarze  *
5c0a657b3Sschwarze  * Permission to use, copy, modify, and distribute this software for any
6c0a657b3Sschwarze  * purpose with or without fee is hereby granted, provided that the above
7c0a657b3Sschwarze  * copyright notice and this permission notice appear in all copies.
8c0a657b3Sschwarze  *
9c0a657b3Sschwarze  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10c0a657b3Sschwarze  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11c0a657b3Sschwarze  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12c0a657b3Sschwarze  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13c0a657b3Sschwarze  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14c0a657b3Sschwarze  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15c0a657b3Sschwarze  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16c0a657b3Sschwarze  */
17c0a657b3Sschwarze #include <sys/types.h>
18c0a657b3Sschwarze 
191a557d3cSschwarze #include <signal.h>
20c0a657b3Sschwarze #include <stddef.h>
21c0a657b3Sschwarze #include <stdio.h>
22c0a657b3Sschwarze #include <stdlib.h>
23c0a657b3Sschwarze #include <string.h>
24c0a657b3Sschwarze #include <unistd.h>
25c0a657b3Sschwarze 
26c0a657b3Sschwarze #include <ohash.h>
27c0a657b3Sschwarze 
28c0a657b3Sschwarze #include "mandoc_aux.h"
29c0a657b3Sschwarze #include "tag.h"
30c0a657b3Sschwarze 
31c0a657b3Sschwarze struct tag_entry {
32c0a657b3Sschwarze 	size_t	 line;
3362615e18Sschwarze 	int	 prio;
34c0a657b3Sschwarze 	char	 s[];
35c0a657b3Sschwarze };
36c0a657b3Sschwarze 
371a557d3cSschwarze static	void	 tag_signal(int);
38c0a657b3Sschwarze static	void	*tag_alloc(size_t, void *);
39c0a657b3Sschwarze static	void	 tag_free(void *, void *);
40c0a657b3Sschwarze static	void	*tag_calloc(size_t, size_t, void *);
41c0a657b3Sschwarze 
42c0a657b3Sschwarze static struct ohash	 tag_data;
43c0a657b3Sschwarze static char		*tag_fn = NULL;
44c0a657b3Sschwarze static int		 tag_fd = -1;
45c0a657b3Sschwarze 
46c0a657b3Sschwarze 
47c0a657b3Sschwarze /*
48c0a657b3Sschwarze  * Set up the ohash table to collect output line numbers
49c0a657b3Sschwarze  * where various marked-up terms are documented and create
50c0a657b3Sschwarze  * the temporary tags file, saving the name for the pager.
51c0a657b3Sschwarze  */
52bef24796Sschwarze char *
53c0a657b3Sschwarze tag_init(void)
54c0a657b3Sschwarze {
55c0a657b3Sschwarze 	struct ohash_info	 tag_info;
56c0a657b3Sschwarze 
57c0a657b3Sschwarze 	tag_fn = mandoc_strdup("/tmp/man.XXXXXXXXXX");
581a557d3cSschwarze 	signal(SIGHUP, tag_signal);
591a557d3cSschwarze 	signal(SIGINT, tag_signal);
601a557d3cSschwarze 	signal(SIGTERM, tag_signal);
61c0a657b3Sschwarze 	if ((tag_fd = mkstemp(tag_fn)) == -1) {
62c0a657b3Sschwarze 		free(tag_fn);
63c0a657b3Sschwarze 		tag_fn = NULL;
64bef24796Sschwarze 		return(NULL);
65c0a657b3Sschwarze 	}
66c0a657b3Sschwarze 
67c0a657b3Sschwarze 	tag_info.alloc = tag_alloc;
68c0a657b3Sschwarze 	tag_info.calloc = tag_calloc;
69c0a657b3Sschwarze 	tag_info.free = tag_free;
70c0a657b3Sschwarze 	tag_info.key_offset = offsetof(struct tag_entry, s);
71c0a657b3Sschwarze 	tag_info.data = NULL;
72c0a657b3Sschwarze 	ohash_init(&tag_data, 4, &tag_info);
73c0a657b3Sschwarze 	return(tag_fn);
74c0a657b3Sschwarze }
75c0a657b3Sschwarze 
76c0a657b3Sschwarze /*
77*c4f5c5f1Sschwarze  * Set the line number where a term is defined,
78*c4f5c5f1Sschwarze  * unless it is already defined at a higher priority.
79c0a657b3Sschwarze  */
80c0a657b3Sschwarze void
81*c4f5c5f1Sschwarze tag_put(const char *s, int prio, size_t line)
82c0a657b3Sschwarze {
83c0a657b3Sschwarze 	struct tag_entry	*entry;
84*c4f5c5f1Sschwarze 	size_t			 len;
85c0a657b3Sschwarze 	unsigned int		 slot;
86c0a657b3Sschwarze 
87c0a657b3Sschwarze 	if (tag_fd == -1)
88c0a657b3Sschwarze 		return;
89*c4f5c5f1Sschwarze 	slot = ohash_qlookup(&tag_data, s);
90c0a657b3Sschwarze 	entry = ohash_find(&tag_data, slot);
91c0a657b3Sschwarze 	if (entry == NULL) {
92*c4f5c5f1Sschwarze 		len = strlen(s) + 1;
93*c4f5c5f1Sschwarze 		entry = mandoc_malloc(sizeof(*entry) + len);
94c0a657b3Sschwarze 		memcpy(entry->s, s, len);
95c0a657b3Sschwarze 		ohash_insert(&tag_data, slot, entry);
96*c4f5c5f1Sschwarze 	} else if (entry->prio <= prio)
97*c4f5c5f1Sschwarze 		return;
98c0a657b3Sschwarze 	entry->line = line;
9962615e18Sschwarze 	entry->prio = prio;
100c0a657b3Sschwarze }
101c0a657b3Sschwarze 
102c0a657b3Sschwarze /*
103c0a657b3Sschwarze  * Write out the tags file using the previously collected
104c0a657b3Sschwarze  * information and clear the ohash table while going along.
105c0a657b3Sschwarze  */
106c0a657b3Sschwarze void
107c0a657b3Sschwarze tag_write(void)
108c0a657b3Sschwarze {
109c0a657b3Sschwarze 	FILE			*stream;
110c0a657b3Sschwarze 	struct tag_entry	*entry;
111c0a657b3Sschwarze 	unsigned int		 slot;
112c0a657b3Sschwarze 
113c0a657b3Sschwarze 	if (tag_fd == -1)
114c0a657b3Sschwarze 		return;
115c0a657b3Sschwarze 	stream = fdopen(tag_fd, "w");
116c0a657b3Sschwarze 	entry = ohash_first(&tag_data, &slot);
117c0a657b3Sschwarze 	while (entry != NULL) {
118c0a657b3Sschwarze 		if (stream != NULL)
119c0a657b3Sschwarze 			fprintf(stream, "%s - %zu\n", entry->s, entry->line);
120c0a657b3Sschwarze 		free(entry);
121c0a657b3Sschwarze 		entry = ohash_next(&tag_data, &slot);
122c0a657b3Sschwarze 	}
123c0a657b3Sschwarze 	ohash_delete(&tag_data);
124c0a657b3Sschwarze 	if (stream != NULL)
125c0a657b3Sschwarze 		fclose(stream);
126c0a657b3Sschwarze }
127c0a657b3Sschwarze 
128c0a657b3Sschwarze void
129c0a657b3Sschwarze tag_unlink(void)
130c0a657b3Sschwarze {
131c0a657b3Sschwarze 
132c0a657b3Sschwarze 	if (tag_fn != NULL)
133c0a657b3Sschwarze 		unlink(tag_fn);
134c0a657b3Sschwarze }
135c0a657b3Sschwarze 
1361a557d3cSschwarze static void
1371a557d3cSschwarze tag_signal(int signum)
1381a557d3cSschwarze {
1391a557d3cSschwarze 
1401a557d3cSschwarze 	tag_unlink();
1411a557d3cSschwarze 	signal(signum, SIG_DFL);
1421a557d3cSschwarze 	kill(getpid(), signum);
1431a557d3cSschwarze 	/* NOTREACHED */
1441a557d3cSschwarze 	_exit(1);
1451a557d3cSschwarze }
1461a557d3cSschwarze 
147c0a657b3Sschwarze /*
148c0a657b3Sschwarze  * Memory management callback functions for ohash.
149c0a657b3Sschwarze  */
150c0a657b3Sschwarze static void *
151c0a657b3Sschwarze tag_alloc(size_t sz, void *arg)
152c0a657b3Sschwarze {
153c0a657b3Sschwarze 
154c0a657b3Sschwarze 	return(mandoc_malloc(sz));
155c0a657b3Sschwarze }
156c0a657b3Sschwarze 
157c0a657b3Sschwarze static void *
158c0a657b3Sschwarze tag_calloc(size_t nmemb, size_t sz, void *arg)
159c0a657b3Sschwarze {
160c0a657b3Sschwarze 
161c0a657b3Sschwarze 	return(mandoc_calloc(nmemb, sz));
162c0a657b3Sschwarze }
163c0a657b3Sschwarze 
164c0a657b3Sschwarze static void
165c0a657b3Sschwarze tag_free(void *p, void *arg)
166c0a657b3Sschwarze {
167c0a657b3Sschwarze 
168c0a657b3Sschwarze 	free(p);
169c0a657b3Sschwarze }
170