tmuck2.4/
tmuck2.4/admin/scripts/
tmuck2.4/docs/
tmuck2.4/minimal-db/
tmuck2.4/minimal-db/data/
tmuck2.4/minimal-db/logs/
tmuck2.4/minimal-db/muf/
tmuck2.4/old/
tmuck2.4/src/
tmuck2.4/src/compile/
tmuck2.4/src/editor/
tmuck2.4/src/game/
tmuck2.4/src/interface/
tmuck2.4/src/scripts/
tmuck2.4/src/utilprogs/
/* Copyright (c) 1992 by David Moore.  All rights reserved. */
/* typechk.c,v 2.6 1997/08/29 21:02:09 dmoore Exp */
#include "config.h"

#include "db.h"
#include "code.h"
#include "typechk.h"
#include "externs.h"

/* #### support for primitives taking a list input is not working. */

#ifdef __GNUC__
#define MUCK_INLINE __inline__
#else
#define MUCK_INLINE
#endif

static const char *typecheck_list(frame *fr, data_stack *st, const int **types, int *pos, int depth);

/* pos and types are based by reference so we can move them along as needed. */
MUCK_INLINE
static const char *typechk_arg(frame *fr, data_stack *st, const int **types, int *pos)
{
    inst *arg;
    int type;

#if 0
    /* now in check_prim_space in inst.c */
    if (*pos >= depth_stack(st, DATA_STACK_SIZE))
	return "Data stack underflow";
#endif

    arg = st->top + *pos;
    (*pos)++;

    type = **types;
    (*types)++;

    switch (type) {
    case INST_T_ANY:
	break;
    case INST_T_a:
	if (arg->type != INST_ADDRESS) return "Address expected";
	break;
    case INST_T_c:
	if (arg->type != INST_CONNECTION) return "Connection expected";
	break;
    case INST_T_n:
	if (arg->type != INST_INTEGER) return "Integer expected";
	break;
    case INST_T_N:
	if ((arg->type != INST_INTEGER) || (arg->un.integer <= 0))
	    return "Non-zero integer expected";
	break;
    case INST_T_o: 
	if (arg->type != INST_OBJECT) return "Dbref expected";
	break;
    case INST_T_O:
	if ((arg->type != INST_OBJECT) || Garbage(arg->un.object))
	    return "Valid dbref expected";
	break;
    case INST_T_Oh:
	if ((arg->type != INST_OBJECT) || ((arg->un.object != HOME)
					   && Garbage(arg->un.object)))
	    return "Valid dbref or HOME expected";
	break;
    case INST_T_P:
	if ((arg->type != INST_OBJECT) || Garbage(arg->un.object))
	    return "Valid dbref expected";
	if (!controls(frame_euid(fr), arg->un.object, frame_wizzed(fr)))
	    return "Permission denied";
	break;
    case INST_T_s:
	if (arg->type != INST_STRING) return "String expected";
	break;
    case INST_T_S:
	if ((arg->type != INST_STRING) || (arg->un.string == NULL))
	    return "Non-empty string expected";
	break;
    case INST_T_v:
	if (arg->type != INST_VARIABLE) return "Variable expected";
	break;
    case INST_T_LIST:
        if ((arg->type != INST_INTEGER) || (arg->un.integer < 0))
	    return "List expected";
        return typecheck_list(fr, st, types, pos, arg->un.integer);
    default:
        log_status("INTERP: Illegal type to typecheck_arg: (%i)", type);
	return "Fatal internal error.";
    }
    
    return NULL;
}


static const char *typecheck_list(frame *fr, data_stack *st, const int **types, int *pos, int depth)
{
    int i;
    const char *error = NULL;
    static Buffer buf;
    static Buffer buf2;

    /* #### i think this is broken.  it'll keep incrementing types when
       it should be keeping types fixed. */
    for (i = 0; i < depth; i++) {
        error = typechk_arg(fr, st, types, pos);
	if (error) break;
    }
	    
    if (error) {
        /* Have it work right for lists w/in lists, etc. */
        Bufsprint(&buf2, "Bad arg (%i) in list: %s", i, error);
	Bufcpy(&buf, Buftext(&buf2));
	return Buftext(&buf);
    }

    return NULL;
}


/* Return the total number of items being popped. */
int typechk_stack(frame *fr, data_stack *st, const int prim, const int total_args, const int *types)
{
    int curr_arg;
    int pos;
    const char *error = NULL;

    pos = 0;
    for (curr_arg = 1; curr_arg <= total_args; curr_arg++) {
	error = typechk_arg(fr, st, &types, &pos);
	if (error) break;
    }

    if (error) {
	interp_error(fr, prim, "Bad arg (%i): %s", curr_arg, error);
	return -1;
    }

    return pos;
}