1 /* $Id: tag.c,v 1.11 2015/11/20 21:59:54 schwarze Exp $ */
3 * Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org>
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.
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.
19 #include <sys/types.h>
29 #include "mandoc_aux.h"
30 #include "mandoc_ohash.h"
39 static void tag_signal(int);
41 static struct ohash tag_data;
42 static struct tag_files tag_files;
46 * Prepare for using a pager.
47 * Not all pagers are capable of using a tag file,
48 * but for simplicity, create it anyway.
58 tag_files.tcpgid = -1;
60 /* Save the original standard output for use by the pager. */
62 if ((tag_files.ofd = dup(STDOUT_FILENO)) == -1)
65 /* Create both temporary output files. */
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));
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);
77 if ((ofd = mkstemp(tag_files.ofn)) == -1)
79 if ((tag_files.tfd = mkstemp(tag_files.tfn)) == -1)
81 if (dup2(ofd, STDOUT_FILENO) == -1)
86 * Set up the ohash table to collect output line numbers
87 * where various marked-up terms are documented.
90 mandoc_ohash_init(&tag_data, 4, offsetof(struct tag_entry, s));
97 if (tag_files.ofd != -1)
99 if (tag_files.tfd != -1)
100 close(tag_files.tfd);
101 *tag_files.ofn = '\0';
102 *tag_files.tfn = '\0';
109 * Set the line number where a term is defined,
110 * unless it is already defined at a higher priority.
113 tag_put(const char *s, int prio, size_t line)
115 struct tag_entry *entry;
119 if (tag_files.tfd <= 0 || strchr(s, ' ') != NULL)
121 slot = ohash_qlookup(&tag_data, s);
122 entry = ohash_find(&tag_data, slot);
125 entry = mandoc_malloc(sizeof(*entry) + len);
126 memcpy(entry->s, s, len);
127 ohash_insert(&tag_data, slot, entry);
128 } else if (entry->prio <= prio)
135 * Write out the tags file using the previously collected
136 * information and clear the ohash table while going along.
142 struct tag_entry *entry;
145 if (tag_files.tfd <= 0)
147 stream = fdopen(tag_files.tfd, "w");
148 entry = ohash_first(&tag_data, &slot);
149 while (entry != NULL) {
151 fprintf(stream, "%s %s %zu\n",
152 entry->s, tag_files.ofn, entry->line);
154 entry = ohash_next(&tag_data, &slot);
156 ohash_delete(&tag_data);
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);
173 if (*tag_files.ofn != '\0')
174 unlink(tag_files.ofn);
175 if (*tag_files.tfn != '\0')
176 unlink(tag_files.tfn);
180 tag_signal(int signum)
185 memset(&sa, 0, sizeof(sa));
186 sigemptyset(&sa.sa_mask);
187 sa.sa_handler = SIG_DFL;
188 sigaction(signum, &sa, NULL);
189 kill(getpid(), signum);