]> git.cameronkatri.com Git - mandoc.git/blob - tag.c
Including <ohash.h> requires including <stdint.h> before,
[mandoc.git] / tag.c
1 /* $Id: tag.c,v 1.7 2015/08/29 15:28:13 schwarze Exp $ */
2 /*
3 * Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17 #include "config.h"
18
19 #include <sys/types.h>
20
21 #include <signal.h>
22 #include <stddef.h>
23 #include <stdint.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28
29 #if HAVE_OHASH
30 #include <ohash.h>
31 #else
32 #include "compat_ohash.h"
33 #endif
34
35 #include "mandoc_aux.h"
36 #include "tag.h"
37
38 struct tag_entry {
39 size_t line;
40 int prio;
41 char s[];
42 };
43
44 static void tag_signal(int);
45 static void *tag_alloc(size_t, void *);
46 static void tag_free(void *, void *);
47 static void *tag_calloc(size_t, size_t, void *);
48
49 static struct ohash tag_data;
50 static struct tag_files tag_files;
51
52
53 /*
54 * Prepare for using a pager.
55 * Not all pagers are capable of using a tag file,
56 * but for simplicity, create it anyway.
57 */
58 struct tag_files *
59 tag_init(void)
60 {
61 struct ohash_info tag_info;
62 int ofd;
63
64 ofd = -1;
65 tag_files.tfd = -1;
66
67 /* Save the original standard output for use by the pager. */
68
69 if ((tag_files.ofd = dup(STDOUT_FILENO)) == -1)
70 goto fail;
71
72 /* Create both temporary output files. */
73
74 (void)strlcpy(tag_files.ofn, "/tmp/man.XXXXXXXXXX",
75 sizeof(tag_files.ofn));
76 (void)strlcpy(tag_files.tfn, "/tmp/man.XXXXXXXXXX",
77 sizeof(tag_files.tfn));
78 signal(SIGHUP, tag_signal);
79 signal(SIGINT, tag_signal);
80 signal(SIGTERM, tag_signal);
81 if ((ofd = mkstemp(tag_files.ofn)) == -1)
82 goto fail;
83 if ((tag_files.tfd = mkstemp(tag_files.tfn)) == -1)
84 goto fail;
85 if (dup2(ofd, STDOUT_FILENO) == -1)
86 goto fail;
87 close(ofd);
88
89 /*
90 * Set up the ohash table to collect output line numbers
91 * where various marked-up terms are documented.
92 */
93
94 tag_info.alloc = tag_alloc;
95 tag_info.calloc = tag_calloc;
96 tag_info.free = tag_free;
97 tag_info.key_offset = offsetof(struct tag_entry, s);
98 tag_info.data = NULL;
99 ohash_init(&tag_data, 4, &tag_info);
100 return(&tag_files);
101
102 fail:
103 tag_unlink();
104 if (ofd != -1)
105 close(ofd);
106 if (tag_files.ofd != -1)
107 close(tag_files.ofd);
108 if (tag_files.tfd != -1)
109 close(tag_files.tfd);
110 *tag_files.ofn = '\0';
111 *tag_files.tfn = '\0';
112 tag_files.ofd = -1;
113 tag_files.tfd = -1;
114 return(NULL);
115 }
116
117 /*
118 * Set the line number where a term is defined,
119 * unless it is already defined at a higher priority.
120 */
121 void
122 tag_put(const char *s, int prio, size_t line)
123 {
124 struct tag_entry *entry;
125 size_t len;
126 unsigned int slot;
127
128 if (tag_files.tfd <= 0)
129 return;
130 slot = ohash_qlookup(&tag_data, s);
131 entry = ohash_find(&tag_data, slot);
132 if (entry == NULL) {
133 len = strlen(s) + 1;
134 entry = mandoc_malloc(sizeof(*entry) + len);
135 memcpy(entry->s, s, len);
136 ohash_insert(&tag_data, slot, entry);
137 } else if (entry->prio <= prio)
138 return;
139 entry->line = line;
140 entry->prio = prio;
141 }
142
143 /*
144 * Write out the tags file using the previously collected
145 * information and clear the ohash table while going along.
146 */
147 void
148 tag_write(void)
149 {
150 FILE *stream;
151 struct tag_entry *entry;
152 unsigned int slot;
153
154 if (tag_files.tfd <= 0)
155 return;
156 stream = fdopen(tag_files.tfd, "w");
157 entry = ohash_first(&tag_data, &slot);
158 while (entry != NULL) {
159 if (stream != NULL)
160 fprintf(stream, "%s %s %zu\n",
161 entry->s, tag_files.ofn, entry->line);
162 free(entry);
163 entry = ohash_next(&tag_data, &slot);
164 }
165 ohash_delete(&tag_data);
166 if (stream != NULL)
167 fclose(stream);
168 }
169
170 void
171 tag_unlink(void)
172 {
173
174 if (*tag_files.ofn != '\0')
175 unlink(tag_files.ofn);
176 if (*tag_files.tfn != '\0')
177 unlink(tag_files.tfn);
178 }
179
180 static void
181 tag_signal(int signum)
182 {
183
184 tag_unlink();
185 signal(signum, SIG_DFL);
186 kill(getpid(), signum);
187 /* NOTREACHED */
188 _exit(1);
189 }
190
191 /*
192 * Memory management callback functions for ohash.
193 */
194 static void *
195 tag_alloc(size_t sz, void *arg)
196 {
197
198 return(mandoc_malloc(sz));
199 }
200
201 static void *
202 tag_calloc(size_t nmemb, size_t sz, void *arg)
203 {
204
205 return(mandoc_calloc(nmemb, sz));
206 }
207
208 static void
209 tag_free(void *p, void *arg)
210 {
211
212 free(p);
213 }