diff options
Diffstat (limited to 'tag.c')
-rw-r--r-- | tag.c | 183 |
1 files changed, 183 insertions, 0 deletions
@@ -0,0 +1,183 @@ +/* $Id: tag.c,v 1.1 2015/07/17 22:38:29 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 <sys/types.h> + +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#if HAVE_OHASH +#include <ohash.h> +#else +#include "compat_ohash.h" +#endif + +#include "mandoc_aux.h" +#include "tag.h" + +struct tag_entry { + size_t line; + char s[]; +}; + +static void *tag_alloc(size_t, void *); +static void tag_free(void *, void *); +static void *tag_calloc(size_t, size_t, void *); + +static struct ohash tag_data; +static char *tag_fn = NULL; +static int tag_fd = -1; + + +/* + * Set up the ohash table to collect output line numbers + * where various marked-up terms are documented and create + * the temporary tags file, saving the name for the pager. + */ +void +tag_init(void) +{ + struct ohash_info tag_info; + + tag_fn = mandoc_strdup("/tmp/man.XXXXXXXXXX"); + if ((tag_fd = mkstemp(tag_fn)) == -1) { + free(tag_fn); + tag_fn = NULL; + return; + } + + tag_info.alloc = tag_alloc; + tag_info.calloc = tag_calloc; + tag_info.free = tag_free; + tag_info.key_offset = offsetof(struct tag_entry, s); + tag_info.data = NULL; + ohash_init(&tag_data, 4, &tag_info); +} + +char * +tag_filename(void) +{ + + return(tag_fn); +} + +/* + * Return the line number where a term is defined, + * or 0 if the term is unknown. + */ +size_t +tag_get(const char *s, size_t len) +{ + struct tag_entry *entry; + const char *end; + unsigned int slot; + + if (tag_fd == -1) + return(0); + if (len == 0) + len = strlen(s); + end = s + len; + slot = ohash_qlookupi(&tag_data, s, &end); + entry = ohash_find(&tag_data, slot); + return(entry == NULL ? 0 : entry->line); +} + +/* + * Set the line number where a term is defined. + */ +void +tag_put(const char *s, size_t len, size_t line) +{ + struct tag_entry *entry; + const char *end; + unsigned int slot; + + if (tag_fd == -1) + return; + if (len == 0) + len = strlen(s); + end = s + len; + slot = ohash_qlookupi(&tag_data, s, &end); + entry = ohash_find(&tag_data, slot); + if (entry == NULL) { + entry = mandoc_malloc(sizeof(*entry) + len + 1); + memcpy(entry->s, s, len); + entry->s[len] = '\0'; + ohash_insert(&tag_data, slot, entry); + } + entry->line = line; +} + +/* + * 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_fd == -1) + return; + stream = fdopen(tag_fd, "w"); + entry = ohash_first(&tag_data, &slot); + while (entry != NULL) { + if (stream != NULL) + fprintf(stream, "%s - %zu\n", entry->s, entry->line); + free(entry); + entry = ohash_next(&tag_data, &slot); + } + ohash_delete(&tag_data); + if (stream != NULL) + fclose(stream); +} + +void +tag_unlink(void) +{ + + if (tag_fn != NULL) + unlink(tag_fn); +} + +/* + * Memory management callback functions for ohash. + */ +static void * +tag_alloc(size_t sz, void *arg) +{ + + return(mandoc_malloc(sz)); +} + +static void * +tag_calloc(size_t nmemb, size_t sz, void *arg) +{ + + return(mandoc_calloc(nmemb, sz)); +} + +static void +tag_free(void *p, void *arg) +{ + + free(p); +} |