Annotation of src/usr.bin/mandoc/tag.c, Revision 1.8
1.8 ! schwarze 1: /* $OpenBSD: tag.c,v 1.7 2015/08/29 15:28:19 schwarze Exp $ */
1.1 schwarze 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 <sys/types.h>
18:
1.2 schwarze 19: #include <signal.h>
1.1 schwarze 20: #include <stddef.h>
1.7 schwarze 21: #include <stdint.h>
1.1 schwarze 22: #include <stdio.h>
23: #include <stdlib.h>
24: #include <string.h>
25: #include <unistd.h>
26:
27: #include <ohash.h>
28:
29: #include "mandoc_aux.h"
30: #include "tag.h"
31:
32: struct tag_entry {
33: size_t line;
1.4 schwarze 34: int prio;
1.1 schwarze 35: char s[];
36: };
37:
1.2 schwarze 38: static void tag_signal(int);
1.1 schwarze 39: static void *tag_alloc(size_t, void *);
40: static void tag_free(void *, void *);
41: static void *tag_calloc(size_t, size_t, void *);
42:
43: static struct ohash tag_data;
1.6 schwarze 44: static struct tag_files tag_files;
1.1 schwarze 45:
46:
47: /*
1.6 schwarze 48: * Prepare for using a pager.
49: * Not all pagers are capable of using a tag file,
50: * but for simplicity, create it anyway.
1.1 schwarze 51: */
1.6 schwarze 52: struct tag_files *
1.1 schwarze 53: tag_init(void)
54: {
55: struct ohash_info tag_info;
1.6 schwarze 56: int ofd;
1.1 schwarze 57:
1.6 schwarze 58: ofd = -1;
59: tag_files.tfd = -1;
60:
61: /* Save the original standard output for use by the pager. */
62:
63: if ((tag_files.ofd = dup(STDOUT_FILENO)) == -1)
64: goto fail;
65:
66: /* Create both temporary output files. */
67:
68: (void)strlcpy(tag_files.ofn, "/tmp/man.XXXXXXXXXX",
69: sizeof(tag_files.ofn));
70: (void)strlcpy(tag_files.tfn, "/tmp/man.XXXXXXXXXX",
71: sizeof(tag_files.tfn));
1.2 schwarze 72: signal(SIGHUP, tag_signal);
73: signal(SIGINT, tag_signal);
74: signal(SIGTERM, tag_signal);
1.6 schwarze 75: if ((ofd = mkstemp(tag_files.ofn)) == -1)
76: goto fail;
77: if ((tag_files.tfd = mkstemp(tag_files.tfn)) == -1)
78: goto fail;
79: if (dup2(ofd, STDOUT_FILENO) == -1)
80: goto fail;
81: close(ofd);
82:
83: /*
84: * Set up the ohash table to collect output line numbers
85: * where various marked-up terms are documented.
86: */
1.1 schwarze 87:
88: tag_info.alloc = tag_alloc;
89: tag_info.calloc = tag_calloc;
90: tag_info.free = tag_free;
91: tag_info.key_offset = offsetof(struct tag_entry, s);
92: tag_info.data = NULL;
93: ohash_init(&tag_data, 4, &tag_info);
1.8 ! schwarze 94: return &tag_files;
1.6 schwarze 95:
96: fail:
97: tag_unlink();
98: if (ofd != -1)
99: close(ofd);
100: if (tag_files.ofd != -1)
101: close(tag_files.ofd);
102: if (tag_files.tfd != -1)
103: close(tag_files.tfd);
104: *tag_files.ofn = '\0';
105: *tag_files.tfn = '\0';
106: tag_files.ofd = -1;
107: tag_files.tfd = -1;
1.8 ! schwarze 108: return NULL;
1.1 schwarze 109: }
110:
111: /*
1.5 schwarze 112: * Set the line number where a term is defined,
113: * unless it is already defined at a higher priority.
1.1 schwarze 114: */
115: void
1.5 schwarze 116: tag_put(const char *s, int prio, size_t line)
1.1 schwarze 117: {
118: struct tag_entry *entry;
1.5 schwarze 119: size_t len;
1.1 schwarze 120: unsigned int slot;
121:
1.6 schwarze 122: if (tag_files.tfd <= 0)
1.1 schwarze 123: return;
1.5 schwarze 124: slot = ohash_qlookup(&tag_data, s);
1.1 schwarze 125: entry = ohash_find(&tag_data, slot);
126: if (entry == NULL) {
1.5 schwarze 127: len = strlen(s) + 1;
128: entry = mandoc_malloc(sizeof(*entry) + len);
1.1 schwarze 129: memcpy(entry->s, s, len);
130: ohash_insert(&tag_data, slot, entry);
1.5 schwarze 131: } else if (entry->prio <= prio)
132: return;
1.1 schwarze 133: entry->line = line;
1.4 schwarze 134: entry->prio = prio;
1.1 schwarze 135: }
136:
137: /*
138: * Write out the tags file using the previously collected
139: * information and clear the ohash table while going along.
140: */
141: void
142: tag_write(void)
143: {
144: FILE *stream;
145: struct tag_entry *entry;
146: unsigned int slot;
147:
1.6 schwarze 148: if (tag_files.tfd <= 0)
1.1 schwarze 149: return;
1.6 schwarze 150: stream = fdopen(tag_files.tfd, "w");
1.1 schwarze 151: entry = ohash_first(&tag_data, &slot);
152: while (entry != NULL) {
153: if (stream != NULL)
1.6 schwarze 154: fprintf(stream, "%s %s %zu\n",
155: entry->s, tag_files.ofn, entry->line);
1.1 schwarze 156: free(entry);
157: entry = ohash_next(&tag_data, &slot);
158: }
159: ohash_delete(&tag_data);
160: if (stream != NULL)
161: fclose(stream);
162: }
163:
164: void
165: tag_unlink(void)
166: {
167:
1.6 schwarze 168: if (*tag_files.ofn != '\0')
169: unlink(tag_files.ofn);
170: if (*tag_files.tfn != '\0')
171: unlink(tag_files.tfn);
1.2 schwarze 172: }
173:
174: static void
175: tag_signal(int signum)
176: {
177:
178: tag_unlink();
179: signal(signum, SIG_DFL);
180: kill(getpid(), signum);
181: /* NOTREACHED */
182: _exit(1);
1.1 schwarze 183: }
184:
185: /*
186: * Memory management callback functions for ohash.
187: */
188: static void *
189: tag_alloc(size_t sz, void *arg)
190: {
191:
1.8 ! schwarze 192: return mandoc_malloc(sz);
1.1 schwarze 193: }
194:
195: static void *
196: tag_calloc(size_t nmemb, size_t sz, void *arg)
197: {
198:
1.8 ! schwarze 199: return mandoc_calloc(nmemb, sz);
1.1 schwarze 200: }
201:
202: static void
203: tag_free(void *p, void *arg)
204: {
205:
206: free(p);
207: }