Annotation of mandoc/tag.c, Revision 1.9
1.9 ! schwarze 1: /* $Id: tag.c,v 1.8 2015/10/06 18:32:20 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: */
1.7 schwarze 17: #include "config.h"
18:
1.1 schwarze 19: #include <sys/types.h>
20:
1.2 schwarze 21: #include <signal.h>
1.1 schwarze 22: #include <stddef.h>
1.7 schwarze 23: #include <stdint.h>
1.1 schwarze 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;
1.4 schwarze 40: int prio;
1.1 schwarze 41: char s[];
42: };
43:
1.2 schwarze 44: static void tag_signal(int);
1.1 schwarze 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;
1.6 schwarze 50: static struct tag_files tag_files;
1.1 schwarze 51:
52:
53: /*
1.6 schwarze 54: * Prepare for using a pager.
55: * Not all pagers are capable of using a tag file,
56: * but for simplicity, create it anyway.
1.1 schwarze 57: */
1.6 schwarze 58: struct tag_files *
1.1 schwarze 59: tag_init(void)
60: {
61: struct ohash_info tag_info;
1.6 schwarze 62: int ofd;
1.1 schwarze 63:
1.6 schwarze 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));
1.2 schwarze 78: signal(SIGHUP, tag_signal);
79: signal(SIGINT, tag_signal);
80: signal(SIGTERM, tag_signal);
1.6 schwarze 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: */
1.1 schwarze 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);
1.8 schwarze 100: return &tag_files;
1.6 schwarze 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;
1.8 schwarze 114: return NULL;
1.1 schwarze 115: }
116:
117: /*
1.5 schwarze 118: * Set the line number where a term is defined,
119: * unless it is already defined at a higher priority.
1.1 schwarze 120: */
121: void
1.5 schwarze 122: tag_put(const char *s, int prio, size_t line)
1.1 schwarze 123: {
124: struct tag_entry *entry;
1.5 schwarze 125: size_t len;
1.1 schwarze 126: unsigned int slot;
127:
1.9 ! schwarze 128: if (tag_files.tfd <= 0 || strchr(s, ' ') != NULL)
1.1 schwarze 129: return;
1.5 schwarze 130: slot = ohash_qlookup(&tag_data, s);
1.1 schwarze 131: entry = ohash_find(&tag_data, slot);
132: if (entry == NULL) {
1.5 schwarze 133: len = strlen(s) + 1;
134: entry = mandoc_malloc(sizeof(*entry) + len);
1.1 schwarze 135: memcpy(entry->s, s, len);
136: ohash_insert(&tag_data, slot, entry);
1.5 schwarze 137: } else if (entry->prio <= prio)
138: return;
1.1 schwarze 139: entry->line = line;
1.4 schwarze 140: entry->prio = prio;
1.1 schwarze 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:
1.6 schwarze 154: if (tag_files.tfd <= 0)
1.1 schwarze 155: return;
1.6 schwarze 156: stream = fdopen(tag_files.tfd, "w");
1.1 schwarze 157: entry = ohash_first(&tag_data, &slot);
158: while (entry != NULL) {
159: if (stream != NULL)
1.6 schwarze 160: fprintf(stream, "%s %s %zu\n",
161: entry->s, tag_files.ofn, entry->line);
1.1 schwarze 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:
1.6 schwarze 174: if (*tag_files.ofn != '\0')
175: unlink(tag_files.ofn);
176: if (*tag_files.tfn != '\0')
177: unlink(tag_files.tfn);
1.2 schwarze 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);
1.1 schwarze 189: }
190:
191: /*
192: * Memory management callback functions for ohash.
193: */
194: static void *
195: tag_alloc(size_t sz, void *arg)
196: {
197:
1.8 schwarze 198: return mandoc_malloc(sz);
1.1 schwarze 199: }
200:
201: static void *
202: tag_calloc(size_t nmemb, size_t sz, void *arg)
203: {
204:
1.8 schwarze 205: return mandoc_calloc(nmemb, sz);
1.1 schwarze 206: }
207:
208: static void
209: tag_free(void *p, void *arg)
210: {
211:
212: free(p);
213: }
CVSweb