/*
 * $Id: misc.c,v 2.0.1.5 1996/06/26 18:39:38 alexis Exp alexis $
 *
 * UPS Daemon
 * The Wild Wind Communications, 1995, 1996
 *
 * See file LICENSE for the distribution terms of this software.
 */

#include "upsd.h"

/*
 * Creates the file and writes out our pid there.
 *
 * Returns zero upon success and -1 if failed.
 */
int
mkpid(pathname)
	char *pathname;
{
	register mode_t oldmask;
	FILE *f;

	oldmask = umask(022);
	if((f = fopen(pathname, "w")) == NULL) {
		syslog(LOG_ERR, "mkpidfile: cannot create %s: %m",
		    pathname);
		return -1;
	}
	fprintf(f, "%u\n", getpid());
	fclose(f);
	umask(oldmask);
	return 0;
}

/*
 * Removes the pid file.
 *
 * Returns zero upon success and -1 if failed.
 */
int
rmpid(pathname)
	char *pathname;
{
	if(unlink(pathname) == -1) {
		syslog(LOG_ERR, "rmpidfile: cannot unlink %s: %m",
		    pathname);
		return -1;
	}
	return 0;
}

/*
 * Allocates memory and handles errors. Returns pointer to the
 * newly allocated or NULL if failed.
 */
void *
xalloc(size)
	size_t size;
{
	register char *p;
	if((p = malloc(size)) == NULL) {
		syslog(LOG_ERR, "xalloc: cannot allocate %u bytes: %m", size);
		return NULL;
	}
	return p;
}

/*
 * Allocates memory and duplicates the string. Returns pointer to the
 * newly allocated area containing the string duplicate or NULL if
 * an error occured.
 */
char *
xstrdup(s)
	char *s;
{
	register char *p;
	register size_t sz;

	if(s == NULL) {
		return NULL;
	}

	if((p = xalloc((sz = strlen(s))+1)) == NULL) {
		return NULL;
	}
	bcopy(s, p, sz + 1);
	return p;
}

/*
 * Searches the list for the item with specified id. The list should
 * be terminated with an empty item with id equal to zero.
 *
 * Returns pointer onto item found or NULL if none found.
 */
void *
whereid(id, list, size)
	register int id;
	register void *list;
	register size_t size;
{
	while(((struct ident *)list)->id != id) {
		if(((struct ident *)list)->id == 0) {
			return NULL;
		}
		list += size;
	}
	return list;
}

/*
 * Searches the list for the item with specified name. The list
 * should be terminated with an empty item with id equal to zero.
 *
 * Returns pointer onto item found or NULL if none found.
 */
void *
wherename(name, list, size)
	register char *name;
	register void *list;
	register size_t size;
{
	for(;((struct ident *)list)->id != 0;list += size) {
		if(((struct ident *)list)->name == name) {
			return list;
		}
		if(((struct ident *)list)->name == NULL || name == NULL) {
			continue;
		}
		if(!strcmp(((struct ident *)list)->name, name)) {
			return list;
		}
	} 
	return NULL;
}

/*
 * Traverses through the chain and calls the function for every
 * element of the chain.
 *
 * This functions doesnt return anything.
 */
void
traverse(chain, func)
	struct chain *chain;
	void *(func)();
{
	while(chain) {
		func(chain);
		chain = chain->next;
	}
}

void
traverse2(chain, func, arg)
	struct chain *chain;
	void *(func)();
	void *arg;
{
	while(chain) {
		func(chain, arg);
		chain = chain->next;
	}
}

/*
 * Makes up a message. Every call to this function overwrites
 * previous message area.
 *
 * XXX: this whole function should be reworked.
 */
char *
expand(msg)
	char *msg;
{
	static char buf[MAXMESSAGELEN+1];
	register char *dst = buf;
	register char *src;
	register char *t;
	register struct ups_val *v;
	register struct ups_reg *r;

	bzero(dst, MAXMESSAGELEN+1);

	if((src = alloca(strlen(msg)+1)) == NULL) {
		syslog(LOG_ERR, "expand: alloca failed");
		return NULL;
	}
	bcopy(msg, src, strlen(msg)+1);

	while((t = index(src, '%')) != NULL) {
		*t = '\0';
		dst += snprintf(dst, MAXMESSAGELEN+1, "%s", src);
		src = t+1;
		if(*src == '%') {
			*dst++ = '%';
			src++;
		} else {
			if((t = index(src, '%')) == NULL) {
				syslog(LOG_ERR, "expand: unterminated %%");
			} else {
				*t = '\0';
				if(((r = REGISTERNAME(src)) != NULL) &&
				    ((v = VALUEID(r->id)) != NULL)) {
					dst += snprintval(dst, MAXMESSAGELEN+1, v);
				} else {
					syslog(LOG_ERR, "expand: incorrect register name for expansion: %s", src);
				}
				src = t+1;
			}
		}
	} 
	dst += snprintf(dst, MAXMESSAGELEN+1, "%s", src);
	return buf;
}

/*
 * Prints a value's content.
 */
int
snprintval(buf, size, val)
	char *buf;
	size_t size;
	struct ups_val *val;	
{
	register struct ups_reg *r;

	if((r = REGISTERID(val->id)) == NULL) {
		syslog(LOG_ERR, "snprintval: incorrect value id");
		return 0;
	}
	if((r->type & T_TYPE) == T_BINARY) {
		return snprintf(buf, size, "%*s", r->size - r->prec,
		    val->val.binary);
	} else {
		return snprintf(buf, size, "%.*lf", r->prec, val->val.number);
	}
}

/*
 * Executes a command.
 */
int
execute(command)
	char *command;
{
	return system(command);
}

/*
 * Gets current time and returns zero if successfull.
 */
int
getcurrenttime(void)
{
	if(time(&current_time) == -1) {
		syslog(LOG_ERR, "cannot get current time: %m");
		return -1;
	}
	return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1