Annotation of src/usr.bin/mandoc/tag.c, Revision 1.11
1.11 ! schwarze 1: /* $OpenBSD: tag.c,v 1.10 2015/10/13 15:50:15 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.11 ! schwarze 51: struct sigaction sa;
1.6 schwarze 52: int ofd;
1.1 schwarze 53:
1.6 schwarze 54: ofd = -1;
55: tag_files.tfd = -1;
1.11 ! schwarze 56: tag_files.tcpgid = -1;
1.6 schwarze 57:
58: /* Save the original standard output for use by the pager. */
59:
60: if ((tag_files.ofd = dup(STDOUT_FILENO)) == -1)
61: goto fail;
62:
63: /* Create both temporary output files. */
64:
65: (void)strlcpy(tag_files.ofn, "/tmp/man.XXXXXXXXXX",
66: sizeof(tag_files.ofn));
67: (void)strlcpy(tag_files.tfn, "/tmp/man.XXXXXXXXXX",
68: sizeof(tag_files.tfn));
1.11 ! schwarze 69: memset(&sa, 0, sizeof(sa));
! 70: sigfillset(&sa.sa_mask);
! 71: sa.sa_handler = tag_signal;
! 72: sigaction(SIGHUP, &sa, NULL);
! 73: sigaction(SIGINT, &sa, NULL);
! 74: sigaction(SIGTERM, &sa, NULL);
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:
1.10 schwarze 88: mandoc_ohash_init(&tag_data, 4, offsetof(struct tag_entry, s));
1.8 schwarze 89: return &tag_files;
1.6 schwarze 90:
91: fail:
92: tag_unlink();
93: if (ofd != -1)
94: close(ofd);
95: if (tag_files.ofd != -1)
96: close(tag_files.ofd);
97: if (tag_files.tfd != -1)
98: close(tag_files.tfd);
99: *tag_files.ofn = '\0';
100: *tag_files.tfn = '\0';
101: tag_files.ofd = -1;
102: tag_files.tfd = -1;
1.8 schwarze 103: return NULL;
1.1 schwarze 104: }
105:
106: /*
1.5 schwarze 107: * Set the line number where a term is defined,
108: * unless it is already defined at a higher priority.
1.1 schwarze 109: */
110: void
1.5 schwarze 111: tag_put(const char *s, int prio, size_t line)
1.1 schwarze 112: {
113: struct tag_entry *entry;
1.5 schwarze 114: size_t len;
1.1 schwarze 115: unsigned int slot;
116:
1.9 schwarze 117: if (tag_files.tfd <= 0 || strchr(s, ' ') != NULL)
1.1 schwarze 118: return;
1.5 schwarze 119: slot = ohash_qlookup(&tag_data, s);
1.1 schwarze 120: entry = ohash_find(&tag_data, slot);
121: if (entry == NULL) {
1.5 schwarze 122: len = strlen(s) + 1;
123: entry = mandoc_malloc(sizeof(*entry) + len);
1.1 schwarze 124: memcpy(entry->s, s, len);
125: ohash_insert(&tag_data, slot, entry);
1.5 schwarze 126: } else if (entry->prio <= prio)
127: return;
1.1 schwarze 128: entry->line = line;
1.4 schwarze 129: entry->prio = prio;
1.1 schwarze 130: }
131:
132: /*
133: * Write out the tags file using the previously collected
134: * information and clear the ohash table while going along.
135: */
136: void
137: tag_write(void)
138: {
139: FILE *stream;
140: struct tag_entry *entry;
141: unsigned int slot;
142:
1.6 schwarze 143: if (tag_files.tfd <= 0)
1.1 schwarze 144: return;
1.6 schwarze 145: stream = fdopen(tag_files.tfd, "w");
1.1 schwarze 146: entry = ohash_first(&tag_data, &slot);
147: while (entry != NULL) {
148: if (stream != NULL)
1.6 schwarze 149: fprintf(stream, "%s %s %zu\n",
150: entry->s, tag_files.ofn, entry->line);
1.1 schwarze 151: free(entry);
152: entry = ohash_next(&tag_data, &slot);
153: }
154: ohash_delete(&tag_data);
155: if (stream != NULL)
156: fclose(stream);
157: }
158:
159: void
160: tag_unlink(void)
161: {
1.11 ! schwarze 162: pid_t tc_pgid;
1.1 schwarze 163:
1.11 ! schwarze 164: if (tag_files.tcpgid != -1) {
! 165: tc_pgid = tcgetpgrp(STDIN_FILENO);
! 166: if (tc_pgid == tag_files.pager_pid ||
! 167: tc_pgid == getpgid(0) ||
! 168: getpgid(tc_pgid) == -1)
! 169: (void)tcsetpgrp(STDIN_FILENO, tag_files.tcpgid);
! 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: {
1.11 ! schwarze 180: struct sigaction sa;
1.2 schwarze 181:
182: tag_unlink();
1.11 ! schwarze 183: memset(&sa, 0, sizeof(sa));
! 184: sigemptyset(&sa.sa_mask);
! 185: sa.sa_handler = SIG_DFL;
! 186: sigaction(signum, &sa, NULL);
1.2 schwarze 187: kill(getpid(), signum);
188: /* NOTREACHED */
189: _exit(1);
1.1 schwarze 190: }