]> git.cameronkatri.com Git - mandoc.git/blob - tag.c
Without HAVE_ERR, don't try to include <err.h>, it probably isn't there.
[mandoc.git] / tag.c
1 /* $Id: tag.c,v 1.10 2015/10/13 15:53:05 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 #include "mandoc_aux.h"
30 #include "mandoc_ohash.h"
31 #include "tag.h"
32
33 struct tag_entry {
34 size_t line;
35 int prio;
36 char s[];
37 };
38
39 static void tag_signal(int);
40
41 static struct ohash tag_data;
42 static struct tag_files tag_files;
43
44
45 /*
46 * Prepare for using a pager.
47 * Not all pagers are capable of using a tag file,
48 * but for simplicity, create it anyway.
49 */
50 struct tag_files *
51 tag_init(void)
52 {
53 int ofd;
54
55 ofd = -1;
56 tag_files.tfd = -1;
57
58 /* Save the original standard output for use by the pager. */
59
60 if ((tag_files.ofd = dup(STDOUT_FILENO)) == -1)
61 goto fail;
62
63 /* Create both temporary output files. */
64
65 (void)strlcpy(tag_files.ofn, "/tmp/man.XXXXXXXXXX",
66 sizeof(tag_files.ofn));
67 (void)strlcpy(tag_files.tfn, "/tmp/man.XXXXXXXXXX",
68 sizeof(tag_files.tfn));
69 signal(SIGHUP, tag_signal);
70 signal(SIGINT, tag_signal);
71 signal(SIGTERM, tag_signal);
72 if ((ofd = mkstemp(tag_files.ofn)) == -1)
73 goto fail;
74 if ((tag_files.tfd = mkstemp(tag_files.tfn)) == -1)
75 goto fail;
76 if (dup2(ofd, STDOUT_FILENO) == -1)
77 goto fail;
78 close(ofd);
79
80 /*
81 * Set up the ohash table to collect output line numbers
82 * where various marked-up terms are documented.
83 */
84
85 mandoc_ohash_init(&tag_data, 4, offsetof(struct tag_entry, s));
86 return &tag_files;
87
88 fail:
89 tag_unlink();
90 if (ofd != -1)
91 close(ofd);
92 if (tag_files.ofd != -1)
93 close(tag_files.ofd);
94 if (tag_files.tfd != -1)
95 close(tag_files.tfd);
96 *tag_files.ofn = '\0';
97 *tag_files.tfn = '\0';
98 tag_files.ofd = -1;
99 tag_files.tfd = -1;
100 return NULL;
101 }
102
103 /*
104 * Set the line number where a term is defined,
105 * unless it is already defined at a higher priority.
106 */
107 void
108 tag_put(const char *s, int prio, size_t line)
109 {
110 struct tag_entry *entry;
111 size_t len;
112 unsigned int slot;
113
114 if (tag_files.tfd <= 0 || strchr(s, ' ') != NULL)
115 return;
116 slot = ohash_qlookup(&tag_data, s);
117 entry = ohash_find(&tag_data, slot);
118 if (entry == NULL) {
119 len = strlen(s) + 1;
120 entry = mandoc_malloc(sizeof(*entry) + len);
121 memcpy(entry->s, s, len);
122 ohash_insert(&tag_data, slot, entry);
123 } else if (entry->prio <= prio)
124 return;
125 entry->line = line;
126 entry->prio = prio;
127 }
128
129 /*
130 * Write out the tags file using the previously collected
131 * information and clear the ohash table while going along.
132 */
133 void
134 tag_write(void)
135 {
136 FILE *stream;
137 struct tag_entry *entry;
138 unsigned int slot;
139
140 if (tag_files.tfd <= 0)
141 return;
142 stream = fdopen(tag_files.tfd, "w");
143 entry = ohash_first(&tag_data, &slot);
144 while (entry != NULL) {
145 if (stream != NULL)
146 fprintf(stream, "%s %s %zu\n",
147 entry->s, tag_files.ofn, entry->line);
148 free(entry);
149 entry = ohash_next(&tag_data, &slot);
150 }
151 ohash_delete(&tag_data);
152 if (stream != NULL)
153 fclose(stream);
154 }
155
156 void
157 tag_unlink(void)
158 {
159
160 if (*tag_files.ofn != '\0')
161 unlink(tag_files.ofn);
162 if (*tag_files.tfn != '\0')
163 unlink(tag_files.tfn);
164 }
165
166 static void
167 tag_signal(int signum)
168 {
169
170 tag_unlink();
171 signal(signum, SIG_DFL);
172 kill(getpid(), signum);
173 /* NOTREACHED */
174 _exit(1);
175 }