Annotation of mandoc/tag.c, Revision 1.11
1.11 ! schwarze 1: /* $Id: tag.c,v 1.10 2015/10/13 15:53:05 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: #include "mandoc_aux.h"
1.10 schwarze 30: #include "mandoc_ohash.h"
1.1 schwarze 31: #include "tag.h"
32:
33: struct tag_entry {
34: size_t line;
1.4 schwarze 35: int prio;
1.1 schwarze 36: char s[];
37: };
38:
1.2 schwarze 39: static void tag_signal(int);
1.1 schwarze 40:
41: static struct ohash tag_data;
1.6 schwarze 42: static struct tag_files tag_files;
1.1 schwarze 43:
44:
45: /*
1.6 schwarze 46: * Prepare for using a pager.
47: * Not all pagers are capable of using a tag file,
48: * but for simplicity, create it anyway.
1.1 schwarze 49: */
1.6 schwarze 50: struct tag_files *
1.1 schwarze 51: tag_init(void)
52: {
1.11 ! schwarze 53: struct sigaction sa;
1.6 schwarze 54: int ofd;
1.1 schwarze 55:
1.6 schwarze 56: ofd = -1;
57: tag_files.tfd = -1;
1.11 ! schwarze 58: tag_files.tcpgid = -1;
1.6 schwarze 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.11 ! schwarze 71: memset(&sa, 0, sizeof(sa));
! 72: sigfillset(&sa.sa_mask);
! 73: sa.sa_handler = tag_signal;
! 74: sigaction(SIGHUP, &sa, NULL);
! 75: sigaction(SIGINT, &sa, NULL);
! 76: sigaction(SIGTERM, &sa, NULL);
1.6 schwarze 77: if ((ofd = mkstemp(tag_files.ofn)) == -1)
78: goto fail;
79: if ((tag_files.tfd = mkstemp(tag_files.tfn)) == -1)
80: goto fail;
81: if (dup2(ofd, STDOUT_FILENO) == -1)
82: goto fail;
83: close(ofd);
84:
85: /*
86: * Set up the ohash table to collect output line numbers
87: * where various marked-up terms are documented.
88: */
1.1 schwarze 89:
1.10 schwarze 90: mandoc_ohash_init(&tag_data, 4, offsetof(struct tag_entry, s));
1.8 schwarze 91: return &tag_files;
1.6 schwarze 92:
93: fail:
94: tag_unlink();
95: if (ofd != -1)
96: close(ofd);
97: if (tag_files.ofd != -1)
98: close(tag_files.ofd);
99: if (tag_files.tfd != -1)
100: close(tag_files.tfd);
101: *tag_files.ofn = '\0';
102: *tag_files.tfn = '\0';
103: tag_files.ofd = -1;
104: tag_files.tfd = -1;
1.8 schwarze 105: return NULL;
1.1 schwarze 106: }
107:
108: /*
1.5 schwarze 109: * Set the line number where a term is defined,
110: * unless it is already defined at a higher priority.
1.1 schwarze 111: */
112: void
1.5 schwarze 113: tag_put(const char *s, int prio, size_t line)
1.1 schwarze 114: {
115: struct tag_entry *entry;
1.5 schwarze 116: size_t len;
1.1 schwarze 117: unsigned int slot;
118:
1.9 schwarze 119: if (tag_files.tfd <= 0 || strchr(s, ' ') != NULL)
1.1 schwarze 120: return;
1.5 schwarze 121: slot = ohash_qlookup(&tag_data, s);
1.1 schwarze 122: entry = ohash_find(&tag_data, slot);
123: if (entry == NULL) {
1.5 schwarze 124: len = strlen(s) + 1;
125: entry = mandoc_malloc(sizeof(*entry) + len);
1.1 schwarze 126: memcpy(entry->s, s, len);
127: ohash_insert(&tag_data, slot, entry);
1.5 schwarze 128: } else if (entry->prio <= prio)
129: return;
1.1 schwarze 130: entry->line = line;
1.4 schwarze 131: entry->prio = prio;
1.1 schwarze 132: }
133:
134: /*
135: * Write out the tags file using the previously collected
136: * information and clear the ohash table while going along.
137: */
138: void
139: tag_write(void)
140: {
141: FILE *stream;
142: struct tag_entry *entry;
143: unsigned int slot;
144:
1.6 schwarze 145: if (tag_files.tfd <= 0)
1.1 schwarze 146: return;
1.6 schwarze 147: stream = fdopen(tag_files.tfd, "w");
1.1 schwarze 148: entry = ohash_first(&tag_data, &slot);
149: while (entry != NULL) {
150: if (stream != NULL)
1.6 schwarze 151: fprintf(stream, "%s %s %zu\n",
152: entry->s, tag_files.ofn, entry->line);
1.1 schwarze 153: free(entry);
154: entry = ohash_next(&tag_data, &slot);
155: }
156: ohash_delete(&tag_data);
157: if (stream != NULL)
158: fclose(stream);
159: }
160:
161: void
162: tag_unlink(void)
163: {
1.11 ! schwarze 164: pid_t tc_pgid;
1.1 schwarze 165:
1.11 ! schwarze 166: if (tag_files.tcpgid != -1) {
! 167: tc_pgid = tcgetpgrp(STDIN_FILENO);
! 168: if (tc_pgid == tag_files.pager_pid ||
! 169: tc_pgid == getpgid(0) ||
! 170: getpgid(tc_pgid) == -1)
! 171: (void)tcsetpgrp(STDIN_FILENO, tag_files.tcpgid);
! 172: }
1.6 schwarze 173: if (*tag_files.ofn != '\0')
174: unlink(tag_files.ofn);
175: if (*tag_files.tfn != '\0')
176: unlink(tag_files.tfn);
1.2 schwarze 177: }
178:
179: static void
180: tag_signal(int signum)
181: {
1.11 ! schwarze 182: struct sigaction sa;
1.2 schwarze 183:
184: tag_unlink();
1.11 ! schwarze 185: memset(&sa, 0, sizeof(sa));
! 186: sigemptyset(&sa.sa_mask);
! 187: sa.sa_handler = SIG_DFL;
! 188: sigaction(signum, &sa, NULL);
1.2 schwarze 189: kill(getpid(), signum);
190: /* NOTREACHED */
191: _exit(1);
1.1 schwarze 192: }
CVSweb