/*
 *	strip TOS executable format files of symbol table info
 *	usage: strip files ...
 *
 *		++jrb	bammi@dsrgsun.ces.cwru.edu
 */
#ifdef atarist
#  include <unixlib.h>
#endif

#ifdef unix
#  include <strings.h>
#  define lwrite write
#  define lread  read
#else
#  include <string.h>
#endif

#include <fcntl.h>

#define NULL		((void *)0)
#define NEWBUFSIZ	16384L

char mybuf[NEWBUFSIZ];
char tmpname[128];

int main(argc, argv)
int argc;
char **argv;
{
    extern int strip(char *);
    extern void report(char *);
    int status = 0;
#ifdef atarist
    char *tmpdir;
    extern char *getenv(const char *);
#endif

    if(argc < 2)
    {
	report("Usage: strip files ...\r\n");
	return 1;
    }

#ifdef atarist
    tmpname[0] = '\0';
    if((tmpdir = getenv("TEMP")) != NULL)
    {
	register int l;
	strcpy(tmpname, tmpdir);
	if(tmpname[(l = ((int)strlen(tmpname) - 1))] == '\\')
	    tmpname[l] = '\0';
    }
    strcat(tmpname, "\\STXXXXXX");
#else
    strcpy(tmpname,"/tmp/STXXXXXX");
#endif

    mktemp(tmpname);
   
    while(--argc > 0)
	status |= strip(*++argv);

    unlink(tmpname);
    return status;
}

#include <st-out.h>
int strip (char *name)
{
    register int fd;
    register int tfd;
    register long count, sbytes, rbytes;
    struct aexec ahead;
    extern long copy(int, int, long);
    extern void report(char *);
    
    if((fd = open(name, O_RDONLY)) < 0)
    {
	perror(name); return 2;
    }
    if((tfd = open(tmpname, O_WRONLY | O_TRUNC | O_CREAT, 0644)) < 0)
    {
	perror(tmpname); close(fd); return 4;
    }
    if((count = lread(fd, &ahead, sizeof(ahead))) != sizeof(ahead))
    {
	perror(name);
	close(tfd); close(fd); return 8;
    }
    if(A_BADMAG(ahead))
    {
	report(name); report(": Bad Magic number\r\n");
	close(tfd); close(fd); return 16;
    }
    if((sbytes = ahead.a_syms) == 0)
    {
	report(name); report(": Already Stripped\r\n");
	close(tfd); close(fd); return 4096;
    }
    ahead.a_syms = 0L;
    if((count = lwrite(tfd, &ahead, sizeof(ahead))) != sizeof(ahead))
    {
	perror(tmpname);
	close(tfd); close(fd); return 32;
    }
    count = ahead.a_text + ahead.a_data;
    if(copy(fd, tfd, count) != count)
    {
	close(tfd); close(fd); return 64;
    }
    if(lseek(fd, sbytes , 1) < 0)
    {
	report(name); report(": seek error\r\n");
	close(tfd); close(fd); return 128;
    }
    if((rbytes = copy(fd, tfd, 0x7fffffffL)) < 0)
    {
	close(tfd); close(fd); return 256;
    }
    close(tfd); close(fd);
    if((fd = open(name, O_WRONLY | O_TRUNC)) < 0)
    {
	perror(name); return 512;
    }
    if((tfd = open(tmpname, O_RDONLY)) < 0)
    {
	perror(tmpname); close(fd); return 1024;
    }
    
    count = sizeof(ahead) + ahead.a_text + ahead.a_data + rbytes;
    if(copy(tfd, fd, count) != count)
    {
	close(tfd); close(fd); return 2048;
    }
    close(tfd); close(fd);
    return 0;
}

/*
 * copy from, to in NEWBUFSIZ chunks upto bytes or EOF whichever occurs first
 * returns # of bytes copied
 */
long copy(int from, int to, long bytes)
{
    register long todo, done = 0L, remaining = bytes, actual;
    extern void report(char *);

    while(done != bytes)
    {
	todo = (remaining > NEWBUFSIZ)? NEWBUFSIZ : remaining;
	if((actual = lread(from, mybuf, todo)) != todo)
	{
	    if(actual < 0)
	    {
		report("Error Reading\r\n");  return -done;
	    }
	}
	if(lwrite(to, mybuf, actual) != actual)
	{
	    report("Error Writing\r\n"); return -done;
	}
        done += actual;
	if(actual != todo) /* eof reached */
		return done;
	remaining -= actual;
    }
    return done;
}

void report(char *s)
{
	lwrite(2, s, (long)strlen(s));
}
