]>
git.cameronkatri.com Git - mandoc.git/blob - tag.c
c517e3abf916045b083cef7911f77a62f604f728
1 /* $Id: tag.c,v 1.14 2016/11/08 15:28:17 schwarze Exp $ */
3 * Copyright (c) 2015, 2016 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"
41 static void tag_signal(int) __attribute__((noreturn
));
43 static struct ohash tag_data
;
44 static struct tag_files tag_files
;
48 * Prepare for using a pager.
49 * Not all pagers are capable of using a tag file,
50 * but for simplicity, create it anyway.
60 tag_files
.tcpgid
= -1;
62 /* Clean up when dying from a signal. */
64 memset(&sa
, 0, sizeof(sa
));
65 sigfillset(&sa
.sa_mask
);
66 sa
.sa_handler
= tag_signal
;
67 sigaction(SIGHUP
, &sa
, NULL
);
68 sigaction(SIGINT
, &sa
, NULL
);
69 sigaction(SIGTERM
, &sa
, NULL
);
72 * POSIX requires that a process calling tcsetpgrp(3)
73 * from the background gets a SIGTTOU signal.
74 * In that case, do not stop.
77 sa
.sa_handler
= SIG_IGN
;
78 sigaction(SIGTTOU
, &sa
, NULL
);
80 /* Save the original standard output for use by the pager. */
82 if ((tag_files
.ofd
= dup(STDOUT_FILENO
)) == -1)
85 /* Create both temporary output files. */
87 (void)strlcpy(tag_files
.ofn
, "/tmp/man.XXXXXXXXXX",
88 sizeof(tag_files
.ofn
));
89 (void)strlcpy(tag_files
.tfn
, "/tmp/man.XXXXXXXXXX",
90 sizeof(tag_files
.tfn
));
91 if ((ofd
= mkstemp(tag_files
.ofn
)) == -1)
93 if ((tag_files
.tfd
= mkstemp(tag_files
.tfn
)) == -1)
95 if (dup2(ofd
, STDOUT_FILENO
) == -1)
100 * Set up the ohash table to collect output line numbers
101 * where various marked-up terms are documented.
104 mandoc_ohash_init(&tag_data
, 4, offsetof(struct tag_entry
, s
));
111 if (tag_files
.ofd
!= -1)
112 close(tag_files
.ofd
);
113 if (tag_files
.tfd
!= -1)
114 close(tag_files
.tfd
);
115 *tag_files
.ofn
= '\0';
116 *tag_files
.tfn
= '\0';
123 * Set the line number where a term is defined,
124 * unless it is already defined at a higher priority.
127 tag_put(const char *s
, int prio
, size_t line
)
129 struct tag_entry
*entry
;
133 if (tag_files
.tfd
<= 0 || strchr(s
, ' ') != NULL
)
136 slot
= ohash_qlookup(&tag_data
, s
);
137 entry
= ohash_find(&tag_data
, slot
);
141 /* Build a new entry. */
144 entry
= mandoc_malloc(sizeof(*entry
) + len
);
145 memcpy(entry
->s
, s
, len
);
147 entry
->maxlines
= entry
->nlines
= 0;
148 ohash_insert(&tag_data
, slot
, entry
);
152 /* A better entry is already present, ignore the new one. */
154 if (entry
->prio
< prio
)
157 /* The existing entry is worse, clear it. */
159 if (entry
->prio
> prio
)
163 /* Remember the new line. */
165 if (entry
->maxlines
== entry
->nlines
) {
166 entry
->maxlines
+= 4;
167 entry
->lines
= mandoc_reallocarray(entry
->lines
,
168 entry
->maxlines
, sizeof(*entry
->lines
));
170 entry
->lines
[entry
->nlines
++] = line
;
175 * Write out the tags file using the previously collected
176 * information and clear the ohash table while going along.
182 struct tag_entry
*entry
;
186 if (tag_files
.tfd
<= 0)
188 stream
= fdopen(tag_files
.tfd
, "w");
189 entry
= ohash_first(&tag_data
, &slot
);
190 while (entry
!= NULL
) {
192 for (i
= 0; i
< entry
->nlines
; i
++)
193 fprintf(stream
, "%s %s %zu\n",
194 entry
->s
, tag_files
.ofn
, entry
->lines
[i
]);
197 entry
= ohash_next(&tag_data
, &slot
);
199 ohash_delete(&tag_data
);
209 if (tag_files
.tcpgid
!= -1) {
210 tc_pgid
= tcgetpgrp(STDIN_FILENO
);
211 if (tc_pgid
== tag_files
.pager_pid
||
212 tc_pgid
== getpgid(0) ||
213 getpgid(tc_pgid
) == -1)
214 (void)tcsetpgrp(STDIN_FILENO
, tag_files
.tcpgid
);
216 if (*tag_files
.ofn
!= '\0')
217 unlink(tag_files
.ofn
);
218 if (*tag_files
.tfn
!= '\0')
219 unlink(tag_files
.tfn
);
223 tag_signal(int signum
)
228 memset(&sa
, 0, sizeof(sa
));
229 sigemptyset(&sa
.sa_mask
);
230 sa
.sa_handler
= SIG_DFL
;
231 sigaction(signum
, &sa
, NULL
);
232 kill(getpid(), signum
);