/*ident "@(#)cls4:tools/pt/ptutil.c 1.15" */ /******************************************************************************* C++ source for the C++ Language System, Release 3.0. This product is a new release of the original cfront developed in the computer science research center of AT&T Bell Laboratories. Copyright (c) 1993 UNIX System Laboratories, Inc. Copyright (c) 1991, 1992 AT&T and UNIX System Laboratories, Inc. Copyright (c) 1984, 1989, 1990 AT&T. All Rights Reserved. THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE of AT&T and UNIX System Laboratories, Inc. The copyright notice above does not evidence any actual or intended publication of such source code. *******************************************************************************/ #include #include #include "pt.h" #include #include #include #ifndef NO_LOCK #ifdef LOCK_FCNTL #include #endif #ifdef LOCK_FLOCK #include #endif #ifdef LOCK_LOCKF #include #endif #endif /************************* UTILITIES *************************/ extern char* tdir; extern int verbose; extern long start_time; extern char* PROGNAME; /* get time */ long get_time() { long time(); return time((long)0); } /* fatal errors */ void fatal(msg, arg1, arg2) char* msg; char* arg1; char* arg2; { char buf[MAXLINE]; void exit(); sprintf(buf, msg, arg1, arg2); fprintf(stderr, "%s fatal error: %s\n", PROGNAME, buf); exit(1); } static long scnt = 0; /* get space */ char* gs(s) int s; { char* p; char* malloc(); if (s < 1) fatal("bad argument to gs()", (char*)0, (char*)0); if ((p = malloc(s)) == NULL) fatal("malloc() out of space", (char*)0, (char*)0); scnt++; return p; } /* free space */ void fs(p) char* p; { if (p == NULL) fatal("bad argument to fs()", (char*)0, (char*)0); if (scnt < 1) fatal("too many calls of fs()", (char*)0, (char*)0); free(p); scnt--; } /* copy a string */ char* copy(s) char* s; { char* p; if (s == NULL || !*s) fatal("bad argument to copy()", (char*)0, (char*)0); p = gs(strlen(s) + 1); strcpy(p, s); return p; } /* basename of a file */ char* basename(f, first) char* f; int first; { char* s; if (f == NULL || !*f || first < 0 || first > 1) fatal("bad argument to basename()", (char*)0, (char*)0); s = f + strlen(f) - 1; while (s > f && *s != '/') { /* maybe clip extension */ if (*s == '.' && first) { *s = 0; if (s > f && s[-1] == '.') { s[-1] = 0; s--; } first = 0; } s--; } if (s[0] == '/' && s[1]) return s + 1; else return f; } #if 0 /* replace one file extension with another */ void replace_ext(f, ext) char* f; char* ext; { char* s; char nwext[25]; char* t; int i; if (f == NULL || !*f || ext == NULL || !*ext) fatal("bad argument to replace_ext()", (char*)0, (char*)0); s = f + strlen(f) - 1; while (s > f && *s != '.') s--; if (s == f) return; /* preserve case when replacing extension */ strcpy(nwext, ext); t = s; i = 0; while (*t && nwext[i]) { if (isupper(*t) && islower(nwext[i])) nwext[i] = toupper(nwext[i]); else if (islower(*t) && isupper(nwext[i])) nwext[i] = tolower(nwext[i]); i++; t++; } strcpy(s, nwext); } #endif /************************* FILE MANIPULATION *************************/ /* copy a file */ int cp(old, new) char* old; char* new; { FILE* fpin; FILE* fpout; int c; if (old == NULL || !*old || new == NULL || !*new) fatal("bad argument to cp()", (char*)0, (char*)0); if ((fpin = fopen(old, "r")) == NULL) return -1; if ((fpout = fopen(new, "w")) == NULL) { fclose(fpin); return -1; } /* actual copy - needs to work on binary files */ for (;;) { c = getc(fpin); if (feof(fpin)) break; putc(c, fpout); } fclose(fpin); fclose(fpout); return 0; } /* move a file */ int mv(old, new, d1, d2) char* old; char* new; char* d1; char* d2; { struct stat sb1; struct stat sb2; int flag; if (old == NULL || !*old || new == NULL || !*new || d1 == NULL || !*d1 || d2 == NULL || !*d2) fatal("bad argument to mv()", (char*)0, (char*)0); unlink(new); /* can we use links? */ flag = 0; if (!strcmp(d1, d2)) flag = 1; if (!flag) { if (stat(d1, &sb1) < 0 || stat(d2, &sb2) < 0) return -1; flag = (sb1.st_dev == sb2.st_dev); } /* links */ #if 0 if (flag) { if (link(old, new) < 0 || unlink(old) < 0) return -1; } /* actual copy */ else { if (cp(old, new) < 0) return -1; unlink(old); } #else if (flag) { if (link(old, new) >= 0 && unlink(old) >= 0) return 0; } if (cp(old, new) < 0) return -1; unlink(old); #endif return 0; } /* compare two files to see if they are the same physical file */ int icmp(f1, f2) char* f1; char* f2; { struct stat sb1; struct stat sb2; if (f1 == NULL || !*f1 || f2 == NULL || !*f2) fatal("bad argument to icmp()", (char*)0, (char*)0); if (stat(f1, &sb1) < 0 || stat(f2, &sb2) < 0) return 0; return sb1.st_dev == sb2.st_dev && sb1.st_ino == sb2.st_ino; } /* get the device and inode for a file */ void get_devnum(f, dev, num) char* f; unsigned long* dev; unsigned long* num; { struct stat sb; if (f == NULL || !*f || dev == NULL || num == NULL) fatal("bad argument to get_devnum()", (char*)0, (char*)0); *dev = 0; *num = 0; if (stat(f, &sb) < 0) return; *dev = sb.st_dev; *num = sb.st_ino; } /* get current working directory */ void get_cwd(p) char* p; { char* getcwd(); if (p == NULL) fatal("bad argument to get_cwd()", (char*)0, (char*)0); if (getcwd(p, MAXPATH) == NULL) fatal("could not get current working directory", (char*)0, (char*)0); } /* compare two files for equality */ int fcmp(f1, f2) char* f1; char* f2; { FILE* fp1; FILE* fp2; int c1; int c2; if (f1 == NULL || !*f1 || f2 == NULL || !*f2) fatal("bad argument to fcmp()", (char*)0, (char*)0); if ((fp1 = fopen(f1, "r")) == NULL) return 0; if ((fp2 = fopen(f2, "r")) == NULL) { fclose(fp1); return 0; } for (;;) { c1 = getc(fp1); c2 = getc(fp2); if (c1 != c2 || c1 == EOF) break; } fclose(fp1); fclose(fp2); return c1 == c2; } /* delete a file */ void del_file(f) char* f; { if (f == NULL || !*f) fatal("bad argument to del_file()", (char*)0, (char*)0); unlink(f); } /* get a modification timestamp for a file; 0 if file does not exist */ unsigned long timestamp(s) char* s; { struct stat sb; if (s == NULL || !*s) fatal("bad argument to timestamp()", (char*)0, (char*)0); if (stat(s, &sb) < 0) return 0; if (sb.st_mtime == 0) { fprintf(stderr, "%s warning: ##### timestamp of 0 for %s #####\n", PROGNAME, s); return 1; } return sb.st_mtime; } /* set the umask for file creation */ void set_umask(r) char* r; { struct stat sb; if (r == NULL || !*r) fatal("bad argument to set_umask()", (char*)0, (char*)0); if (stat(r, &sb) < 0) fatal("could not stat %s", r, (char*)0); umask(~sb.st_mode & 0777); } /* set repository permissions to those of the parent directory */ void set_rep_perms(r) char* r; { struct stat sb; if (r == NULL || !*r) fatal("bad argument to set_rep_perms()", (char*)0, (char*)0); /* change the mode */ umask(0); if (stat(".", &sb) < 0) fatal("could not stat %s", ".", (char*)0); if (chmod(r, sb.st_mode & 0777) < 0) fatal("could not chmod %s", r, (char*)0); /* change the group - no error if doesn't work */ chown(r, (int)getuid(), (int)sb.st_gid); } /* check whether a file exists */ int facc(f) char* f; { struct stat sb; if (f == NULL || !*f) fatal("bad argument to facc()", (char*)0, (char*)0); return stat(f, &sb) == 0; } /* hash a string */ unsigned long hash(s, n) char* s; long n; { unsigned long h; if (s == NULL || !*s || n < 1) fatal("bad argument to hash()", (char*)0, (char*)0); h = 0; while (*s) h = h * 271 + *s++; return h % n; } /* give progress messages */ void progress(s, a1, a2) char* s; char* a1; char* a2; { char buf[MAXLINE]; if (s == NULL || !*s) fatal("bad argument to progress()", (char*)0, (char*)0); if (!verbose) return; sprintf(buf, s, a1, a2); fprintf(stderr, "%s %s [%d] ...\n", PROGNAME, buf, get_time() - start_time); start_time = get_time(); } void progress2() { if (verbose) fprintf(stderr, "\n"); } /************************* SIGNALS *************************/ #ifdef NO_SIGNAL void signal_block() { } void signal_unblock() { } #else typedef void (*T)(); static T old_int; static T old_quit; static int sig_flag = 0; void signal_block(t) T t; { if (t == NULL) fatal("bad argument to signal_block()", (char*)0, (char*)0); if (sig_flag) fatal("nested call of signal_block()", (char*)0, (char*)0); old_int = (T)signal(SIGINT, t); old_quit = (T)signal(SIGQUIT, t); sig_flag = 1; } void signal_unblock() { if (!sig_flag) fatal("signal_unblock() called with no prior block", (char*)0, (char*)0); signal(SIGINT, old_int); signal(SIGQUIT, old_quit); sig_flag = 0; } #endif /************************* LOCKING *************************/ #ifdef LOCK_FCNTL #undef LOCK_FLOCK #undef LOCK_LOCKF #endif #ifdef LOCK_FLOCK #undef LOCK_FCNTL #undef LOCK_LOCKF #endif #ifdef LOCK_LOCKF #undef LOCK_FCNTL #undef LOCK_FLOCK #endif static int lock_cnt = 0; static int lock_fd = -1; static char* lock_str = "_lock"; #ifdef NO_LOCK /* lock a file */ int lock_file(f) char* f; { return 0; } /* unlock a file */ int unlock_file() { return 0; } /* lock a repository */ void lock_rep(r) char* r; { } /* unlock a repository */ void unlock_rep(r) char* r; { } #else /* lock a file */ int lock_file(f) char* f; { #ifdef LOCK_FCNTL struct flock fl; #endif if (lock_fd < 0) lock_fd = open(f, O_WRONLY | O_CREAT, 0666); if (lock_fd < 0) fatal("could not get file descriptor to lock %s - possible permissions problem", f, (char*)0); #ifdef LOCK_FCNTL fl.l_type = F_WRLCK; fl.l_whence = SEEK_SET; fl.l_start = 0; fl.l_len = 0; return fcntl(lock_fd, F_SETLK, &fl); #endif #ifdef LOCK_FLOCK return flock(lock_fd, LOCK_EX | LOCK_NB); #endif #ifdef LOCK_LOCKF return lockf(lock_fd, F_TLOCK, 0); #endif } /* unlock a file */ int unlock_file() { int ret; #ifdef LOCK_FCNTL struct flock fl; fl.l_type = F_UNLCK; fl.l_whence = SEEK_SET; fl.l_start = 0; fl.l_len = 0; ret = fcntl(lock_fd, F_SETLK, &fl); #endif #ifdef LOCK_FLOCK ret= flock(lock_fd, LOCK_UN); #endif #ifdef LOCK_LOCKF ret = lockf(lock_fd, F_ULOCK, 0); #endif if (ret < 0 || close(lock_fd) < 0) { lock_fd = -1; return -1; } lock_fd = -1; return 0; } /* lock a repository */ void lock_rep(r) char* r; { char fbuf[MAXPATH]; int i; if (r == NULL || !*r) fatal("bad argument to lock_rep()", (char*)0, (char*)0); if (lock_cnt++ > 0) fatal("repository %s already locked", r, (char*)0); sprintf(fbuf, "%s/%s", r, lock_str); i = LOCK_MAX; while (i-- > 0) { if (lock_file(fbuf) >= 0) return; fprintf(stderr, "%s: waiting to lock repository %s, sleeping ...\n", PROGNAME, r); sleep(LOCK_SLEEP); } fatal("could not get lock on repository %s", r, (char*)0); } /* unlock a repository */ void unlock_rep(r) char* r; { if (r == NULL || !*r) fatal("bad argument to unlock_rep()", (char*)0, (char*)0); if (lock_cnt-- != 1) fatal("unlock_rep() called when not locked", (char*)0, (char*)0); if (unlock_file() < 0) fatal("cannot unlock repository %s", r, (char*)0); } #endif /************************* SYSTEM AND POPEN *************************/ #ifndef SLOW_SYSTEM /* fast system() function */ int fast_system(s) char* s; { int status; int pid; int w; char cbuf[MAXCBUF]; char* cbufp[MAXCBUF/4]; int n; char* t; int fdcnt; int fdlist[3][2]; int fd; int i; int j; if (s == NULL || !*s) fatal("bad argument to fast_system()", (char*)0, (char*)0); /* split apart input */ strcpy(cbuf, s); t = cbuf; n = 0; for (;;) { while (*t && *t <= ' ') t++; if (!*t) break; cbufp[n++] = t; while (*t > ' ') t++; if (*t) *t++ = 0; } cbufp[n] = 0; if (n < 2) fatal("missing argument to fast_system()", (char*)0, (char*)0); /* start up child */ if ((pid = fork()) == 0) { /* handle I/O redirection */ fdcnt = 0; for (i = 0; i < n; i++) { if (isdigit(cbufp[i][0]) && cbufp[i][1] == '>') { fd = creat(&cbufp[i][2], 0666); if (fd < 0) return -1; fdlist[fdcnt][0] = cbufp[i][0] - '0'; fdlist[fdcnt][1] = fd; fdcnt++; cbufp[i] = 0; } } for (i = 0; i <= 2; i++) { for (j = 0; j < fdcnt; j++) { if (i == fdlist[j][0]) break; } if (j < fdcnt) { close(i); dup(fdlist[j][1]); close(fdlist[j][1]); } } /* execute */ execvp(cbufp[0], cbufp); _exit(127); } /* wait on child */ while ((w = wait(&status)) != pid && w != -1) ; if (w == -1) status = -1; return status; } /* fast popen() */ FILE* fast_popen(cmd, mode) char* cmd; char* mode; { char fbuf[MAXPATH]; char cmd2[MAXCBUF]; if (cmd == NULL || !*cmd || mode == NULL || !*mode) fatal("bad argument to fast_popen()", (char*)0, (char*)0); /* dump into a temporary file */ sprintf(fbuf, "%s/popen_buf", tdir); sprintf(cmd2, "%s 1>%s", cmd, fbuf); if (fast_system(cmd2)) return NULL; /* return pointer to that file */ return fopen(fbuf, "r"); } /* fast pclose() */ int fast_pclose(fp) FILE* fp; { if (fp == NULL) fatal("bad argument to fast_pclose()", (char*)0, (char*)0); return fclose(fp); } #endif /************************* STRING LISTS *************************/ /* add to a string list */ void slp_add(slp, name) Slist* slp; char* name; { char** np; int i; if (slp == NULL || name == NULL || !*name) fatal("bad argument to slp_add()", (char*)0, (char*)0); /* first time */ if (slp->n == 0) { slp->max = LISTSTART; slp->ptrs = (char**)gs(sizeof(char*) * slp->max); } /* grow list if have to */ else if (slp->n >= slp->max) { np = (char**)gs(sizeof(char*) * slp->max * 2); for (i = 0; i < slp->n; i++) np[i] = slp->ptrs[i]; slp->max *= 2; fs((char*)slp->ptrs); slp->ptrs = np; } slp->ptrs[slp->n++] = copy(name); } /* add to a string list if not already there */ int slp_adduniq(slp, name) Slist* slp; char* name; { int i; char** p; if (slp == NULL || name == NULL || !*name) fatal("bad argument to slp_adduniq()", (char*)0, (char*)0); if (slp->n) { for (i = slp->n - 1, p = slp->ptrs + i; i >= 0; i--, p--) { if (!STRCMP(*p, name)) return 0; } } slp_add(slp, name); return 1; } /* delete a string list */ void slp_del(slp) Slist* slp; { int i; if (slp == NULL) fatal("bad argument to slp_del()", (char*)0, (char*)0); if (slp->n < 0 || (slp->n > 0 && slp->ptrs == NULL)) fatal("string list corrupted", (char*)0, (char*)0); for (i = 0; i < slp->n; i++) fs((char*)slp->ptrs[i]); if (slp->n > 0) fs((char*)slp->ptrs); slp->n = 0; } /* sort a list of strings */ void slp_sort(slp) Slist* slp; { int h; int i; int j; char* m; char** ms; if (slp == NULL) fatal("bad argument to slp_sort()", (char*)0, (char*)0); if (!slp->n) return; /* sort using a Shell sort */ h = 1; ms = slp->ptrs - 1; do h = h * 3 + 1; while (h <= slp->n); do { h /= 3; for (i = h + 1; i <= slp->n; i++) { m = ms[i]; j = i; while (strcmp(ms[j - h], m) > 0) { ms[j] = ms[j - h]; j -= h; if (j <= h) break; } ms[j] = m; } } while (h != 1); } /* see if any members of p1 are found in p2 --> p3 */ int slp_eq(p1, p2, p3) Slist* p1; Slist* p2; Slist* p3; { int i; int j; if (p1 == NULL || p2 == NULL || p3 == NULL) fatal("bad argument to slp_eq()", (char*)0, (char*)0); for (i = 0; i < p1->n; i++) { for (j = 0; j < p2->n; j++) { if (!STRCMP(p1->ptrs[i], p2->ptrs[j])) { slp_add(p3, p1->ptrs[i]); break; } } } return p3->n > 0; } /* see if p1 is a subset of p2 with members that are not --> p3 */ int slp_subset(p1, p2, p3) Slist* p1; Slist* p2; Slist* p3; { int i; int j; if (p1 == NULL || p2 == NULL || p3 == NULL) fatal("bad argument to slp_subset()", (char*)0, (char*)0); for (i = 0; i < p1->n; i++) { for (j = 0; j < p2->n; j++) { if (!STRCMP(p1->ptrs[i], p2->ptrs[j])) break; } if (j == p2->n) slp_add(p3, p1->ptrs[i]); } return p3->n == 0; }