Annotation of mandoc/term_tag.c, Revision 1.1
1.1 ! schwarze 1: /* $Id$ */
! 2: /*
! 3: * Copyright (c) 2015,2016,2018,2019,2020 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: * Functions to write a ctags(1) file.
! 18: * For use by the mandoc(1) ASCII and UTF-8 formatters only.
! 19: */
! 20: #include "config.h"
! 21:
! 22: #include <sys/types.h>
! 23:
! 24: #include <errno.h>
! 25: #include <signal.h>
! 26: #include <stddef.h>
! 27: #include <stdio.h>
! 28: #include <stdlib.h>
! 29: #include <string.h>
! 30: #include <unistd.h>
! 31:
! 32: #include "mandoc.h"
! 33: #include "roff.h"
! 34: #include "tag.h"
! 35: #include "term_tag.h"
! 36:
! 37: static void tag_signal(int) __attribute__((__noreturn__));
! 38:
! 39: static struct tag_files tag_files;
! 40:
! 41:
! 42: /*
! 43: * Prepare for using a pager.
! 44: * Not all pagers are capable of using a tag file,
! 45: * but for simplicity, create it anyway.
! 46: */
! 47: struct tag_files *
! 48: term_tag_init(char *tagname)
! 49: {
! 50: struct sigaction sa;
! 51: int ofd; /* In /tmp/, dup(2)ed to stdout. */
! 52: int tfd;
! 53:
! 54: ofd = tfd = -1;
! 55: tag_files.tfs = NULL;
! 56: tag_files.tcpgid = -1;
! 57: tag_files.tagname = tagname;
! 58:
! 59: /* Clean up when dying from a signal. */
! 60:
! 61: memset(&sa, 0, sizeof(sa));
! 62: sigfillset(&sa.sa_mask);
! 63: sa.sa_handler = tag_signal;
! 64: sigaction(SIGHUP, &sa, NULL);
! 65: sigaction(SIGINT, &sa, NULL);
! 66: sigaction(SIGTERM, &sa, NULL);
! 67:
! 68: /*
! 69: * POSIX requires that a process calling tcsetpgrp(3)
! 70: * from the background gets a SIGTTOU signal.
! 71: * In that case, do not stop.
! 72: */
! 73:
! 74: sa.sa_handler = SIG_IGN;
! 75: sigaction(SIGTTOU, &sa, NULL);
! 76:
! 77: /* Save the original standard output for use by the pager. */
! 78:
! 79: if ((tag_files.ofd = dup(STDOUT_FILENO)) == -1) {
! 80: mandoc_msg(MANDOCERR_DUP, 0, 0, "%s", strerror(errno));
! 81: goto fail;
! 82: }
! 83:
! 84: /* Create both temporary output files. */
! 85:
! 86: (void)strlcpy(tag_files.ofn, "/tmp/man.XXXXXXXXXX",
! 87: sizeof(tag_files.ofn));
! 88: (void)strlcpy(tag_files.tfn, "/tmp/man.XXXXXXXXXX",
! 89: sizeof(tag_files.tfn));
! 90: if ((ofd = mkstemp(tag_files.ofn)) == -1) {
! 91: mandoc_msg(MANDOCERR_MKSTEMP, 0, 0,
! 92: "%s: %s", tag_files.ofn, strerror(errno));
! 93: goto fail;
! 94: }
! 95: if ((tfd = mkstemp(tag_files.tfn)) == -1) {
! 96: mandoc_msg(MANDOCERR_MKSTEMP, 0, 0,
! 97: "%s: %s", tag_files.tfn, strerror(errno));
! 98: goto fail;
! 99: }
! 100: if ((tag_files.tfs = fdopen(tfd, "w")) == NULL) {
! 101: mandoc_msg(MANDOCERR_FDOPEN, 0, 0, "%s", strerror(errno));
! 102: goto fail;
! 103: }
! 104: tfd = -1;
! 105: if (dup2(ofd, STDOUT_FILENO) == -1) {
! 106: mandoc_msg(MANDOCERR_DUP, 0, 0, "%s", strerror(errno));
! 107: goto fail;
! 108: }
! 109: close(ofd);
! 110: return &tag_files;
! 111:
! 112: fail:
! 113: term_tag_unlink();
! 114: if (ofd != -1)
! 115: close(ofd);
! 116: if (tfd != -1)
! 117: close(tfd);
! 118: if (tag_files.ofd != -1) {
! 119: close(tag_files.ofd);
! 120: tag_files.ofd = -1;
! 121: }
! 122: tag_files.tagname = NULL;
! 123: return NULL;
! 124: }
! 125:
! 126: void
! 127: term_tag_write(struct roff_node *n, size_t line)
! 128: {
! 129: const char *cp;
! 130: int len;
! 131:
! 132: if (tag_files.tfs == NULL)
! 133: return;
! 134: if (n->string == NULL)
! 135: n = n->child;
! 136: cp = n->string;
! 137: if (cp[0] == '\\' && (cp[1] == '&' || cp[1] == 'e'))
! 138: cp += 2;
! 139: len = strcspn(cp, " \t\\");
! 140: fprintf(tag_files.tfs, "%.*s %s %zu\n",
! 141: len, cp, tag_files.ofn, line);
! 142: }
! 143:
! 144: void
! 145: term_tag_finish(void)
! 146: {
! 147: if (tag_files.tfs == NULL)
! 148: return;
! 149: fclose(tag_files.tfs);
! 150: tag_files.tfs = NULL;
! 151: switch (tag_check(tag_files.tagname)) {
! 152: case TAG_EMPTY:
! 153: unlink(tag_files.tfn);
! 154: *tag_files.tfn = '\0';
! 155: /* FALLTHROUGH */
! 156: case TAG_MISS:
! 157: if (tag_files.tagname == NULL)
! 158: break;
! 159: mandoc_msg(MANDOCERR_TAG, 0, 0, "%s", tag_files.tagname);
! 160: tag_files.tagname = NULL;
! 161: break;
! 162: case TAG_OK:
! 163: break;
! 164: }
! 165: }
! 166:
! 167: void
! 168: term_tag_unlink(void)
! 169: {
! 170: pid_t tc_pgid;
! 171:
! 172: if (tag_files.tcpgid != -1) {
! 173: tc_pgid = tcgetpgrp(tag_files.ofd);
! 174: if (tc_pgid == tag_files.pager_pid ||
! 175: tc_pgid == getpgid(0) ||
! 176: getpgid(tc_pgid) == -1)
! 177: (void)tcsetpgrp(tag_files.ofd, tag_files.tcpgid);
! 178: }
! 179: if (*tag_files.ofn != '\0') {
! 180: unlink(tag_files.ofn);
! 181: *tag_files.ofn = '\0';
! 182: }
! 183: if (*tag_files.tfn != '\0') {
! 184: unlink(tag_files.tfn);
! 185: *tag_files.tfn = '\0';
! 186: }
! 187: if (tag_files.tfs != NULL) {
! 188: fclose(tag_files.tfs);
! 189: tag_files.tfs = NULL;
! 190: }
! 191: }
! 192:
! 193: static void
! 194: tag_signal(int signum)
! 195: {
! 196: struct sigaction sa;
! 197:
! 198: term_tag_unlink();
! 199: memset(&sa, 0, sizeof(sa));
! 200: sigemptyset(&sa.sa_mask);
! 201: sa.sa_handler = SIG_DFL;
! 202: sigaction(signum, &sa, NULL);
! 203: kill(getpid(), signum);
! 204: /* NOTREACHED */
! 205: _exit(1);
! 206: }
CVSweb