/*      @(#)/usr/src/cmd/make/files.c   3.4     */

#include "defs"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/dir.h>
#include <pwd.h>
#include <ar.h>
#include <a.out.h>
/* UNIX DEPENDENT PROCEDURES */


char archmem[16];
char archname[64];              /* name of archive library */


TIMETYPE exists(pname)
NAMEBLOCK pname;
{
        register CHARSTAR s;
        struct stat buf;
        TIMETYPE lookarch();
        CHARSTAR filename;

        filename = pname->namep;

        if(any(filename, LPAREN))
                return(lookarch(filename));

        if(stat(filename,&buf) < 0) 
        {
                s = findfl(filename);
                if(s != (CHARSTAR )-1)
                {
                        pname->alias = copys(s);
                        if(stat(pname->alias, &buf) == 0)
                                return(buf.st_mtime);
                }
                return(0);
        }
        else
                return(buf.st_mtime);
}


TIMETYPE prestime()
{
        TIMETYPE t;
        time(&t);
        return(t);
}



FSTATIC char n15[15];
FSTATIC CHARSTAR n15end = &n15[14];



DEPBLOCK srchdir(pat, mkchain, nextdbl)
register CHARSTAR pat;          /* pattern to be matched in directory */
int mkchain;                    /* nonzero if results to be remembered */
DEPBLOCK nextdbl;               /* final value for chain */
{
        FILE * dirf;
        int i, nread;
        CHARSTAR dirname, dirpref, endir, filepat, p;
        char temp[100];
        char fullname[100];
        CHARSTAR p1, p2;
        NAMEBLOCK q;
        DEPBLOCK thisdbl;
        OPENDIR od;
        int dirofl = 0;
        static opendirs = 0;
        PATTERN patp;

        struct direct entry[32];


        thisdbl = 0;

        if(mkchain == NO)
                for(patp=firstpat ; patp!=0 ; patp = patp->nextpattern)
                        if(equal(pat,patp->patval))
                                return(0);

        patp = ALLOC(pattern);
        patp->nextpattern = firstpat;
        firstpat = patp;
        patp->patval = copys(pat);

        endir = 0;

        for(p=pat; *p!=CNULL; ++p)
                if(*p==SLASH)
                        endir = p;

        if(endir==0)
        {
                dirname = ".";
                dirpref = "";
                filepat = pat;
        }
        else
        {
                *endir = CNULL;
                dirpref = concat(pat, "/", temp);
                filepat = endir+1;
                dirname = temp;
        }

        dirf = NULL;

        for(od=firstod ; od!=0; od = od->nextopendir)
                if(equal(dirname, od->dirn))
                {
                        dirf = od->dirfc;
                        fseek(dirf,0L,0); /* start over at the beginning  */
                        break;
                }

        if(dirf == NULL)
        {
                dirf = fopen(dirname, "r");
                if(++opendirs < MAXODIR)
                {
                        od = ALLOC(opendir);
                        od->nextopendir = firstod;
                        firstod = od;
                        od->dirfc = dirf;
                        od->dirn = copys(dirname);
                }
                else
                        dirofl = 1;
        }

        if(dirf == NULL)
        {
                fprintf(stderr, "Directory %s: ", dirname);
                fatal("Cannot open");
        }

        else    do
                {
                        nread = fread(entry,sizeof(entry[0]),32,dirf) ;
                        for(i=0; i<nread; ++i)
                                if(entry[i].d_ino!= 0)
                                {
                                        p1 = entry[i].d_name;
                                        p2 = n15;
                                        while( (p2<n15end) &&
                                          (*p2++ = *p1++)!=CNULL );
                                        if( amatch(n15,filepat) )
                                        {
                                                concat(dirpref,n15,fullname);
                                                if( (q=srchname(fullname)) ==0)
                                                        q = makename(copys(fullname));
                                                if(mkchain)
                                                {
                                                        thisdbl = ALLOC(depblock);
                                                        thisdbl->nextdep = nextdbl;
                                                        thisdbl->depname = q;
                                                        nextdbl = thisdbl;
                                                }
                                        }
                                }
                } while(nread==32);

        if(endir != 0)
                *endir = SLASH;
        if(dirofl)
                fclose(dirf);

        return(thisdbl);
}

/* stolen from glob through find */

amatch(s, p)
CHARSTAR s, p;
{
        register int cc, scc, k;
        int c, lc;

        scc = *s;
        lc = 077777;
        switch (c = *p)
        {

        case LSQUAR:
                k = 0;
                while (cc = *++p)
                {
                        switch (cc)
                        {

                        case RSQUAR:
                                if (k)
                                        return(amatch(++s, ++p));
                                else
                                        return(0);

                        case MINUS:
                                k |= lc <= scc & scc <= (cc=p[1]);
                        }
                        if(scc==(lc=cc))
                                k++;
                }
                return(0);

        case QUESTN:
        caseq:
                if(scc)
                        return(amatch(++s, ++p));
                return(0);
        case STAR:
                return(umatch(s, ++p));
        case 0:
                return(!scc);
        }
        if(c==scc)
                goto caseq;
        return(0);
}

