/*
** utils.c
**
** Functions of general utility.
*/

#include "rc.h"

#include <errno.h>
#include <signal.h>

/* enh 1996/02/29 - convert a raw string into a protected string: that's to
** say, a string where all potentially troublesome characters have been
** escaped. The memory handling here is stupid, but I'm not at home with
** what rc's doing with its memory yet. */
/*
extern char *
protect_string ( char * s ) {
	char * p, *q;
	char * o = ealloc (3*strlen(s)+1);

	for ( p = s, q = o ; *p ; p++ ) {
		if ( *p == '\t' ) {
			*(q++) = '\\'; *(q++) = 't';
		} else if ( *p == '\r' ) {
			*(q++) = '\\'; *(q++) = 'r';
		} else if ( *p == '\n' ) {
			*(q++) = '\\'; *(q++) = 'n';
		} else if ( strchr ( "#;&|^$=~`'{}@!()<>\\", *p ) != NULL ) {
			*(q++) = '\''; *(q++) = *p; *(q++) = '\'';
		} else {
			*(q++) = *p;
		}
	}
	*q = '\0';
	p = strdup ( o );
	efree ( o );
	return p;
}
*/

/* print error with line number on noninteractive shells (i.e., scripts) */

extern void pr_error(char *s) {
	if (s != NULL) {
		if (interactive)
			fprint(STDERR_FILENO, "%s\n", s);
		else
			fprint(STDERR_FILENO, "line %d: %s\n", lineno - 1, s);
	}
}

/* our perror */

extern void uerror(char *s) {
	extern int sys_nerr;
	extern char *sys_errlist[];
	if (errno > sys_nerr)
		return;
	if (s != NULL)
		fprint(STDERR_FILENO, "%s: %s\n", s, sys_errlist[errno]);
	else
		fprint(STDERR_FILENO, "%s\n", sys_errlist[errno]);
}

/* Die horribly. This should never get called. Please let me know if it does. */

#define PANICMSG "rc panic: "

extern void panic(char *s) {
	write (STDERR_FILENO, PANICMSG, conststrlen(PANICMSG));
	write (STDERR_FILENO, s, strlen(s));
	write (STDERR_FILENO, "!\n", 2);
	exit (EXIT_FAILURE);
}

/* ascii -> unsigned conversion routines. -1 indicates conversion error. */

extern int n2u(char *s, unsigned int base) {
	unsigned int i;
	for (i = 0; *s != '\0'; s++) {
		unsigned int j = (unsigned int) *s - '0';
		if (j >= base) /* small hack with unsigned ints -- one compare for range test */
			return -1;
		i = i * base + j;
	}
	return (int) i;
}

/* The last word in portable ANSI: a strcmp wrapper for qsort */

extern int starstrcmp(const void *s1, const void *s2) {
	return strcmp(*(char **)s1, *(char **)s2);
}

/* tests to see if pathname begins with "/", "./", or "../" */

extern bool isabsolute(char *path) {
	return path[0] == '/' || (path[0] == '.' && (path[1] == '/' || (path[1] == '.' && path[2] == '/')));
}

/* signal-safe read and write (slow devices). writeall also allows partial writes */

extern void writeall(int fd, char *buf, size_t remain) {
	int i;
	for (i = 0; remain > 0; buf += i, remain -= i) {
		do {
			i = write (fd, buf, remain);
		} while (i == -1 && errno == EINTR);
		if (i <= 0) break; /* abort silently on errors in write() */
	}
	sigchk ();
}

extern int rc_read(int fd, char *buf, size_t n) {
	long /*ssize_t*/ r;
	do {
		r = read (fd, buf, n);
	} while (r == -1 && errno == EINTR);
	sigchk ();
	return r;
}

/* duplicate a fd and close the old one only if necessary */

extern int mvfd(int i, int j) {
	if (i != j) {
		int s = dup2(i, j);
		close(i);
		return s;
	}
	return 0;
}
