/*                             -*- Mode: Elec-C -*- 
 * toglclr.c -- utility to toggle the program load flags in the .prg header.
 *
 *              usage: toglclr [options] file file ...
 * 
 * Author          : J.R. Bammi, modified by F. Ridderbusch
 * Created On      : Some time ago.
 * Last Modified By: J.R. Bammi
 * Last Modified On: Fri Sep 25 12:00:28 1992
 * Update Count    : 6
 * Status          : Unknown, Use with caution!
 */

/* HISTORY 
 * 25-Sep-1992          ++jrb
 *    Added support for cross-environment with support for 
 *    WORD_ALIGNED hosts.
 *
 * 13-Sep-1992		Frank Ridderbusch	
 *    This program was originally written by J.R. Bammi
 *    (bammi@cadence.com) to toggle the clear TPA above BSS flag
 *    introduced with TOS 1.4. I extended it to also handle the additional
 *    program flags introduced with the TOS versions for the STE and TT.
 */

#include <stdio.h>
#include <stdlib.h>
#include <unixlib.h>
#include <string.h>
#include <st-out.h>

#ifndef FILENAME_MAX
#define FILENAME_MAX 1024
#endif

int flags_to_toggle = 0;

#ifdef WORD_ALIGNED

#define ckread(addr, bytes, fd) if(read(fd, addr, bytes) != bytes) return 1;
#define ckwrite(addr, bytes, fd) if(write(fd, addr, bytes) != bytes) return 1;

int readhead(h, fd)
struct aexec *h;
int fd;
{
    short i;
    long j;
    int k;
	
    ckread(&i, 2, fd);
    h->a_magic = i;
    ckread(&j, 4, fd);
    h->a_text = j;
    ckread(&j, 4, fd);
    h->a_data = j;
    ckread(&j, 4, fd);
    h->a_bss = j;
    ckread(&j, 4, fd);
    h->a_syms = j;
    ckread(&j, 4, fd);
    h->a_AZero1 = j;
    ckread(&j, 4, fd);
    h->a_ldflgs = j;
    ckread(&i, 2, fd);
    h->a_isreloc = i;

    return 0;
}

int writehead(h, fd)
struct aexec *h;
int fd;
{
    short i;
    long j;
    int k;
	
    i = h->a_magic;
    ckwrite(&i, 2, fd);
    j = h->a_text;
    ckwrite(&j, 4, fd);
    j = h->a_data;
    ckwrite(&j, 4, fd);
    j = h->a_bss;
    ckwrite(&j, 4, fd);
    j = h->a_syms;
    ckwrite(&j, 4, fd);
    j = h->a_AZero1;
    ckwrite(&j, 4, fd);
    j = h->a_ldflgs;
    ckwrite(&j, 4, fd);
    i = h->a_isreloc;
    ckwrite(&i, 2, fd);

    return 0;
}

#else

#define readhead(addr, fd) \
 (read(fd, addr, sizeof(struct aexec)) != sizeof(struct aexec))

#define writehead(addr, fd) \
 (write(fd, addr, sizeof(struct aexec)) != sizeof(struct aexec))

#endif /* WORD_ALIGNED */

int toggle (fd, fn)
int fd;
char *fn;
{
    struct aexec head;
    unsigned long t;
    char *ptr;
    
    if(readhead(&head, fd))
    {
	perror(fn);
	return 4;
    }
    if(head.a_magic != CMAGIC)
    {
	fprintf(stderr,"%s: Invalid magic number %x\n", fn, head.a_magic);
	return 8;
    }

    t = head.a_AZero2;
    if (flags_to_toggle)
    {
        head.a_AZero2 ^= flags_to_toggle;
        lseek(fd, 0L, SEEK_SET);
	if(writehead(&head, fd))
        {
	    perror(fn);
	    return 16;
        }
    }

    printf("%s:            `fast load' bit was %d is now %d\n", fn, 
	   (int)((t & F_FASTLOAD) == F_FASTLOAD),
	   (int)((head.a_AZero2 & F_FASTLOAD) == F_FASTLOAD));

    printf("%s:      `run in fast ram' bit was %d is now %d\n", fn, 
	   (int)((t & F_ALTLOAD) == F_ALTLOAD),
	   (int)((head.a_AZero2 & F_ALTLOAD) == F_ALTLOAD));

    printf("%s: `malloc from fast ram' bit was %d is now %d\n", fn, 
	   (int)((t & F_ALTALLOC) == F_ALTALLOC),
	   (int)((head.a_AZero2 & F_ALTALLOC) == F_ALTALLOC));

    return 0;
}

int main(argc, argv)
int argc;
char **argv;
{
    int fd;
    int status = 0;
    char fn[FILENAME_MAX];
    
    if(argc < 2)
    {
	fprintf(stderr, "usage: toglclr [options] file file .....\n\n");
	fprintf(stderr, "options: -fload = toggle `fast load' bit\n");
	fprintf(stderr, "         -frun  = toggle `load program into fast ram' bit\n");
	fprintf(stderr, "         -fram  = toggle `malloc from fast ram' bit\n\n");
	fprintf(stderr, "without options the current state is reported.\n");
	exit(1);
    }

    while (**++argv == '-')
    {
        if (!strcmp(*argv, "-fload"))
	    flags_to_toggle |= F_FASTLOAD;
        if (!strcmp(*argv, "-frun"))
	    flags_to_toggle |= F_ALTLOAD;
        if (!strcmp(*argv, "-fram"))
	    flags_to_toggle |= F_ALTALLOC;
	--argc;
    }

    while(--argc > 0)
    {
	(void) strcpy(fn, *argv++);
        if((fd = open(fn, 2)) < 0)
        {
	    perror(fn);
	    continue;
        }
	status |= toggle(fd, fn);
	if(close(fd))
	{
	    perror(fn);
	    exit(2);
	}
    }
    
    return status;
}
