/*
 * Module:      msymbol.c
 * Author:      Mark I. Himelstein, Himelsoft, Inc.
 * Purpose:     returns values for miscellanious queries on MIPS COFF
 *              symbol table
 */


#include "conv.h"

extern int verbose;

extern data
get_compiler_version(
        arg_s           *parg,          /* arg entry causing call */
        callinfo_s      *pinfo,         /* info we need to pass around */
        long            *plength)       /* for varying length fields */
{
    /* return symbol's value field
     */
    static char buffer[1024];

    parg;

    sprintf(buffer, "MIPS %d.%d", (pinfo->pconv->paoutheader->MajorLinkerVersion),
        (pinfo->pconv->paoutheader->MinorLinkerVersion));
    *plength = strlen(buffer);
    return (data)buffer;
} /* get_compiler_version */


extern data
get_block_length(
        arg_s           *parg,          /* arg entry causing call */
        callinfo_s      *pinfo,         /* info we need to pass around */
        long            *plength)       /* for varying length fields */
{
    /* return size of a nested block of text in bytes
     */
    pSYMR       psymend;

    parg;
    plength;

    if (pinfo->psym->st != stBlock || pinfo->psym->sc != scText ||
        pinfo->psym->index == 0 || pinfo->psym->index == indexNil) {
        fatal("tried to get block length on inappropriate symbol\n");
    } /* if */

    /* get pointer to end symbol and subtract value from current symbol */
    psymend = isym_to_psym(pinfo, pinfo->psym->index-1);
    return (data)(psymend->value - pinfo->psym->value);

} /* get_block_length */


extern data
get_cv_symbol_type(
        arg_s           *parg,          /* arg entry causing call */
        callinfo_s      *pinfo,         /* info we need to pass around */
        long            *plength)       /* for varying length fields */
{
    parg;
    plength;

    return pinfo->psymmap->sym;
} /* get_cv_symbol_type */


extern data
get_arg_type(
        arg_s           *parg,          /* arg entry causing call */
        callinfo_s      *pinfo,         /* info we need to pass around */
        long            *plength)       /* for varying length fields */
{
    /* use this instead of get_type so we can use the type for both
     *  the list_member and the arg symbol.
     */
    unsigned long       arg_type_index;
    callinfo_s          info;

    arg_type_index = get_type(parg,  pinfo, plength);
    info = *pinfo;
    /* next line sets us up to dump things into the type buffer with info */
    list_member(parg, &info, plength);
    VERBOSE_TOTAL(info.buf);
    VERBOSE_PRINTF("arg type index = ");
    buffer_put_value(info.buf, arg_type_index, CV_TYPE_SIZE, NO_VLENGTH);
    VERBOSE_POP_INDENT();
    return arg_type_index;
} /* get_arg_type */


extern data
get_length_dummy(
        arg_s           *parg,          /* arg entry causing call */
        callinfo_s      *pinfo,         /* info we need to pass around */
        long            *plength)       /* for varying length fields */
{
    parg;
    plength;

    /* hold onto pointer to fill later */
    pinfo->plength = (unsigned short *)buffer_ptr(pinfo->buf);
    return 0;
} /* get_cv_symbol_type */


extern data
force_ignore_matching_end(
        arg_s           *parg,          /* arg entry causing call */
        callinfo_s      *pinfo,         /* info we need to pass around */
        long            *plength)       /* for varying length fields */
{
    /* dummy arg which just causes this routine to be executed
     *  which will force the matching end for this block,file, etc to
     *  be set to ignore.
     */
    pSYMR       psym;

    parg;
    plength;

    switch (pinfo->psym->st) {
    case stFile:
    case stBlock:
        if (pinfo->psym->index == indexNil)
            return 0;
        psym = isym_to_psym(pinfo, pinfo->psym->index-1);
        if (psym->st != stEnd) {
            fatal("expected end symbol\n");
        } /* if */
        psym->st = stIgnore;
        return 0;

    default:
        fatal("force_ignore_matching_end: unexpected symbol type(%d)\n",
                psym->st);
    } /* switch */
} /* force_ignore_matching_end */


extern void
put_numeric (
        char            *name,          /* name for verbose output */
        struct buffer_s *buf,           /* buffer to output to */
        unsigned long   value)          /* numeric value to output */
{
    if (value <  LF_NUMERIC) {
        VERBOSE_TOTAL(buf);
        VERBOSE_PRINTF("%s numeric = ", name);
        buffer_put_value(buf, value, CV_SMALL_NUMERIC_SIZE, NO_VLENGTH);
    } else {
        VERBOSE_TOTAL(buf);
        VERBOSE_PRINTF("%s ulong tag = ", name);
        buffer_put_value(buf,LF_ULONG,CV_SMALL_NUMERIC_SIZE, NO_VLENGTH);
        VERBOSE_TOTAL(buf);
        VERBOSE_PRINTF("%s ulong numeric = ", name);
        buffer_put_value(buf, value, CV_ULONG_NUMERIC_SIZE, NO_VLENGTH);
    } /* if */
//printf("%lx [0x%08x] %s (value %lx)\n", buf, buffer_total(buf), name, value);
} /* put_numeric */