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