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