/*ident "@(#)cls4:tools/pt/ptcomp.c 1.9" */
/*******************************************************************************
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 <stdio.h>
#include <ctype.h>
#include "pt.h"
char* tdir;
int verbose = 0;
long start_time;
char* PROGNAME = "CC[ptcomp]";
/************************* PROCESS A MAP FILE *************************/
typedef struct Map Map;
struct Map {
char* name;
char* file;
Map* next;
char rtype;
};
static Map* maph = NULL;
static Map* mapc = NULL;
/* strip quotes off a name */
char* strip(s, buf)
char* s;
char* buf;
{
if (s == NULL || !*s || buf == NULL)
fatal("bad argument to strip()", (char*)0, (char*)0);
if (*s == '"' || *s == '<') {
strcpy(buf, s + 1);
buf[strlen(buf) - 1] = 0;
}
else {
strcpy(buf, s);
}
return buf;
}
/* get the basename of a header file */
char* getbase(p, ilist)
char* p;
Slist* ilist;
{
char* s;
int len;
int i;
char buf[MAXPATH];
char* orig;
int maxlen;
if (p == NULL || !*p || ilist == NULL)
fatal("bad argument to getbase()", (char*)0, (char*)0);
/* clip any prefix from -I list */
orig = p;
maxlen = 0;
for (i = 0; i < ilist->n; i++) {
s = ilist->ptrs[i];
if (s[0] != '-' || s[1] != 'I')
continue;
s += 2;
if (!strncmp(s, p, len = strlen(s)) &&
p[len] == '/' && len > maxlen) {
maxlen = len;
}
}
if (maxlen)
p += maxlen + 1;
/* clip off any ./ */
if (!maxlen && p[0] == '.' && p[1] == '/')
p += 2;
/* see if file refers to local directory */
if ((!maxlen && orig[0] != '/') || icmp(basename(orig, 0), orig))
sprintf(buf, "\"%s\"", p);
else
sprintf(buf, "<%s>", p);
return copy(buf);
}
/* read raw cfront output */
void readcfout(f, ilist)
char* f;
Slist* ilist;
{
FILE* fp;
char* flds[3];
char* s;
char* start;
int i;
Map* p;
char fbuf[MAXLINE];
char t;
char buf[MAXLINE];
if (f == NULL || !*f || ilist == NULL)
fatal("bad argument to readcfout()", (char*)0, (char*)0);
if ((fp = fopen(f, "r")) == NULL)
fatal("could not open map file %s for reading", f, (char*)0);
/* iterate over type records and pick apart fields */
while (fgets(fbuf, MAXLINE, fp) != NULL) {
s = fbuf;
for (i = 0; i <= 2; i++) {
while (*s && *s <= ' ')
s++;
start = s;
while (*s && *s > ' ')
s++;
if (s == start)
break;
*s++ = 0;
flds[i] = start;
}
if (i != 3) {
fprintf(stderr, "%s warning: ##### illegally formatted record in map file %s, ignoring #####\n", PROGNAME, f);
continue;
}
p = (Map*)gs(sizeof(Map));
t = flds[0][0];
if (t != 'c' && t != 's' && t != 'u' &&
t != 'f' && t != 't' && t != 'e') {
sprintf(buf, "bad record type \"%c\" in map file %s", t, f);
fatal(buf, (char*)0, (char*)0);
}
/* add record to list */
p->rtype = t;
p->name = copy(flds[1]);
p->file = getbase(flds[2], ilist);
p->next = NULL;
if (maph == NULL) {
maph = p;
mapc = maph;
}
else {
mapc->next = p;
mapc = p;
}
}
fclose(fp);
}
/************************* TYPE LISTS *************************/
typedef struct Tfile Tfile;
struct Tfile {
char* name;
Slist files;
Slist bns;
Tfile* next;
char type;
char deleted;
};
static Tfile* tftab[TFTABSIZE2];
static Slist tab;
/* read a map file */
void readtf(f, failok)
char* f;
int failok;
{
FILE* fp;
char buf[MAXMAPL];
char lbuf[MAXLINE];
int ln;
char* s;
Slist* slp;
Tfile* p;
int h;
char* t;
Slist* slp2;
int err;
char* start;
int len;
int flag;
int indx;
if (f == NULL || !*f)
fatal("bad argument to readtf()", (char*)0, (char*)0);
if ((fp = fopen(f, "r")) == NULL && !failok)
fatal("cannot open map file %s for reading", f, (char*)0);
if (fp == NULL)
return;
ln = 0;
slp = NULL;
/* iterate over lines of file */
while (fgets(buf, MAXMAPL, fp) != NULL) {
ln++;
len = strlen(buf) - 1;
if (buf[len] != '\n') {
sprintf(lbuf, "%d", ln);
fatal("missing newline at line %s of map file %s", lbuf, f);
}
buf[len] = 0;
s = buf;
while (*s && *s <= ' ')
s++;
if (!*s)
continue;
/* might be string table */
if (!strcmp(s, "@tab")) {
flag = 0;
while (fgets(buf, MAXMAPL, fp) != NULL) {
ln++;
buf[strlen(buf) - 1] = 0;
if (!strcmp(buf, "@etab")) {
flag = 1;
break;
}
slp_add(&tab, buf);
}
if (!flag || !tab.n) {
sprintf(lbuf, "%d", ln);
fatal("incorrectly formatted map file %s at line %s", f, lbuf);
}
continue;
}
/* check formatting */
err = 0;
if (s[0] == '@') {
if (strncmp(s, "@dec", 4) && strncmp(s, "@def", 4))
err = 1;
if (!err && s[4] != ' ')
err = 1;
t = s + 5;
while (*t && *t <= ' ')
t++;
if (!err && !isalpha(*t) && *t != '_')
err = 1;
if (err) {
sprintf(lbuf, "%d", ln);
fatal("incorrectly formatted map file %s at line %s", f, lbuf);
}
}
/* start of a new type */
if (s[0] == '@') {
if (slp != NULL && slp->n < 1) {
sprintf(lbuf, "%d", ln);
fatal("no files found for type in map file %s at line %s", f, lbuf);
}
p = (Tfile*)gs(sizeof(Tfile));
p->type = (s[3] == 'f' ? 'F' : 'C');;
/* get type name */
t = s + 5;
while (*t && *t <= ' ')
t++;
while (isalnum(*t) || *t == '_')
t++;
if (*t)
*t++ = 0;
else
*t = 0;
p->name = copy(s + 5);
slp = &p->files;
slp->n = 0;
/* get list of basenames */
slp2 = &p->bns;
slp2->n = 0;
for (;;) {
while (*t && *t <= ' ')
t++;
if (!*t)
break;
start = t;
while (*t && *t > ' ')
t++;
if (*t)
*t++ = 0;
else
*t = 0;
if (start[0] == '\\' && !start[1]) {
if (fgets(buf, MAXMAPL, fp) == NULL)
fatal("premature EOF for map file %s", f, (char*)0);
ln++;
len = strlen(buf) - 1;
if (buf[len] != '\n') {
sprintf(lbuf, "%d", ln);
fatal("missing newline at line %s of map file %s", lbuf, f);
}
buf[len] = 0;
t = buf;
}
else {
if (start[0] == '@' && isdigit(start[1])) {
indx = atoi(start + 1);
if (indx < 0 || indx >= tab.n) {
sprintf(lbuf, "%d", ln);
fatal("index for string table out of range at line %s of map file %s", lbuf, f);
}
slp_add(slp2, tab.ptrs[indx]);
}
else {
slp_add(slp2, start);
slp_adduniq(&tab, start);
}
}
}
p->deleted = 0;
h = (int)hash(p->name, (long)TFTABSIZE2);
p->next = tftab[h];
tftab[h] = p;
}
/* another file for preceding type */
else {
if (slp == NULL) {
sprintf(lbuf, "%d", ln);
fatal("incorrectly formatted map file %s at line %s", f, lbuf);
}
slp_add(slp, s);
}
}
if (slp != NULL && slp->n < 1)
fatal("premature EOF for map file %s", f, (char*)0);
fclose(fp);
}
/************************* TABLE OF FILENAMES SEEN *************************/
typedef struct Fname Fname;
struct Fname {
char* name;
Fname* next;
};
static Fname* ftab[FTSIZE2];
/* look up a filename */
Fname* lookup(s)
char* s;
{
Fname* p;
if (s == NULL || !*s)
fatal("bad argument to lookup()", (char*)0, (char*)0);
p = ftab[(int)hash(s, (long)FTSIZE2)];
while (p != NULL) {
if (!STRCMP(s, p->name))
return p;
p = p->next;
}
return NULL;
}
/* add a filename */
void add(s)
char* s;
{
Fname* p;
int h;
if (s == NULL || !*s)
fatal("bad argument to add()", (char*)0, (char*)0);
p = ftab[h = (int)hash(s, (long)FTSIZE2)];
while (p != NULL) {
if (!strcmp(s, p->name))
return;
p = p->next;
}
if (p == NULL) {
p = (Fname*)gs(sizeof(Fname));
p->next = ftab[h];
ftab[h] = p;
p->name = copy(s);
}
}
/************************* TABLE OF BASENAMES *************************/
typedef struct Bnlist Bnlist;
struct Bnlist {
char* name;
char* indx;
Bnlist* next;
};
static Bnlist* bntab[BNSIZE];
/* look up a basename in string table list */
char* bn_lookup(s)
char* s;
{
int i;
static int first_flag = 0;
Bnlist* p;
int h;
char buf[MAXLINE];
if (s == NULL || !*s)
fatal("bad argument to bn_lookup()", (char*)0, (char*)0);
/* set up table */
if (!first_flag++) {
for (i = 0; i < tab.n; i++) {
h = (int)hash(tab.ptrs[i], (long)BNSIZE);
p = (Bnlist*)gs(sizeof(Bnlist));
p->name = copy(tab.ptrs[i]);
sprintf(buf, "@%d", i);
p->indx = copy(buf);
p->next = bntab[h];
bntab[h] = p;
}
}
/* look up basename */
h = (int)hash(s, (long)BNSIZE);
p = bntab[h];
while (p != NULL && strcmp(s, p->name))
p = p->next;
if (p != NULL)
return p->indx;
else
fatal("basename %s not found in basename list", s, (char*)0);
return NULL;
}
/*****************************************************************************/
main(argc, argv)
int argc;
char* argv[];
{
char sb1[MAXPATH];
char sb2[MAXPATH];
char* bn;
char fbuf[MAXPATH];
char fbuf2[MAXPATH];
Map* p;
int i;
FILE* fp;
char* rep;
char* tout;
char* nmap;
char* progname;
int j;
Tfile* tfp;
int h;
char* n;
int lock_flag;
int len;
int len2;
int dflag;
char* fincl;
int flag;
Slist ilist;
char* s;
char buf3[MAXPATH];
start_time = get_time();
/* check out arguments */
lock_flag = 1;
dflag = 0;
while (argc >= 2 && !strncmp(argv[1], "-pt", 3)) {
switch (argv[1][3]) {
case 'l':
lock_flag = 0;
break;
case 'v':
verbose = 1;
break;
case 'd':
dflag = 1;
break;
default:
break; /* ignore bad options */
}
argc--;
argv++;
}
if (argc != 6)
fatal("usage is: ptcomp [-ptv] repository toutfile nmap progname incl", (char*)0, (char*)0);
if (!lock_flag)
verbose = 0;
progress2();
rep = argv[1];
tout = argv[2];
nmap = argv[3];
progname = basename(copy(argv[4]), 1);
fincl = argv[5];
if (!*progname)
fatal("progname passed to ptcomp is empty string", (char*)0, (char*)0);
/* maybe change permissions on repository */
if (dflag)
set_rep_perms(rep);
/* set umask */
set_umask(rep);
/* lock repository */
if (lock_flag) {
lock_rep(rep);
progress("locked repository", (char*)0, (char*)0);
}
/* read in include list */
if ((fp = fopen(fincl, "r")) == NULL)
fatal("cannot open include list %s for reading", fincl, (char*)0);
ilist.n = 0;
while (fgets(buf3, MAXPATH, fp) != NULL) {
s = buf3;
s[strlen(s) - 1] = 0;
slp_add(&ilist, s);
}
fclose(fp);
/* read new raw cfront information */
readcfout(tout, &ilist);
progress("read raw cfront information", (char*)0, (char*)0);
/* read old map file */
sprintf(fbuf, "%s/%s", rep, nmap);
readtf(fbuf, 1);
progress("read old map file", (char*)0, (char*)0);
/* make list of unique filenames in new map file */
p = maph;
while (p != NULL) {
add(strip(p->file, sb1));
p = p->next;
}
progress("made list of unique filenames in new map file", (char*)0, (char*)0);
/* delete all entries from old map file that have a */
/* basename matching the current program name being compiled */
for (i = 0; i < TFTABSIZE2; i++) {
tfp = tftab[i];
while (tfp != NULL) {
for (j = 0; j < tfp->bns.n; j++) {
if (!STRCMP(progname, tfp->bns.ptrs[j]))
break;
}
if (j < tfp->bns.n) {
if (tfp->files.n == 1 &&
lookup(strip(tfp->files.ptrs[0], sb1)) != NULL) {
if (tfp->bns.n == 1) {
tfp->deleted = 1;
slp_del(&tfp->files);
slp_del(&tfp->bns);
}
else {
fs((char*)tfp->bns.ptrs[j]);
tfp->bns.ptrs[j] = tfp->bns.ptrs[tfp->bns.n - 1];
tfp->bns.n--;
}
}
}
tfp = tfp->next;
}
}
progress("deleted old map file entries", (char*)0, (char*)0);
/* add in new entries */
p = maph;
slp_adduniq(&tab, progname);
while (p != NULL) {
tfp = tftab[h = (int)hash(p->name, (long)TFTABSIZE2)];
flag = 0;
for (; tfp != NULL; tfp = tfp->next) {
/* skip entries with wrong names and @def entries */
if (strcmp(tfp->name, p->name) || tfp->type == 'F')
continue;
/* if a function template or > 1 header or */
/* header matches, then merge in */
if (p->rtype == 'f' || tfp->files.n != 1 ||
!strcmp(strip(tfp->files.ptrs[0], sb1),
strip(p->file, sb2))) {
tfp->deleted = 0;
slp_adduniq(&tfp->bns, progname);
strip(p->file, sb1);
for (i = 0; i < tfp->files.n; i++) {
strip(tfp->files.ptrs[i], sb2);
if (!strcmp(sb1, sb2)) {
fs((char*)tfp->files.ptrs[i]);
tfp->files.ptrs[i] = copy(p->file);
break;
}
}
if (i == tfp->files.n)
slp_adduniq(&tfp->files, p->file);
flag = 1;
}
if (flag)
break;
}
/* not previously seen; create new entry */
if (!flag) {
tfp = (Tfile*)(gs(sizeof(Tfile)));
tfp->name = copy(p->name);
tfp->files.n = 0;
tfp->bns.n = 0;
slp_add(&tfp->files, p->file);
slp_add(&tfp->bns, progname);
tfp->deleted = 0;
tfp->type = 'C';
tfp->next = tftab[h];
tftab[h] = tfp;
}
p = p->next;
}
progress("added in new map entries", (char*)0, (char*)0);
/* back up the defmap file */
signal_block(SIG_IGN);
sprintf(fbuf, "%s/%s", rep, nmap);
sprintf(fbuf2, "%s/%s.old", rep, nmap);
if (facc(fbuf) && mv(fbuf, fbuf2, rep, rep) < 0)
fatal("could not move file %s --> %s", fbuf, fbuf2);
/* write the new formatted file */
if ((fp = fopen(fbuf, "w")) == NULL)
fatal("cannot open map file %s for writing", fbuf, (char*)0);
/* string table */
fprintf(fp, "@tab\n");
for (i = 0; i < tab.n; i++)
fprintf(fp, "%s\n", tab.ptrs[i]);
fprintf(fp, "@etab\n");
/* individual type entries */
for (i = 0; i < TFTABSIZE2; i++) {
for (tfp = tftab[i]; tfp != NULL; tfp = tfp->next) {
if (tfp->deleted)
continue;
n = (tfp->type == 'F' ? "ef" : "ec");
fprintf(fp, "@d%s %s", n, tfp->name);
len = 5 + strlen(tfp->name);
for (j = 0; j < tfp->bns.n; j++) {
bn = bn_lookup(tfp->bns.ptrs[j]);
len2 = strlen(bn);
if (len + 1 + len2 > 75) {
len = strlen(bn) + 4;
fputs(" \\\n ", fp);
}
else {
putc(' ', fp);
len += 1 + len2;
}
fputs(bn, fp);
}
putc('\n', fp);
for (j = 0; j < tfp->files.n; j++) {
fputs(tfp->files.ptrs[j], fp);
putc('\n', fp);
}
}
}
fclose(fp);
progress("wrote new map file", (char*)0, (char*)0);
/* unlock repository */
if (lock_flag) {
unlock_rep(rep);
progress("unlocked repository", (char*)0, (char*)0);
}
progress2();
exit(0);
}
|