diff options
author | bapt <bapt@FreeBSD.org> | 2016-01-15 23:28:12 +0000 |
---|---|---|
committer | bapt <bapt@FreeBSD.org> | 2016-01-15 23:28:12 +0000 |
commit | e1581ec0f03f2f2c260785ce05fca5a98c8d65b4 (patch) | |
tree | ae81f04244baa70cf59bab257864c9dd79596a69 /contrib/mdocml/tag.c | |
parent | cb734ceab666d0372162796ee007f4777451d293 (diff) | |
parent | e15bccbf37b1a75c96083f38f1d7580cfa8aa1ea (diff) | |
download | FreeBSD-src-e1581ec0f03f2f2c260785ce05fca5a98c8d65b4.zip FreeBSD-src-e1581ec0f03f2f2c260785ce05fca5a98c8d65b4.tar.gz |
Update mandoc to 20160116
Diffstat (limited to 'contrib/mdocml/tag.c')
-rw-r--r-- | contrib/mdocml/tag.c | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/contrib/mdocml/tag.c b/contrib/mdocml/tag.c new file mode 100644 index 0000000..57925ce --- /dev/null +++ b/contrib/mdocml/tag.c @@ -0,0 +1,192 @@ +/* $Id: tag.c,v 1.11 2015/11/20 21:59:54 schwarze Exp $ */ +/* + * Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "config.h" + +#include <sys/types.h> + +#include <signal.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "mandoc_aux.h" +#include "mandoc_ohash.h" +#include "tag.h" + +struct tag_entry { + size_t line; + int prio; + char s[]; +}; + +static void tag_signal(int); + +static struct ohash tag_data; +static struct tag_files tag_files; + + +/* + * Prepare for using a pager. + * Not all pagers are capable of using a tag file, + * but for simplicity, create it anyway. + */ +struct tag_files * +tag_init(void) +{ + struct sigaction sa; + int ofd; + + ofd = -1; + tag_files.tfd = -1; + tag_files.tcpgid = -1; + + /* Save the original standard output for use by the pager. */ + + if ((tag_files.ofd = dup(STDOUT_FILENO)) == -1) + goto fail; + + /* Create both temporary output files. */ + + (void)strlcpy(tag_files.ofn, "/tmp/man.XXXXXXXXXX", + sizeof(tag_files.ofn)); + (void)strlcpy(tag_files.tfn, "/tmp/man.XXXXXXXXXX", + sizeof(tag_files.tfn)); + memset(&sa, 0, sizeof(sa)); + sigfillset(&sa.sa_mask); + sa.sa_handler = tag_signal; + sigaction(SIGHUP, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + if ((ofd = mkstemp(tag_files.ofn)) == -1) + goto fail; + if ((tag_files.tfd = mkstemp(tag_files.tfn)) == -1) + goto fail; + if (dup2(ofd, STDOUT_FILENO) == -1) + goto fail; + close(ofd); + + /* + * Set up the ohash table to collect output line numbers + * where various marked-up terms are documented. + */ + + mandoc_ohash_init(&tag_data, 4, offsetof(struct tag_entry, s)); + return &tag_files; + +fail: + tag_unlink(); + if (ofd != -1) + close(ofd); + if (tag_files.ofd != -1) + close(tag_files.ofd); + if (tag_files.tfd != -1) + close(tag_files.tfd); + *tag_files.ofn = '\0'; + *tag_files.tfn = '\0'; + tag_files.ofd = -1; + tag_files.tfd = -1; + return NULL; +} + +/* + * Set the line number where a term is defined, + * unless it is already defined at a higher priority. + */ +void +tag_put(const char *s, int prio, size_t line) +{ + struct tag_entry *entry; + size_t len; + unsigned int slot; + + if (tag_files.tfd <= 0 || strchr(s, ' ') != NULL) + return; + slot = ohash_qlookup(&tag_data, s); + entry = ohash_find(&tag_data, slot); + if (entry == NULL) { + len = strlen(s) + 1; + entry = mandoc_malloc(sizeof(*entry) + len); + memcpy(entry->s, s, len); + ohash_insert(&tag_data, slot, entry); + } else if (entry->prio <= prio) + return; + entry->line = line; + entry->prio = prio; +} + +/* + * Write out the tags file using the previously collected + * information and clear the ohash table while going along. + */ +void +tag_write(void) +{ + FILE *stream; + struct tag_entry *entry; + unsigned int slot; + + if (tag_files.tfd <= 0) + return; + stream = fdopen(tag_files.tfd, "w"); + entry = ohash_first(&tag_data, &slot); + while (entry != NULL) { + if (stream != NULL) + fprintf(stream, "%s %s %zu\n", + entry->s, tag_files.ofn, entry->line); + free(entry); + entry = ohash_next(&tag_data, &slot); + } + ohash_delete(&tag_data); + if (stream != NULL) + fclose(stream); +} + +void +tag_unlink(void) +{ + pid_t tc_pgid; + + if (tag_files.tcpgid != -1) { + tc_pgid = tcgetpgrp(STDIN_FILENO); + if (tc_pgid == tag_files.pager_pid || + tc_pgid == getpgid(0) || + getpgid(tc_pgid) == -1) + (void)tcsetpgrp(STDIN_FILENO, tag_files.tcpgid); + } + if (*tag_files.ofn != '\0') + unlink(tag_files.ofn); + if (*tag_files.tfn != '\0') + unlink(tag_files.tfn); +} + +static void +tag_signal(int signum) +{ + struct sigaction sa; + + tag_unlink(); + memset(&sa, 0, sizeof(sa)); + sigemptyset(&sa.sa_mask); + sa.sa_handler = SIG_DFL; + sigaction(signum, &sa, NULL); + kill(getpid(), signum); + /* NOTREACHED */ + _exit(1); +} |