1*c4f5c5f1Sschwarze /* $OpenBSD: tag.c,v 1.5 2015/07/25 14:28:40 schwarze Exp $ */ 2c0a657b3Sschwarze /* 3c0a657b3Sschwarze * Copyright (c) 2015 Ingo Schwarze <schwarze@openbsd.org> 4c0a657b3Sschwarze * 5c0a657b3Sschwarze * Permission to use, copy, modify, and distribute this software for any 6c0a657b3Sschwarze * purpose with or without fee is hereby granted, provided that the above 7c0a657b3Sschwarze * copyright notice and this permission notice appear in all copies. 8c0a657b3Sschwarze * 9c0a657b3Sschwarze * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10c0a657b3Sschwarze * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11c0a657b3Sschwarze * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12c0a657b3Sschwarze * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13c0a657b3Sschwarze * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14c0a657b3Sschwarze * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15c0a657b3Sschwarze * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16c0a657b3Sschwarze */ 17c0a657b3Sschwarze #include <sys/types.h> 18c0a657b3Sschwarze 191a557d3cSschwarze #include <signal.h> 20c0a657b3Sschwarze #include <stddef.h> 21c0a657b3Sschwarze #include <stdio.h> 22c0a657b3Sschwarze #include <stdlib.h> 23c0a657b3Sschwarze #include <string.h> 24c0a657b3Sschwarze #include <unistd.h> 25c0a657b3Sschwarze 26c0a657b3Sschwarze #include <ohash.h> 27c0a657b3Sschwarze 28c0a657b3Sschwarze #include "mandoc_aux.h" 29c0a657b3Sschwarze #include "tag.h" 30c0a657b3Sschwarze 31c0a657b3Sschwarze struct tag_entry { 32c0a657b3Sschwarze size_t line; 3362615e18Sschwarze int prio; 34c0a657b3Sschwarze char s[]; 35c0a657b3Sschwarze }; 36c0a657b3Sschwarze 371a557d3cSschwarze static void tag_signal(int); 38c0a657b3Sschwarze static void *tag_alloc(size_t, void *); 39c0a657b3Sschwarze static void tag_free(void *, void *); 40c0a657b3Sschwarze static void *tag_calloc(size_t, size_t, void *); 41c0a657b3Sschwarze 42c0a657b3Sschwarze static struct ohash tag_data; 43c0a657b3Sschwarze static char *tag_fn = NULL; 44c0a657b3Sschwarze static int tag_fd = -1; 45c0a657b3Sschwarze 46c0a657b3Sschwarze 47c0a657b3Sschwarze /* 48c0a657b3Sschwarze * Set up the ohash table to collect output line numbers 49c0a657b3Sschwarze * where various marked-up terms are documented and create 50c0a657b3Sschwarze * the temporary tags file, saving the name for the pager. 51c0a657b3Sschwarze */ 52bef24796Sschwarze char * 53c0a657b3Sschwarze tag_init(void) 54c0a657b3Sschwarze { 55c0a657b3Sschwarze struct ohash_info tag_info; 56c0a657b3Sschwarze 57c0a657b3Sschwarze tag_fn = mandoc_strdup("/tmp/man.XXXXXXXXXX"); 581a557d3cSschwarze signal(SIGHUP, tag_signal); 591a557d3cSschwarze signal(SIGINT, tag_signal); 601a557d3cSschwarze signal(SIGTERM, tag_signal); 61c0a657b3Sschwarze if ((tag_fd = mkstemp(tag_fn)) == -1) { 62c0a657b3Sschwarze free(tag_fn); 63c0a657b3Sschwarze tag_fn = NULL; 64bef24796Sschwarze return(NULL); 65c0a657b3Sschwarze } 66c0a657b3Sschwarze 67c0a657b3Sschwarze tag_info.alloc = tag_alloc; 68c0a657b3Sschwarze tag_info.calloc = tag_calloc; 69c0a657b3Sschwarze tag_info.free = tag_free; 70c0a657b3Sschwarze tag_info.key_offset = offsetof(struct tag_entry, s); 71c0a657b3Sschwarze tag_info.data = NULL; 72c0a657b3Sschwarze ohash_init(&tag_data, 4, &tag_info); 73c0a657b3Sschwarze return(tag_fn); 74c0a657b3Sschwarze } 75c0a657b3Sschwarze 76c0a657b3Sschwarze /* 77*c4f5c5f1Sschwarze * Set the line number where a term is defined, 78*c4f5c5f1Sschwarze * unless it is already defined at a higher priority. 79c0a657b3Sschwarze */ 80c0a657b3Sschwarze void 81*c4f5c5f1Sschwarze tag_put(const char *s, int prio, size_t line) 82c0a657b3Sschwarze { 83c0a657b3Sschwarze struct tag_entry *entry; 84*c4f5c5f1Sschwarze size_t len; 85c0a657b3Sschwarze unsigned int slot; 86c0a657b3Sschwarze 87c0a657b3Sschwarze if (tag_fd == -1) 88c0a657b3Sschwarze return; 89*c4f5c5f1Sschwarze slot = ohash_qlookup(&tag_data, s); 90c0a657b3Sschwarze entry = ohash_find(&tag_data, slot); 91c0a657b3Sschwarze if (entry == NULL) { 92*c4f5c5f1Sschwarze len = strlen(s) + 1; 93*c4f5c5f1Sschwarze entry = mandoc_malloc(sizeof(*entry) + len); 94c0a657b3Sschwarze memcpy(entry->s, s, len); 95c0a657b3Sschwarze ohash_insert(&tag_data, slot, entry); 96*c4f5c5f1Sschwarze } else if (entry->prio <= prio) 97*c4f5c5f1Sschwarze return; 98c0a657b3Sschwarze entry->line = line; 9962615e18Sschwarze entry->prio = prio; 100c0a657b3Sschwarze } 101c0a657b3Sschwarze 102c0a657b3Sschwarze /* 103c0a657b3Sschwarze * Write out the tags file using the previously collected 104c0a657b3Sschwarze * information and clear the ohash table while going along. 105c0a657b3Sschwarze */ 106c0a657b3Sschwarze void 107c0a657b3Sschwarze tag_write(void) 108c0a657b3Sschwarze { 109c0a657b3Sschwarze FILE *stream; 110c0a657b3Sschwarze struct tag_entry *entry; 111c0a657b3Sschwarze unsigned int slot; 112c0a657b3Sschwarze 113c0a657b3Sschwarze if (tag_fd == -1) 114c0a657b3Sschwarze return; 115c0a657b3Sschwarze stream = fdopen(tag_fd, "w"); 116c0a657b3Sschwarze entry = ohash_first(&tag_data, &slot); 117c0a657b3Sschwarze while (entry != NULL) { 118c0a657b3Sschwarze if (stream != NULL) 119c0a657b3Sschwarze fprintf(stream, "%s - %zu\n", entry->s, entry->line); 120c0a657b3Sschwarze free(entry); 121c0a657b3Sschwarze entry = ohash_next(&tag_data, &slot); 122c0a657b3Sschwarze } 123c0a657b3Sschwarze ohash_delete(&tag_data); 124c0a657b3Sschwarze if (stream != NULL) 125c0a657b3Sschwarze fclose(stream); 126c0a657b3Sschwarze } 127c0a657b3Sschwarze 128c0a657b3Sschwarze void 129c0a657b3Sschwarze tag_unlink(void) 130c0a657b3Sschwarze { 131c0a657b3Sschwarze 132c0a657b3Sschwarze if (tag_fn != NULL) 133c0a657b3Sschwarze unlink(tag_fn); 134c0a657b3Sschwarze } 135c0a657b3Sschwarze 1361a557d3cSschwarze static void 1371a557d3cSschwarze tag_signal(int signum) 1381a557d3cSschwarze { 1391a557d3cSschwarze 1401a557d3cSschwarze tag_unlink(); 1411a557d3cSschwarze signal(signum, SIG_DFL); 1421a557d3cSschwarze kill(getpid(), signum); 1431a557d3cSschwarze /* NOTREACHED */ 1441a557d3cSschwarze _exit(1); 1451a557d3cSschwarze } 1461a557d3cSschwarze 147c0a657b3Sschwarze /* 148c0a657b3Sschwarze * Memory management callback functions for ohash. 149c0a657b3Sschwarze */ 150c0a657b3Sschwarze static void * 151c0a657b3Sschwarze tag_alloc(size_t sz, void *arg) 152c0a657b3Sschwarze { 153c0a657b3Sschwarze 154c0a657b3Sschwarze return(mandoc_malloc(sz)); 155c0a657b3Sschwarze } 156c0a657b3Sschwarze 157c0a657b3Sschwarze static void * 158c0a657b3Sschwarze tag_calloc(size_t nmemb, size_t sz, void *arg) 159c0a657b3Sschwarze { 160c0a657b3Sschwarze 161c0a657b3Sschwarze return(mandoc_calloc(nmemb, sz)); 162c0a657b3Sschwarze } 163c0a657b3Sschwarze 164c0a657b3Sschwarze static void 165c0a657b3Sschwarze tag_free(void *p, void *arg) 166c0a657b3Sschwarze { 167c0a657b3Sschwarze 168c0a657b3Sschwarze free(p); 169c0a657b3Sschwarze } 170