/* utils.c: functions of general utility */
/* print error with line number on noninteractive shells (i.e., scripts) */
extern void pr_error(char *s
) {
fprint(2, "line %d: %s\n", lineno
- 1, s
);
extern void uerror(char *s
) {
extern char *sys_errlist
[];
fprint(2, "%s: %s\n", s
, sys_errlist
[errno
]);
fprint(2, "%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(2, PANICMSG
, conststrlen(PANICMSG
));
/* ascii -> unsigned conversion routines. -1 indicates conversion error. */
extern int n2u(char *s
, unsigned int base
) {
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 */
/* 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 (for BSD slow devices). writeall also allows partial writes */
extern void writeall(int fd
, char *buf
, size_t remain
) {
for (i
= 0; remain
> 0; buf
+= i
, remain
-= i
) {
interrupt_happened
= FALSE
;
if (!setjmp(slowbuf
.j
)) {
else if ((i
= write(fd
, buf
, remain
)) <= 0)
break; /* abort silently on errors in write() */
extern int rc_read(int fd
, char *buf
, size_t n
) {
interrupt_happened
= FALSE
;
if (!setjmp(slowbuf
.j
)) {
/* clear out z bytes from character string s */
extern char *clear(char *s
, size_t z
) {
/* duplicate a fd and close the old one only if necessary */
extern int mvfd(int i
, int j
) {