root/usr/src/cmd/adbgen/common/adbsub.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright (c) 1983-1998 by Sun Microsystems, Inc.
 * All rights reserved.
 */

/*
 * Subroutines to be called by adbgen2.c, the C program generated
 * by adbgen1.c.
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>

off_t last_off;
int warnings = 1;
int warns = 0;

/*
 * User claims offset is ok.
 * This usually follows call to another script, which we cannot handle.
 */
void
offsetok(void)
{
        last_off = -1;
}

/*
 * Get adb.s dot to the right offset.
 */
void
offset(off_t off)
{
        off_t off_diff;

        if (last_off == -1) {
                last_off = off;
                return;
        }
        off_diff = off - last_off;
        if (off_diff) {
                if (off_diff > 0) {
                        if (off_diff > 1) {
                                printf("%ld", off_diff);
                        }
                        printf("+");
                }
                if (off_diff < 0) {
                        if (off_diff < -1) {
                                printf("%ld", -off_diff);
                        }
                        printf("-");
                }
        }
        last_off = off;
}

/*
 * Emit the format command, return the size.
 */
int
do_fmt(char *acp)
{
        int rcount, width, sum, i;
        char *cp;

        cp = acp;
        sum = rcount = 0;
        do {
                while (*cp >= '0' && *cp <= '9') {
                        rcount = rcount * 10 + *cp++ - '0';
                }
                if (rcount == 0) {
                        rcount = 1;
                }
                switch (*cp) {
                case 'e':
                case 'E':
                case 'F':
                case 'g':
                case 'G':
                case 'J':
                        width = 8;
                        break;
                case 'K':
#ifdef  _LP64
                        width = 8;
#else   /* _LP64 */
                        width = 4;
#endif  /* _LP64 */
                        break;
                case 'X':
                case 'O':
                case 'Q':
                case 'D':
                case 'U':
                case 'f':
                case 'Y':
                case 'p':
                case 'P':
                        width = 4;
                        break;
                case 'x':
                case 'o':
                case 'q':
                case 'd':
                case 'u':
                        width = 2;
                        break;
                case 'v':
                case 'V':
                case 'b':
                case 'B':
                case 'c':
                case 'C':
                case '+':
                        width = 1;
                        break;
                case 'I':
                case 'a':
                case 'A':
                case 't':
                case 'r':
                case 'n':
                        width = 0;
                        break;
                case '-':
                        width = -1;
                        break;
                case 's':
                case 'S':
                case 'i':
                        if (warnings) {
                                fprintf(stderr,
                                "Unknown format size \"%s\", assuming zero\n",
                                acp);
                                warns++;
                        }
                        width = 0;
                        break;
                default:
                        fprintf(stderr, "Unknown format size: %s\n", acp);
                        exit(1);
                }
                for (i = 0; i < rcount; i++) {
                        putchar(*cp);
                }
                cp++;
                sum += width * rcount;
        } while (*cp);
        return (sum);
}

/*
 * Format struct member, checking size.
 */
void
format(char *name, size_t size, char *fmt)
{
        int fs;

        fs = do_fmt(fmt);
        if (fs != size && warnings) {
                fprintf(stderr,
                        "warning: \"%s\" size is %ld, \"%s\" width is %d\n",
                        name, size, fmt, fs);
                warns++;
        }
        last_off += fs;
}

/*
 * Get the value at offset based on base.
 */
void
indirect(off_t offset, size_t size, char *base, char *member)
{
        if (size == 8 || size == 4) {
                if (offset == 0) {
                        printf("*%s", base);
                } else {
                        printf("*(%s+0t%ld)", base, offset);
                }
        } else if (size == 2) {
                if (offset == 2) {
                        printf("(*%s&0xffff)", base);
                } else {
                        printf("(*(%s+0t%ld)&0xffff)", base, offset - 2);
                }
        } else if (size == 1) {
                if (offset == 3) {
                        printf("(*%s&0xff)", base);
                } else {
                        if ((offset & 0x1) == 0x1) {
                                printf("(*(%s+0t%ld)&0xff)", base, offset - 3);
                        } else {
                                printf("((*(%s+0t%ld)&0xff00)/0x100)",
                                    base, offset - 2);
                        }
                }
        } else {
                fprintf(stderr, "Indirect size %ld not 1, 2, or 4: %s\n",
                    size, member);
                exit(1);
        }
}