umatch(s, p)
register CHARSTAR s, p;
{
        if(*p==0)
                return(1);
        while(*s)
                if(amatch(s++,p))
                        return(1);
        return(0);
}

#ifdef METERFILE
int meteron 0;  /* default: metering off */

meter(file)
CHARSTAR file;
{
        TIMETYPE tvec;
        CHARSTAR p, ctime();
        FILE * mout;
        struct passwd *pwd, *getpwuid();

        if(file==0 || meteron==0)
                return;

        pwd = getpwuid(getuid());

        time(&tvec);

        if( (mout=fopen(file,"a")) != NULL )
        {
                p = ctime(&tvec);
                p[16] = CNULL;
                fprintf(mout,"User %s, %s\n",pwd->pw_name,p+4);
                fclose(mout);
        }
}
#endif


/* look inside archives for notations a(b) and a((b))
        a(b)    is file member   b   in archive a
        a((b))  is entry point  _b  in object archive a
*/

static struct ar_hdr arhead;
FILE *arfd;
long int arpos, arlen;

static struct exec objhead;

static struct nlist objentry;


TIMETYPE lookarch(filename)
register CHARSTAR filename;
{
        register int i;
        CHARSTAR p, q, send;
        char s[15];
        int nc, nsym, objarch;

        for(p = filename; *p!= LPAREN ; ++p);
        q = p++;

        if(*p == LPAREN)
        {
                objarch = YES;
                nc = 8;
                ++p;
        }
        else
        {
                objarch = NO;
                nc = 14;
                for(i = 0; i < 14; i++)
                {
                        if(p[i] == RPAREN)
                        {
                                i--;
                                break;
                        }
                        archmem[i] = p[i];
                }
                archmem[++i] = 0;
                if(archmem[0] == CNULL)
                        fatal1("Null archive member name `%s'", filename);
        }
        *q = CNULL;
        copstr(archname, filename);
        if(archname[0] == CNULL)
                fatal1("Null archive name `%s'", archmem);
        i = openarch(filename);
        *q = LPAREN;
        if(i == -1)
                return(0);
        send = s + nc;

        for( q = s ; q<send && *p!=CNULL && *p!=RPAREN ; *q++ = *p++ );

        while(q < send)
                *q++ = CNULL;
        while(getarch())
        {
                if(objarch)
                {
                        getobj();
                        nsym = objhead.a_syms / sizeof(objentry);
                        for(i = 0; i<nsym ; ++i)
                        {
                                fread(&objentry, sizeof(objentry),1,arfd);
                                if( (objentry.n_type & N_EXT)
                                   && eqstr(objentry.n_name,s,nc))
                                {
                                        for(i = 0; i < 14; i++)
                                                archmem[i] = arhead.ar_name[i];
                                        archmem[++i] = 0;
        out:
                                        clarch();
                                        return(arhead.ar_date);
                                }
                        }
                }

                else if( eqstr(arhead.ar_name, s, nc))
                        goto out;
        }

        clarch();
        return( 0L);
}


clarch()
{
        fclose( arfd );
}


openarch(f)
register CHARSTAR f;
{
        int word = 0;
        struct stat buf;

        if(stat(f, &buf) == -1)
                return(-1);
        arlen = buf.st_size;

        arfd = fopen(f, "r");
        if(arfd == NULL)
                return(-1);
        fread(&word, sizeof(word), 1, arfd);
        if(word != ARMAG)
                fatal1("%s is not an archive", f);
/*
 *      trick getarch() into jumping to the first archive member.
 */
        arpos = sizeof(word);
        arhead.ar_size = -(int)sizeof(arhead);
        return(0);
}



getarch()
{
        arpos += sizeof(arhead);
        arpos += (arhead.ar_size + 1 ) & ~1L;
        if(arpos >= arlen)
                return(0);
        fseek(arfd, arpos, 0);
        fread(&arhead, sizeof(arhead), 1, arfd);
        return(1);
}


getobj()
{
        long int skip;

        fread(&objhead, sizeof(objhead), 1, arfd);
/*
        if( objhead.a_magic != A_MAGIC1 &&
            objhead.a_magic != A_MAGIC2 &&
            objhead.a_magic != A_MAGIC3 )
                        fatal1("%s is not an object module", arhead.ar_name);
*/
        skip = objhead.a_text + objhead.a_data;
#if vax || u370
        skip += objhead.a_trsize + objhead.a_drsize;
#else
        if(! objhead.a_flag )
                skip *= 2;
#endif
        fseek(arfd, skip, 1);
}


eqstr(a,b,n)
register CHARSTAR a, b;
register int n;
{
        register int i;
        for(i = 0 ; i < n ; ++i)
                if(*a++ != *b++)
                        return(NO);
        return(YES);
}
/*
 *      Used when unlinking files. If file cannot be stat'ed or it is
 *      a directory, then do not remove it.
 */
isdir(p)
char *p;
{
        struct stat statbuf;

        if(stat(p, &statbuf) == -1)
                return(1);              /* no stat, no remove */
        if((statbuf.st_mode&S_IFMT) == S_IFDIR)
                return(1);
        return(0);
}
