#include <ctype.h>
#include "detar.h"
#include <time.h>

#define isodigit(x) (isdigit(x) && ((x)<'8'))

void tooct();
extern int verbos, xtract;

void bcopy(src,dest,n)char *src,*dest;int n;
{
    while(n--)
        *dest++ = *src++;
}

void lcopy(src,dest,n)long *src,*dest;int n;
{
    while(n--)
        *dest++ = *src++;
}

long from_oct(digs,where)int digs;char *where;
{
    long ans=0;

    while(isspace(*where) && digs)
        digs--,where++;
    if(!digs) return 0L;

    while(isodigit(*where) && digs)
    {
        ans = ans *8 +(*where++ - '0');
        digs--;
    }
    return ans;
}

int chec_chksum(tar_rec) union record *tar_rec;
{
    long sum,recsum;
    int i;
    char *p;

    p=tar_rec->charptr;
    recsum=from_oct(8,tar_rec->header.chksum);
    sum=0L;
    for(i=sizeof(*tar_rec);--i>=0;)
        sum = sum + (*p++ & 0xff);
    for(i=sizeof(tar_rec->header.chksum);--i>=0;)
        sum = sum - (0xff & tar_rec->header.chksum[i]);
    sum = sum +' '*sizeof(tar_rec->header.chksum);
    if(sum==recsum) return 1;
    if(sum==8*' ') return 2;
    return 0;
}

void Makedirs(name)char *name;
{
    struct stat stbuf;
    char *p,*q,*index();
    int makeit;

    p=name;
    while(q=index(p,'\\'))
    {
        *q='\0';
        makeit=0;
        if(stat(name,&stbuf))
            makeit=1;
        else if((stbuf.st_mode & S_IFMT) != S_IFDIR)        
            makeit=1;
        if(makeit && xtract)
            mkdir(name);
        *q='\\';
        p=q+1;
    }
}

void bzero(p,n)char *p;int n;
{
    while(n--)
        *p++='\0';
}

void lzero(p,n)long *p;int n;
{
    while(n--)
        *p++=0L;
}

void
calc_chksum(header)
    register union record *header;
{
    register int    i, sum;
    register char   *p;

    bcopy(CHKBLANKS, header->header.chksum, sizeof(header->header.chksum));

    sum = 0;
    p = header->charptr;
    for (i = sizeof(*header); --i >= 0; )
    {
        /*
         * We can't use unsigned char here because of old compilers,
         * e.g. V7.
         */
        sum += 0xFF & *p++;
    }

    /*
     * Fill in the checksum field.  It's formatted differently
     * from the other fields:  it has [6] digits, a null, then a
     * space -- rather than digits, a space, then a null.
     * We use tooct then write the null in over tooct's space.
     * The final space is already there, from checksumming, and
     * tooct doesn't modify it.
     *
     * This is a fast way to do:
     * (void) sprintf(header->header.chksum, "%6o", sum);
     */
    tooct((long) sum,   8,  header->header.chksum);
    header->header.chksum[6] = '\0';    /* Zap the space */
}

void
tooct(value, digs, where)
    register long   value;
    register int    digs;
    register char   *where;
{
    
    --digs;             /* Trailing null slot is left alone */
    where[--digs] = ' ';        /* Put in the space, though */

    /* Produce the digits -- at least one */
    do {
        where[--digs] = '0' + (char)(value & 7); /* one octal digit */
        value >>= 3;
    } while (digs > 0 && value != 0);

    /* Leading spaces, if necessary */
    while (digs > 0)
        where[--digs] = ' ';
}

char *tounix(name)
register char *name;
{
    static char punix[100];
    register char *p;
    
    bzero(punix,100);
    for(p=punix;*name;name++,p++)
        switch(*name)
        {
        case '\\':
            *p='/';
            break;
        default:
            if(*name >= 'A' && *name <= 'Z') *p = *name | '\40';
	    else *p = *name;
            break;
        }
    return punix;
}

extern char *rindex(),*index();

static char *do_one(s)char *s;
{
    static char work[16];
    char *p,*q;

    bzero(work,16);

    if(p=rindex(s,'.'))
    {
        *p='\0';
        strncpy(work,s,8);
        for(q=work;*q;q++)
            if(*q=='.') *q='_';
        *p='.';
        strncat(work,p,4);
    }else
        strncpy(work,s,8);
    return work;
}

char *to_gem(punix)
char *punix;
{
    static char gem[100];
    char *p,*q;

    bzero(gem,100);
    p=punix;
    while(q=index(p,'/'))
    {
        *q='\0';
        strcat(gem,do_one(p));
        strcat(gem,"\\");
        *q='/';
        p=q+1;
    }
    strcat(gem,do_one(p));
}

ptime(raw)
long raw;
{
    char tstr[48];
    extern char *ctime();

    sprintf(tstr, "%s", ctime(&raw));
    tstr[strlen(tstr)-1] = '\0';
    printf("%s", tstr);
}

vtype(mode, fsize, mtime, name)
int mode;
long fsize, mtime;
char *name;
{
    if(verbos)
    {
	if(mode & 0x100) putchar('r');
	else putchar('-');
	if(mode & 0x80) putchar('w');
	else putchar('-');
	if(mode & 0x40) putchar('x');
	else putchar('-');
	if(mode & 0x20) putchar('r');
	else putchar('-');
	if(mode & 0x10) putchar('w');
	else putchar('-');
	if(mode & 0x08) putchar('x');
	else putchar('-');
	if(mode & 0x04) putchar('r');
	else putchar('-');
	if(mode & 0x02) putchar('w');
	else putchar('-');
	if(mode & 0x01) putchar('x');
	else putchar('-');

        printf(" %7ld  ", fsize);

	ptime(mtime);
    }
    printf("  %s\n", name);
}

char *lcase(name)
register char *name;
{
    static char punix[100];
    register char *p;
    
    bzero(punix,100);
    for(p=punix;*name;name++,p++)
    {
        if(*name >= 'A' && *name <= 'Z') *p = *name | '\100';
	else *p = *name;
    }
    return punix;
}
