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