Import bmake-20100808:
[pkgsrc.git] / devel / bmake / files / util.c
1 /*      $NetBSD: util.c,v 1.50 2010/06/03 15:40:16 sjg Exp $    */
2
3 /*
4  * Missing stuff from OS's
5  *
6  *      $Id: util.c,v 1.1.1.8 2010/09/07 14:12:10 joerg Exp $
7  */
8
9 #include "make.h"
10
11 #ifndef MAKE_NATIVE
12 static char rcsid[] = "$NetBSD: util.c,v 1.50 2010/06/03 15:40:16 sjg Exp $";
13 #else
14 #ifndef lint
15 __RCSID("$NetBSD: util.c,v 1.50 2010/06/03 15:40:16 sjg Exp $");
16 #endif
17 #endif
18
19 #include <errno.h>
20 #include <time.h>
21 #include <signal.h>
22
23 #if !defined(HAVE_STRERROR)
24 extern int errno, sys_nerr;
25 extern char *sys_errlist[];
26
27 char *
28 strerror(int e)
29 {
30     static char buf[100];
31     if (e < 0 || e >= sys_nerr) {
32         snprintf(buf, sizeof(buf), "Unknown error %d", e);
33         return buf;
34     }
35     else
36         return sys_errlist[e];
37 }
38 #endif
39
40 #if !defined(HAVE_SETENV) || !defined(HAVE_UNSETENV)
41 extern char **environ;
42
43 static char *
44 findenv(const char *name, int *offset)
45 {
46         size_t i, len;
47         char *p, *q;
48
49         for (i = 0; (q = environ[i]); i++) {
50                 char *p = strchr(q, '=');
51                 if (p == NULL)
52                         continue;
53                 if (strncmp(name, q, len = p - q) == 0) {
54                         *offset = i;
55                         return q + len + 1;
56                 }
57         }
58         *offset = i;
59         return NULL;
60 }
61 #endif
62
63 #if !defined(HAVE_UNSETENV)
64 int
65 unsetenv(const char *name)
66 {
67         char **p;
68         int offset;
69
70         if (name == NULL || *name == '\0' || strchr(name, '=') != NULL) {
71                 errno = EINVAL;
72                 return -1;
73         }
74
75         while (findenv(name, &offset))  { /* if set multiple times */
76                 for (p = &environ[offset];; ++p)
77                         if (!(*p = *(p + 1)))
78                                 break;
79         }
80         return 0;
81 }
82 #endif
83
84 #if !defined(HAVE_SETENV)
85 int
86 setenv(const char *name, const char *value, int rewrite)
87 {
88         static char **saveenv;  /* copy of previously allocated space */
89         char *c, **newenv;
90         const char *cc;
91         size_t l_value, size;
92         int offset;
93
94         if (name == NULL || value == NULL) {
95                 errno = EINVAL;
96                 return -1;
97         }
98
99         if (*value == '=')                      /* no `=' in value */
100                 ++value;
101         l_value = strlen(value);
102
103         /* find if already exists */
104         if ((c = findenv(name, &offset))) {
105                 if (!rewrite)
106                         return 0;
107                 if (strlen(c) >= l_value)       /* old larger; copy over */
108                         goto copy;
109         } else {                                        /* create new slot */
110                 size = sizeof(char *) * (offset + 2);
111                 if (saveenv == environ) {               /* just increase size */
112                         if ((newenv = realloc(saveenv, size)) == NULL)
113                                 return -1;
114                         saveenv = newenv;
115                 } else {                                /* get new space */
116                         /*
117                          * We don't free here because we don't know if
118                          * the first allocation is valid on all OS's
119                          */
120                         if ((saveenv = malloc(size)) == NULL)
121                                 return -1;
122                         (void)memcpy(saveenv, environ, size - sizeof(char *));
123                 }
124                 environ = saveenv;
125                 environ[offset + 1] = NULL;
126         }
127         for (cc = name; *cc && *cc != '='; ++cc)        /* no `=' in name */
128                 continue;
129         size = cc - name;
130         /* name + `=' + value */
131         if ((environ[offset] = malloc(size + l_value + 2)) == NULL)
132                 return -1;
133         c = environ[offset];
134         (void)memcpy(c, name, size);
135         c += size;
136         *c++ = '=';
137 copy:
138         (void)memcpy(c, value, l_value + 1);
139         return 0;
140 }
141
142 #ifdef TEST
143 int
144 main(int argc, char *argv[])
145 {
146         setenv(argv[1], argv[2], 0);
147         printf("%s\n", getenv(argv[1]));
148         unsetenv(argv[1]);
149         printf("%s\n", getenv(argv[1]));
150         return 0;
151 }
152 #endif
153
154 #endif
155
156
157 #if defined(__hpux__) || defined(__hpux)
158 /* strrcpy():
159  *      Like strcpy, going backwards and returning the new pointer
160  */
161 static char *
162 strrcpy(char *ptr, char *str)
163 {
164     int len = strlen(str);
165
166     while (len)
167         *--ptr = str[--len];
168
169     return (ptr);
170 } /* end strrcpy */
171
172
173 char    *sys_siglist[] = {
174         "Signal 0",
175         "Hangup",                       /* SIGHUP    */
176         "Interrupt",                    /* SIGINT    */
177         "Quit",                         /* SIGQUIT   */
178         "Illegal instruction",          /* SIGILL    */
179         "Trace/BPT trap",               /* SIGTRAP   */
180         "IOT trap",                     /* SIGIOT    */
181         "EMT trap",                     /* SIGEMT    */
182         "Floating point exception",     /* SIGFPE    */
183         "Killed",                       /* SIGKILL   */
184         "Bus error",                    /* SIGBUS    */
185         "Segmentation fault",           /* SIGSEGV   */
186         "Bad system call",              /* SIGSYS    */
187         "Broken pipe",                  /* SIGPIPE   */
188         "Alarm clock",                  /* SIGALRM   */
189         "Terminated",                   /* SIGTERM   */
190         "User defined signal 1",        /* SIGUSR1   */
191         "User defined signal 2",        /* SIGUSR2   */
192         "Child exited",                 /* SIGCLD    */
193         "Power-fail restart",           /* SIGPWR    */
194         "Virtual timer expired",        /* SIGVTALRM */
195         "Profiling timer expired",      /* SIGPROF   */
196         "I/O possible",                 /* SIGIO     */
197         "Window size changes",          /* SIGWINDOW */
198         "Stopped (signal)",             /* SIGSTOP   */
199         "Stopped",                      /* SIGTSTP   */
200         "Continued",                    /* SIGCONT   */
201         "Stopped (tty input)",          /* SIGTTIN   */
202         "Stopped (tty output)",         /* SIGTTOU   */
203         "Urgent I/O condition",         /* SIGURG    */
204         "Remote lock lost (NFS)",       /* SIGLOST   */
205         "Signal 31",                    /* reserved  */
206         "DIL signal"                    /* SIGDIL    */
207 };
208 #endif /* __hpux__ || __hpux */
209
210 #if defined(__hpux__) || defined(__hpux)
211 #include <sys/types.h>
212 #include <sys/syscall.h>
213 #include <sys/signal.h>
214 #include <sys/stat.h>
215 #include <dirent.h>
216 #include <sys/time.h>
217 #include <unistd.h>
218
219 int
220 killpg(int pid, int sig)
221 {
222     return kill(-pid, sig);
223 }
224
225 #if !defined(__hpux__) && !defined(__hpux)
226 void
227 srandom(long seed)
228 {
229     srand48(seed);
230 }
231
232 long
233 random(void)
234 {
235     return lrand48();
236 }
237 #endif
238
239 #if !defined(__hpux__) && !defined(__hpux)
240 int
241 utimes(char *file, struct timeval tvp[2])
242 {
243     struct utimbuf t;
244
245     t.actime  = tvp[0].tv_sec;
246     t.modtime = tvp[1].tv_sec;
247     return(utime(file, &t));
248 }
249 #endif
250
251 #if !defined(BSD) && !defined(d_fileno)
252 # define d_fileno d_ino
253 #endif
254
255 #ifndef DEV_DEV_COMPARE
256 # define DEV_DEV_COMPARE(a, b) ((a) == (b))
257 #endif
258 #define ISDOT(c) ((c)[0] == '.' && (((c)[1] == '\0') || ((c)[1] == '/')))
259 #define ISDOTDOT(c) ((c)[0] == '.' && ISDOT(&((c)[1])))
260
261 char *
262 getwd(char *pathname)
263 {
264     DIR    *dp;
265     struct dirent *d;
266     extern int errno;
267
268     struct stat st_root, st_cur, st_next, st_dotdot;
269     char    pathbuf[MAXPATHLEN], nextpathbuf[MAXPATHLEN * 2];
270     char   *pathptr, *nextpathptr, *cur_name_add;
271
272     /* find the inode of root */
273     if (stat("/", &st_root) == -1) {
274         (void)sprintf(pathname,
275                         "getwd: Cannot stat \"/\" (%s)", strerror(errno));
276         return NULL;
277     }
278     pathbuf[MAXPATHLEN - 1] = '\0';
279     pathptr = &pathbuf[MAXPATHLEN - 1];
280     nextpathbuf[MAXPATHLEN - 1] = '\0';
281     cur_name_add = nextpathptr = &nextpathbuf[MAXPATHLEN - 1];
282
283     /* find the inode of the current directory */
284     if (lstat(".", &st_cur) == -1) {
285         (void)sprintf(pathname,
286                         "getwd: Cannot stat \".\" (%s)", strerror(errno));
287         return NULL;
288     }
289     nextpathptr = strrcpy(nextpathptr, "../");
290
291     /* Descend to root */
292     for (;;) {
293
294         /* look if we found root yet */
295         if (st_cur.st_ino == st_root.st_ino &&
296             DEV_DEV_COMPARE(st_cur.st_dev, st_root.st_dev)) {
297             (void)strcpy(pathname, *pathptr != '/' ? "/" : pathptr);
298             return (pathname);
299         }
300
301         /* open the parent directory */
302         if (stat(nextpathptr, &st_dotdot) == -1) {
303             (void)sprintf(pathname,
304                             "getwd: Cannot stat directory \"%s\" (%s)",
305                             nextpathptr, strerror(errno));
306             return NULL;
307         }
308         if ((dp = opendir(nextpathptr)) == NULL) {
309             (void)sprintf(pathname,
310                             "getwd: Cannot open directory \"%s\" (%s)",
311                             nextpathptr, strerror(errno));
312             return NULL;
313         }
314
315         /* look in the parent for the entry with the same inode */
316         if (DEV_DEV_COMPARE(st_dotdot.st_dev, st_cur.st_dev)) {
317             /* Parent has same device. No need to stat every member */
318             for (d = readdir(dp); d != NULL; d = readdir(dp))
319                 if (d->d_fileno == st_cur.st_ino)
320                     break;
321         }
322         else {
323             /*
324              * Parent has a different device. This is a mount point so we
325              * need to stat every member
326              */
327             for (d = readdir(dp); d != NULL; d = readdir(dp)) {
328                 if (ISDOT(d->d_name) || ISDOTDOT(d->d_name))
329                     continue;
330                 (void)strcpy(cur_name_add, d->d_name);
331                 if (lstat(nextpathptr, &st_next) == -1) {
332                     (void)sprintf(pathname,
333                         "getwd: Cannot stat \"%s\" (%s)",
334                         d->d_name, strerror(errno));
335                     (void)closedir(dp);
336                     return NULL;
337                 }
338                 /* check if we found it yet */
339                 if (st_next.st_ino == st_cur.st_ino &&
340                     DEV_DEV_COMPARE(st_next.st_dev, st_cur.st_dev))
341                     break;
342             }
343         }
344         if (d == NULL) {
345             (void)sprintf(pathname,
346                 "getwd: Cannot find \".\" in \"..\"");
347             (void)closedir(dp);
348             return NULL;
349         }
350         st_cur = st_dotdot;
351         pathptr = strrcpy(pathptr, d->d_name);
352         pathptr = strrcpy(pathptr, "/");
353         nextpathptr = strrcpy(nextpathptr, "../");
354         (void)closedir(dp);
355         *cur_name_add = '\0';
356     }
357 } /* end getwd */
358
359 #endif /* __hpux */
360
361 #if !defined(HAVE_GETCWD)
362 char *
363 getcwd(path, sz)
364      char *path;
365      int sz;
366 {
367         return getwd(path);
368 }
369 #endif
370
371 /* force posix signals */
372 void (*
373 bmake_signal(int s, void (*a)(int)))(int)
374 {
375     struct sigaction sa, osa;
376
377     sa.sa_handler = a;
378     sigemptyset(&sa.sa_mask);
379     sa.sa_flags = SA_RESTART;
380
381     if (sigaction(s, &sa, &osa) == -1)
382         return SIG_ERR;
383     else
384         return osa.sa_handler;
385 }
386
387 #if !defined(HAVE_VSNPRINTF) || !defined(HAVE_VASPRINTF)
388 #include <stdarg.h>
389 #endif
390
391 #if !defined(HAVE_VSNPRINTF)
392 #if !defined(__osf__)
393 #ifdef _IOSTRG
394 #define STRFLAG (_IOSTRG|_IOWRT)        /* no _IOWRT: avoid stdio bug */
395 #else
396 #if 0
397 #define STRFLAG (_IOREAD)               /* XXX: Assume svr4 stdio */
398 #endif
399 #endif /* _IOSTRG */
400 #endif /* __osf__ */
401
402 int
403 vsnprintf(char *s, size_t n, const char *fmt, va_list args)
404 {
405 #ifdef STRFLAG
406         FILE fakebuf;
407
408         fakebuf._flag = STRFLAG;
409         /*
410          * Some os's are char * _ptr, others are unsigned char *_ptr...
411          * We cast to void * to make everyone happy.
412          */
413         fakebuf._ptr = (void *)s;
414         fakebuf._cnt = n-1;
415         fakebuf._file = -1;
416         _doprnt(fmt, args, &fakebuf);
417         fakebuf._cnt++;
418         putc('\0', &fakebuf);
419         if (fakebuf._cnt<0)
420             fakebuf._cnt = 0;
421         return (n-fakebuf._cnt-1);
422 #else
423 #ifndef _PATH_DEVNULL
424 # define _PATH_DEVNULL "/dev/null"
425 #endif
426         /*
427          * Rats... we don't want to clobber anything...
428          * do a printf to /dev/null to see how much space we need.
429          */
430         static FILE *nullfp;
431         int need = 0;                   /* XXX what's a useful error return? */
432
433         if (!nullfp)
434                 nullfp = fopen(_PATH_DEVNULL, "w");
435         if (nullfp) {
436                 need = vfprintf(nullfp, fmt, args);
437                 if (need < n)
438                         (void)vsprintf(s, fmt, args);
439         }
440         return need;
441 #endif
442 }
443 #endif
444
445 #if !defined(HAVE_SNPRINTF)
446 int
447 snprintf(char *s, size_t n, const char *fmt, ...)
448 {
449         va_list ap;
450         int rv;
451
452         va_start(ap, fmt);
453         rv = vsnprintf(s, n, fmt, ap);
454         va_end(ap);
455         return rv;
456 }
457 #endif
458                 
459 #if !defined(HAVE_STRFTIME)
460 size_t
461 strftime(char *buf, size_t len, const char *fmt, const struct tm *tm)
462 {
463         static char months[][4] = {
464                 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 
465                 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
466         };
467
468         size_t s;
469         char *b = buf;
470
471         while (*fmt) {
472                 if (len == 0)
473                         return buf - b;
474                 if (*fmt != '%') {
475                         *buf++ = *fmt++;
476                         len--;
477                         continue;
478                 }
479                 switch (*fmt++) {
480                 case '%':
481                         *buf++ = '%';
482                         len--;
483                         if (len == 0) return buf - b;
484                         /*FALLTHROUGH*/
485                 case '\0':
486                         *buf = '%';
487                         s = 1;
488                         break;
489                 case 'k':
490                         s = snprintf(buf, len, "%d", tm->tm_hour);
491                         break;
492                 case 'M':
493                         s = snprintf(buf, len, "%02d", tm->tm_min);
494                         break;
495                 case 'S':
496                         s = snprintf(buf, len, "%02d", tm->tm_sec);
497                         break;
498                 case 'b':
499                         if (tm->tm_mon >= 12)
500                                 return buf - b;
501                         s = snprintf(buf, len, "%s", months[tm->tm_mon]);
502                         break;
503                 case 'd':
504                         s = snprintf(buf, len, "%02d", tm->tm_mday);
505                         break;
506                 case 'Y':
507                         s = snprintf(buf, len, "%d", 1900 + tm->tm_year);
508                         break;
509                 default:
510                         s = snprintf(buf, len, "Unsupported format %c",
511                             fmt[-1]);
512                         break;
513                 }
514                 buf += s;
515                 len -= s;
516         }
517 }
518 #endif
519
520 #if !defined(HAVE_KILLPG)
521 #if !defined(__hpux__) && !defined(__hpux)
522 int
523 killpg(int pid, int sig)
524 {
525     return kill(-pid, sig);
526 }
527 #endif
528 #endif