[BACK]Return to tag.c CVS log [TXT][DIR] Up to [cvsweb.bsd.lv] / mandoc

File: [cvsweb.bsd.lv] / mandoc / tag.c (download)

Revision 1.5, Sat Jul 25 14:28:59 2015 UTC (8 years, 8 months ago) by schwarze
Branch: MAIN
Changes since 1.4: +10 -32 lines

Simplify and make tag_put() more efficient by integrating tag_get()
into it and by only handling NUL-terminated strings.
Minus 25 lines of code, no functional change.

/*      $Id: tag.c,v 1.5 2015/07/25 14:28:59 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 <signal.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;
	int	 prio;
	char	 s[];
};

static	void	 tag_signal(int);
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.
 */
char *
tag_init(void)
{
	struct ohash_info	 tag_info;

	tag_fn = mandoc_strdup("/tmp/man.XXXXXXXXXX");
	signal(SIGHUP, tag_signal);
	signal(SIGINT, tag_signal);
	signal(SIGTERM, tag_signal);
	if ((tag_fd = mkstemp(tag_fn)) == -1) {
		free(tag_fn);
		tag_fn = NULL;
		return(NULL);
	}

	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);
	return(tag_fn);
}

/*
 * 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_fd == -1)
		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_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);
}

static void
tag_signal(int signum)
{

	tag_unlink();
	signal(signum, SIG_DFL);
	kill(getpid(), signum);
	/* NOTREACHED */
	_exit(1);
}

/*
 * 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);
}