/* transmap - examine a keymap or copy part of one into another
 * by Steven Reiz 1/5/89
 * usage to examine a map: transmap keymapfile
 * usage to transfer a map: transmap frommapfile intomapfile
 */


#define INMAP 9
struct {
    char  *name;
    short offset;
    short size;
} map[2][INMAP];
short wread();
typedef int file;
#define O_RDONLY 0
file in, out, open(), creat();  /* to read the source keymap and write dest */
char *memout, *malloc();        /* outfile is stored in memory to change it */
int outsize;                    /* size of outfile in bytes */
long lseek();
short word;                     /* to read() words from the file */
#define HUNK_OFS 0x1a           /* ofset in file where code hunk starts */
#define MAP_OFS  0x20           /* ofset in file where code hunk body starts */

main(argc, argv)
int argc;
char **argv; {

    map[0][0].name=map[1][0].name="name";
    map[0][1].name=map[1][1].name="LoKeyMapTypes";
    map[0][2].name=map[1][2].name="LoKeyMap";
    map[0][3].name=map[1][3].name="LoCapsable";
    map[0][4].name=map[1][4].name="LoRepeatable";
    map[0][5].name=map[1][5].name="HiKeyMapTypes";
    map[0][6].name=map[1][6].name="HiKeyMap";
    map[0][7].name=map[1][7].name="HiCapsable";
    map[0][8].name=map[1][8].name="HiRepeatable";

    if (argc<2 || argc>3) {
        usage();
        exit(20);
    }
    if ((in=open(argv[1], O_RDONLY))<0) {
        printf("%s: couldn't open %s\n", argv[0], argv[1]);
        exit(20);
    }
    mapstat(in, 0); /* read the sizes of the in map into map[0] */
    if (argc==2) {
        close(in);
        showmap(0);
        exit(0);
    }
    if ((out=open(argv[2], O_RDONLY))<0) {
        printf("%s: couldn't open %s\n", argv[0], argv[2]);
        exit(20);
    }
    outsize=lseek(out, 0L, 2);
    lseek(out, 0L, 0);
    if (!(memout=malloc(outsize))) {
        printf("%s: couldn't malloc a lousy %d bytes !\n", argv[0], outsize);
        exit(20);
    }
    if (read(out, memout, outsize)!=outsize) {
        printf("%s: io error reading %s\n", argv[0], argv[2]);
        exit(20);
    }
    mapstat(out, 1);
    close(out);
    transplant(in, 0, 1, 1);
    transplant(in, 0, 1, 2);
    transplant(in, 0, 1, 3);
    transplant(in, 0, 1, 4);
    close(in);
    if ((out=creat(argv[2], 0700))<0) {
        printf("%s: couldn't creat %s\n", argv[0], argv[2]);
        exit(20);
    }
    if (write(out, memout, outsize)!=outsize) {
        printf("%s: io error writing %s\n", argv[0], argv[2]);
        exit(20);
    }
    close(out);
    free(memout);
}


/* usage prints a description of this
 * program
 */
usage() {
    printf("transmap - examine a keymap or copy part of one into another\n");
    printf("by Steven Reiz 1/5/89\n");
    printf("usage to examine a map: transmap keymapfile\n");
    printf("usage to transfer a map: transmap frommapfile intomapfile\n");
}


/* wread reads a short from fd and
 * returns it
 */
short wread(fd)
file fd; {
    short tmp;

    if (read(fd, &tmp, sizeof(tmp))!=sizeof(tmp)) {
        printf("wread: unexpected eof\n");
        exit(20);
    }
    return tmp;
}


/* mapstat reads in and computes it's mapsizes,
 * putting them in map[nr]
 */
mapstat(in, nr)
file in;
int nr; {
    int i, j, tmp, size;

    lseek(in, (long)HUNK_OFS, 0);
    if (wread(in)!=0x3e9) {
        printf("this is not a keymap file\n");
        exit(20);
    }
    wread(in);
    size=wread(in)*4;           /* read keymap size */
    lseek(in, (long)MAP_OFS+10, 0);
    for (i=0; i<INMAP; ++i) {
        wread(in);
        map[nr][i].offset=wread(in);
        map[nr][i].size=20000;
    }
    for (i=0; i<INMAP; ++i)         /* computing sizes of map parts */
        for (j=0; j<INMAP; ++j) {
            tmp=map[nr][j].offset-map[nr][i].offset;
            if (tmp>0 && tmp<map[nr][i].size)
                map[nr][i].size=tmp;
        }
    for (i=0; i<INMAP; ++i)         /* adjusting the last part */
        if (map[nr][i].size==20000)
            map[nr][i].size=size-map[nr][i].offset;
}


/* showmap shows map[nr]'s sizes
 */
showmap(nr)
int nr; {
    int i;

    printf("name          offset size\n");
    for (i=0; i<INMAP; ++i)
        printf("%-13s %6d %4d\n", map[nr][i].name,
         map[nr][i].offset, map[nr][i].size);
}


/* transplant takes part nr from file fd
 * according to map[from] and puts it
 * into memout according to map[to]
 */
transplant(fd, from, to, nr) {

    if (map[from][nr].size!=map[to][nr].size) {
        printf("sorry, map sizes for part %d didn't match (%d vs. %d)\n",
         nr, map[from][nr].size, map[to][nr].size);
        exit(20);
    }
    lseek(fd, (long)(MAP_OFS+map[from][nr].offset), 0);
    if (read(fd, (long)memout+MAP_OFS+map[to][nr].offset,
     map[from][nr].size)!=map[from][nr].size) {
        printf("transplant: read error\n");
        exit(20);
    }
}
