Beispiel #1
0
/*-------------------------------------------------------------------------*/
void
struct_free_name (struct_name_t *pSName)

/* Free the struct name object <pSName> and all referenced data.
 */

{
#ifdef DEBUG
    if (!pSName)
        fatal("NULL pointer passed to struct_free_type().\n");

    if (pSName->ref != 0)
        fatal("struct name object with %"PRIdPINT" refs passed to struct_free_type().\n"
             , pSName->ref);
#endif

    remove_struct_name(pSName); /* In case it was published */

    size_struct_type -= STRUCT_NAME_MEMSIZE;

    free_mstring(pSName->name);
    free_mstring(pSName->prog_name);

    xfree(pSName);
} /* struct_free_name() */
Beispiel #2
0
/*-------------------------------------------------------------------------*/
void
save_error (const char *msg, const char *file, int line)

/* A runtime error <msg> occured for object <file> in line number <line>.
 * Store this information in the wizlist so that the mudlib can handle
 * it later with the efun get_error_file().
 * TODO: A proper runtime error handling could put this into the mudlib
 * TODO:: completely.
 */

{
    wiz_list_t *wl;
    char *copy, *p;
    string_t *name;
    size_t len;

    /* Get the wizard name and the wizlist entry. */
    name = get_wiz_name(file);
    if (!name)
        return;
    wl = add_name(name);

    /* Set the file_name */
    if (wl->file_name)
        free_mstring(wl->file_name);

    len = strlen(file);
    copy = alloca(len + 4); /* May add .c plus the null byte, and / */
    *copy = '/';
    strcpy(copy+1, file);

    /* If it is a cloned object, we have to find out what the file
     * name is, and add '.c'.
     */
    if ( NULL != (p = strrchr(copy, '#'))
     || ((p = copy+len), *p++ != 'c') || p[-2] != '.' )
    {
        p[0] = '.';
        p[1] = 'c';
        p[2] = '\0';
    }
    wl->file_name = new_mstring(copy);

    /* Set the error_message */
    if (wl->error_message)
        free_mstring(wl->error_message);
    wl->error_message = new_mstring(msg);

    /* Set the line_number */
    wl->line_number = line;
} /* save_error() */
Beispiel #3
0
/*-------------------------------------------------------------------------*/
Bool
dumpstat_dest(string_t *fname)

/* this function dumps statistics about all destructed objects into the file
 * $MUDLIB/<fname>. It is called by dump_driver_info().
 * Return TRUE on success, FALSE if <fname> can't be written.
 */

{
    FILE *f;
    object_t *ob;

    fname = check_valid_path(fname, current_object, STR_OBJDUMP, MY_TRUE);
    if (!fname)
        return MY_FALSE;
    f = fopen(get_txt(fname), "w");
    if (!f)
    {
        free_mstring(fname);
        return MY_FALSE;
    }
    FCOUNT_WRITE(get_txt(fname));

    for (ob = newly_destructed_objs; ob; ob = ob->next_all)
    {
#ifdef DEBUG
        if (!(ob->flags & O_DESTRUCTED)) /* TODO: Can't happen */
            continue;
#endif
        fprintf(f, "%-20s ref %2"PRIdPINT" NEW\n"
                , get_txt(ob->name)
                , ob->ref
               );
    }

    for (ob = destructed_objs; ob; ob = ob->next_all)
    {
#ifdef DEBUG
        if (!(ob->flags & O_DESTRUCTED)) /* TODO: Can't happen */
            continue;
#endif
        fprintf(f, "%-20s ref %2"PRIdPINT"\n"
                , get_txt(ob->name)
                , ob->ref
               );
    }
    fclose(f);
    free_mstring(fname);
    return MY_TRUE;
} /* dumpstat_dest() */
Beispiel #4
0
/*-------------------------------------------------------------------------*/
void
load_wiz_file (void)

/* Load the old wizlist from the wizlist file and add it's data to
 * the wizlist already in memory.
 *
 * This function is called at driver start up.
 * TODO: Since the wizlist is saved from the mudlib, this function
 * TODO:: should be implemented on mudlib level, too.
 */

{
    char buff[1000];
    FILE *f;

    if (wizlist_name[0] == '\0')
        return;

    f = fopen(wizlist_name, "r");
    if (f == NULL)
        return;

    while (fgets(buff, sizeof buff, f) != NULL)
    {
        char *p;
        uint32 score;

        p = strchr(buff, ' ');
        if (p == 0)
        {
            fprintf(stderr, "%s Bad WIZLIST file '%s'.\n"
                          , time_stamp(), wizlist_name);
            break;
        }
        *p = '\0';
        p++;
        if (*p == '\0')
        {
            fprintf(stderr, "%s Bad WIZLIST file '%s'.\n"
                          , time_stamp(), wizlist_name);
            break;
        }
        score = atoi(p);
        if (score > 0)
        {
            string_t * tmp;

            tmp = new_mstring(buff);
            add_name(tmp)->score += score;
            free_mstring(tmp);
        }
    }
    fclose(f);
} /* load_wiz_file() */
Beispiel #5
0
/*-------------------------------------------------------------------------*/
void
remove_wiz_list (void)

/* Remove all memory allocated by the wizlist.
 *
 * Called from simulate::shutdowngame().
 */

{
    wiz_list_t *wl, *w;

    for (w = all_wiz; w; w = wl)
    {
        free_mstring(w->name);
        if (w->file_name)
            free_mstring(w->file_name);
        if (w->error_message)
            free_mstring(w->error_message);
        wl = w->next;
        xfree(w);
    }
} /* remove_wiz_list() */
Beispiel #6
0
/*-------------------------------------------------------------------------*/
void
struct_free_type (struct_type_t *pSType)

/* Free the struct typeobject <pSType> and all referenced data.
 */

{
    unsigned short num;

#ifdef DEBUG
    if (!pSType)
        fatal("NULL pointer passed to struct_free_type().\n");

    if (pSType->ref != 0)
        fatal("struct typeobject with %"PRIdPINT" refs passed to struct_free_type().\n"
             , pSType->ref);
#endif

    num_struct_type--;
    size_struct_type -=   STRUCT_TYPE_MEMSIZE
                        + STRUCT_TYPE_MEMBER_MEMSIZE(pSType->num_members);

    if(pSType->name->current == pSType)
        pSType->name->current = NULL;
    free_struct_name(pSType->name);

    if (pSType->unique_name)
        free_mstring(pSType->unique_name);
    if (pSType->base)
        free_struct_type(pSType->base);

    for (num = 0; num < pSType->num_members; num++)
    {
        free_struct_member_data(&pSType->member[num]);
    }

    if (pSType->member)
        xfree(pSType->member);

    xfree(pSType);
} /* struct_free_type() */
Beispiel #7
0
/*-------------------------------------------------------------------------*/
Bool
assert_simul_efun_object (void)

/* (Re)load the simul_efun object and extract all information we need.
 * Result is TRUE if either the simul_efun object could be loaded, or if
 * master::get_simul_efun() did not return a string/string vector to
 * name the simul efun object. The result is FALSE if master::get_simul_efun()
 * specified a simul efun object, which couldn't be found.
 *
 * In other words: after calling assert_simul_efun_object(), the caller
 * still has to check if simul_efun_object is NULL.
 *
 * At the time of call, simul_efun_object must be NULL.
 */

{
    svalue_t           *svp;
    object_t           *ob;
    program_t          *progp;
    CBool              *visible; /* Flag for every function: visible or not */
    string_t           *name;
    int                 i, j, num_fun;

    invalidate_simul_efuns(); /* Invalidate the simul_efun information */

    free_defines(); /* to prevent #defines hideing places for globals */

    /* Get the name(s) of the simul_efun  object. */
    svp = apply_master(STR_GET_SEFUN, 0);

    /* If a simul_efun_object appears during the GET_SEFUN call, it
     * might have been due to a recursive get_simul_efun() call which may
     * have gotten an old backup copy. This can lead to hard-to-debug
     * variable and function definition inconsistencies.
     */
    if (simul_efun_object)
    {
        printf("%s simul_efun object appeared while asking for it.\n", time_stamp());
        return MY_TRUE;
    }

    if (svp == NULL)
    {
        printf("%s No simul_efun\n", time_stamp());
        return MY_TRUE;
    }

    if (svp->type == T_POINTER)
    {
        simul_efun_vector = svp->u.vec;
        svp->type = T_NUMBER;
        if (VEC_SIZE(svp->u.vec))
            svp = svp->u.vec->item;
    }

    if (svp->type != T_STRING)
    {
        printf("%s No simul_efun\n", time_stamp());
        return MY_TRUE;
    }

    /* Make the (primary) simul_efun name */
    name = del_slash(svp->u.str);
    if (simul_efun_file_name)
        free_mstring(simul_efun_file_name);
    simul_efun_file_name = make_tabled(name);

    /* Get the object and load the program */
    ob = find_object(simul_efun_file_name);
    if (ob == NULL)
    {
        fprintf(stderr, "%s The simul_efun file %s was not loaded.\n"
               , time_stamp(), get_txt(simul_efun_file_name));
        fprintf(stderr, "%s The function get_simul_efun() in the master must load it.\n"
               , time_stamp());
        return MY_FALSE;
    }
    if (O_PROG_SWAPPED(ob) && load_ob_from_swap(ob) < 0)
    {
        fprintf(stderr, "%s Out of memory (unswap object '%s') ==> "
                        "No simul_efun\n", time_stamp(), get_txt(ob->name));
        return MY_TRUE;
    }
    reference_prog( (simul_efun_program = ob->prog), "get_simul_efun");

    num_fun = ob->prog->num_function_names;
    if (num_fun == 0)
        return MY_TRUE;
    if (!simul_efunp)
    {
        simul_efunp = xalloc(sizeof (function_t) * num_fun);
    }
    else
        num_fun = total_simul_efun;

    free_defines(); /* to prevent #defines hideing places for globals */

    /* locals and defines are freed now. There are still reserved words,
     * but it is impossible to define a function with the name being
     * a reserved word, thus, there will be no clashes with higher-priority
     * shared identifiers.
     */

    progp = ob->prog;
    visible = alloca((i = ob->prog->num_functions) * sizeof(*visible));
    memset(visible, 0, i);
    i = ob->prog->num_function_names;
    while (--i >= 0)
        visible[progp->function_names[i]] = MY_TRUE;
    /* The functions .num_function_names+1 .. .num_functions are not
     * visible by definition.
     */

    /* Loop over the functions in the simul_efun object and
     * copy the salient information.
     */
    for (i = 0; i < ob->prog->num_functions; i++)
    {
        int        ix;
        funflag_t  flags, flags2;
        bytecode_p funstart;
        mp_int     fun_ix_offs, var_ix_offs;
        program_t *inherit_progp;
        function_t*funheader;

        if (!visible[i])
            continue;

        ix = i;
        flags2 = flags = progp->functions[ix];
        flags &= ~FUNSTART_MASK;

        /* Pinpoint the function, resolving inheritance where
         * necessary.
         */
        fun_ix_offs = ix;
        var_ix_offs = 0;
        inherit_progp = progp;
        while (flags2 & NAME_INHERITED)
        {
            inherit_t *inheritp;

            inheritp = &inherit_progp->inherit[flags2 & INHERIT_MASK];
            ix -= inheritp->function_index_offset;
            var_ix_offs += inheritp->variable_index_offset;
            inherit_progp = inheritp->prog;
            flags2 = inherit_progp->functions[ix];
        }
        fun_ix_offs -= ix;

        funstart = inherit_progp->program + (flags2 & FUNSTART_MASK);
        funheader = inherit_progp->function_headers + FUNCTION_HEADER_INDEX(funstart);

        /* Don't stumble over undefined functions */
        if (is_undef_function(funstart))
        {
            flags |= NAME_UNDEFINED;
        }

        /* If the function is __INIT, pretend it's a private function */
        if ( !(flags & (TYPE_MOD_STATIC|TYPE_MOD_PRIVATE|NAME_UNDEFINED)) )
        {
            if (mstreq(funheader->name, STR_VARINIT))
                flags |= TYPE_MOD_PRIVATE;
        }

        /* If the function is indeed visible, get its information */
        if ( !(flags & (TYPE_MOD_STATIC|TYPE_MOD_PROTECTED|TYPE_MOD_PRIVATE|NAME_UNDEFINED)) )
        {
            string_t *function_name;
            ident_t *p;
            unsigned char num_arg;

            function_name = funheader->name;
            num_arg = funheader->num_arg;

            /* Find or make the identifier for the function */
            p = make_shared_identifier_mstr(function_name, I_TYPE_GLOBAL, 0);
            if (p->type == I_TYPE_UNKNOWN)
            {
                init_global_identifier(p, /* bVariable: */ MY_FALSE);
                p->next_all = all_simul_efuns;
                all_simul_efuns = p;
            }

            if (flags & TYPE_MOD_VARARGS)
                num_arg = SIMUL_EFUN_VARARGS;

            /* Find the proper index in simul_efunp[] */
            switch(0) { default: /* TRY... */

                /* Try to find a discarded sefun entry with matching
                 * name, number of arguments and XVARARGS flag to reuse.
                 */
                if (all_discarded_simul_efun >= 0)
                {
                    int last;

                    j = all_discarded_simul_efun;
                    while ( (j = simul_efunp[last = j].offset.next_sefun) >= 0)
                    {
                        if (num_arg != simul_efunp[j].num_arg
                         || 0 != ((simul_efunp[j].flags ^ flags) & TYPE_MOD_XVARARGS)
                           )
                            continue;
                        if (!mstreq(function_name, simul_efunp[j].name))
                            continue;

                        /* Found one: remove it from the 'discarded' list */
                        simul_efunp[last].offset.next_sefun =
                              simul_efunp[j].offset.next_sefun;
                        break;
                    }
                    if (j >= 0)
                        break; /* switch */
                }

                /* New simul_efun: make a new entry */
                (void)ref_mstring(function_name);
                j = num_simul_efun++;
                if (num_simul_efun > num_fun)
                {
                    num_fun = num_simul_efun + 12;
                    simul_efunp = rexalloc(simul_efunp
                                          , sizeof (function_t) * num_fun
                      );
                }
                simul_efunp[j].name    = function_name;
                simul_efunp[j].num_arg = num_arg;
            } /* switch() */

            /* j now indexes the simul_efunp[] entry to use */

            p->u.global.sim_efun = j;
            simul_efunp[j].flags      = funheader->flags;
            simul_efunp[j].type       = funheader->type;
            simul_efunp[j].num_locals = funheader->num_locals;

            /* If possible, make an entry in the simul_efun table */
            if ((size_t)j < SEFUN_TABLE_SIZE)
            {
                simul_efun_table[j].funstart = funstart;
                simul_efun_table[j].program = inherit_progp;
                simul_efun_table[j].function_index_offset = fun_ix_offs;
                simul_efun_table[j].variable_index_offset = var_ix_offs;
            }
        } /* if (function visible) */
    } /* for ( all functions) */

    total_simul_efun = num_fun;
    simul_efun_object = ob;

    return MY_TRUE;
} /* get_simul_efun_object() */
Beispiel #8
0
/*-------------------------------------------------------------------------*/
svalue_t * 
f_sl_open (svalue_t *sp) 

/* EFUN sl_open
 *
 *   int sl_open(string filename)
 *
 * Opens the file <filename> for use as a SQLite database.
 * If the file doesn't exists it will be created.
 * Only one open file per object is allowed. On success this
 * function returns 1, otherwise usually an error is thrown.
 */

{
    string_t *file;
    sqlite3 *db;
    sqlite_dbs_t *tmp;
    int err;
   
    file = check_valid_path(sp->u.str, current_object, STR_SQLITE_OPEN , MY_TRUE);
    if (!file)
        errorf("Illegal use of sl_open('%s')\n", get_txt(sp->u.str));
   
    tmp = find_db (current_object);
    if (tmp)
    {
        free_mstring(file);
        errorf("The current object already has a database open.\n");
    }

    err = sqlite3_open (get_txt(file), &db);
    free_mstring(file);
    if (err)
    {
        const char* msg = sqlite3_errmsg(db);
        sqlite3_close(db);
        errorf("sl_open: %s\n", msg );
        /* NOTREACHED */
    }

    /* create a new chain link and hang on the old chain */
    tmp = new_db(); 
    if(!tmp)
    {
        sqlite3_close(db);
        errorf("(sl_open) Out of memory: (%lu bytes)\n",
                (unsigned long) sizeof(*tmp));
    }
   
    tmp->db = db;
    tmp->obj = current_object;
    current_object->open_sqlite_db = MY_TRUE;

    /* Synchronous is damn slow. Forget it. */
    sqlite3_exec(db, "PRAGMA synchronous = OFF", NULL, NULL, NULL);
    sqlite3_set_authorizer(db, my_sqlite3_authorizer, NULL);
  
    free_string_svalue (sp);
    put_number (sp, 1);
    return sp;
} /* f_sl_open() */
Beispiel #9
0
char *
read_bytes(char *file, int start, size_t len)
{
    struct stat st;

    char *str;
    int size;
    int f;

    if(len > MAX_BYTE_TRANSFER)
	return 0;

    file = check_valid_path(file, current_object, "read_bytes", 0);

    if (!file)
	return 0;
    f = open(file, O_RDONLY);
    if (f < 0)
	return 0;

#ifdef PURIFY
    (void)memset(&st, '\0', sizeof(st));
#endif

    if (fstat(f, &st) == -1)
	fatal("Could not stat an open file.\n");
    size = (int)st.st_size;
    if(start < 0) 
	start = size + start;

    if (start >= size)
    {
	(void)close(f);
	return 0;
    }
    if ((start+len) > size) 
	len = (size - start);

    if ((size = (int)lseek(f, (off_t)start, 0)) < 0)
    {
	(void)close(f);
	return 0;
    }

    str = allocate_mstring(len);

    size = read(f, str, len);

    (void)close(f);

    if (size <= 0)
    {
        free_mstring(str);
	return 0;
    }

    /* We want to allow all characters to pass untouched!
    for (il = 0; il < size; il++) 
	if (!isprint(str[il]) && !isspace(str[il]))
	    str[il] = ' ';

    */
    /*
     * The string has to end to '\0'!!!
     */
    str[size] = '\0';


    return str;
}
Beispiel #10
0
/*
 * Append string to file. Return 0 for failure, otherwise 1.
 */
int 
write_file(char *file, char *str)
{
    FILE *f;

    file = check_valid_path(file, current_object, "write_file", 1);

    if (!file)
	return 0;
    f = fopen(file, "a");
    if (f == 0)
	error("Wrong permissions for opening file %s for append.\n", file);
    if (s_flag)
	num_filewrite++;
    if (fwrite(str, strlen(str), 1, f) != 1) {
	(void)fclose(f);
	return 0;
    }
    if (fclose(f) == EOF)
	return 0;
    return 1;
}

int read_file_len; /* Side effect from read_file, so we know how many lines
		      we managed to read */
char *
read_file(char *file, int start, int len)
{
    struct stat st;
    FILE *f;
    char *str, *p, *p2, *end, c;
    size_t size;

    read_file_len = len;
    if (len < 0) return 0;

    file = check_valid_path(file, current_object, "read_file", 0);

    if (!file)
	return 0;
    f = fopen(file, "r");
    if (f == 0)
	return 0;

#ifdef PURIFY
    (void)memset(&st, '\0', sizeof(st));
#endif

    if (fstat(fileno(f), &st) == -1)
	fatal("Could not stat an open file.\n");
    size = (int)st.st_size;
    if (s_flag)
	num_fileread++;
    if (size > READ_FILE_MAX_SIZE)
    {
	if ( start || len )
	    size = READ_FILE_MAX_SIZE;
	else
	{
	    (void)fclose(f);
	    return 0;
	}
    }
    if (!start)
	start = 1;
    if (!len)
	read_file_len = len = READ_FILE_MAX_SIZE;
    str = allocate_mstring(size);
    str[size] = '\0';
    do
    {
	if (size > (int)st.st_size)
	    size = (int)st.st_size;
        if (fread(str, size, 1, f) != 1)
	{
    	    (void)fclose(f);
	    free_mstring(str);
    	    return 0;
        }
	st.st_size -= size;
	end = str + size;
        for (p = str; ( p2 = memchr(p, '\n', (size_t)(end - p)) ) && --start; )
	    p = p2 + 1;
    } while ( start > 1 );
    
    for (p2 = str; p != end; )
    {
        c = *p++;
	if (!isprint(c) && !isspace(c))
	    c = ' ';
	*p2++ = c;
	if ( c == '\n' )
	    if (!--len)
		break;
    }
    if (len && st.st_size)
    {
	size -= (p2 - str) ; 
	if (size > (int)st.st_size)
	    size = (int)st.st_size;
        if (fread(p2, size, 1, f) != 1)
	{
    	    (void)fclose(f);
	    free_mstring(str);
    	    return 0;
        }
	st.st_size -= size;
	end = p2 + size;
        for (; p2 != end; )
	{
	    c = *p2;
	    if (!isprint(c) && !isspace(c))
		*p2 = ' ';
	    p2++;
	    if (c == '\n')
	        if (!--len) break;
	}
	if ( st.st_size && len )
	{
	    /* tried to read more than READ_MAX_FILE_SIZE */
	    (void)fclose(f);
	    free_mstring(str);
	    return 0;
	}
    }
    read_file_len -= len;
    *p2 = '\0';
    (void)fclose(f);
    return str;
}
Beispiel #11
0
/*-------------------------------------------------------------------------*/
Bool
dumpstat (string_t *fname)

/* This function dumps statistics about all listed objects into the file
 * $MUDLIB/<fname>. It is called from dump_driver_info.
 * Return TRUE on success, FALSE if <fname> can't be written.
 */

{
    FILE *f;
    object_t *ob;

    static char *swapstrings[] =
    {"", "PROG SWAPPED", "VAR SWAPPED", "SWAPPED", };

    fname = check_valid_path(fname, current_object, STR_OBJDUMP, MY_TRUE);
    if (!fname)
        return MY_FALSE;
    f = fopen(get_txt(fname), "w");
    if (!f)
    {
        free_mstring(fname);
        return MY_FALSE;
    }
    FCOUNT_WRITE(get_txt(fname));

    for (ob = obj_list; ob; ob = ob->next_all)
    {
        mp_int compsize, totalsize, overhead;
        char timest[21];
        struct tm *tm;

#ifdef DEBUG
        if (ob->flags & O_DESTRUCTED) /* TODO: Can't happen */
            continue;
#endif
        compsize = data_size(ob, &totalsize);

        if (!O_PROG_SWAPPED(ob)
                && (ob->prog->ref == 1 || !(ob->flags & (O_CLONE|O_REPLACED))))
        {
            overhead = ob->prog->total_size;
        }
        else
        {
            overhead = 0;
        }

        overhead += sizeof (object_t);

        fprintf(f, "%-20s %5"PRIdMPINT" (%5"PRIdMPINT") ref %2"PRIdPINT" %s "
                , get_txt(ob->name)
                , compsize + overhead, totalsize + overhead
                , ob->ref
                , ob->flags & O_HEART_BEAT ? "HB" : "  "
               );
        if (ob->super)
            fprintf(f, "%s ", get_txt(ob->super->name));
        else
            fprintf(f, "-- ");

        if (ob->gigaticks)
            fprintf(f, " (%"PRIuMPINT"%09"PRIuMPINT")",
                    (mp_uint)ob->gigaticks, (mp_uint)ob->ticks);
        else
            fprintf(f, " (%"PRIuMPINT")", (mp_uint)ob->ticks);
        fprintf(f, " %s",
                swapstrings[(O_PROG_SWAPPED(ob)?1:0) | (O_VAR_SWAPPED(ob)?2:0)]
               );
        tm = localtime((time_t *)&ob->load_time);
        strftime(timest, sizeof(timest), "%Y.%m.%d-%H:%M:%S", tm);
        fprintf(f, " %s\n", timest);
    }
    fclose(f);
    free_mstring(fname);

    return MY_TRUE;
} /* dumpstat() */
Beispiel #12
0
/*-------------------------------------------------------------------------*/
svalue_t *
x_filter_string (svalue_t *sp, int num_arg)

/* EFUN: filter() for strings.
 *
 *   string filter(string arr, string fun, string|object obj, mixed extra, ...)
 *   string filter(string arr, closure cl, mixed extra, ...)
 *   string filter(string arr, mapping map)
 *
 * Filter the elements of <arr> through a filter defined by the other
 * arguments, and return an array of those elements, for which the
 * filter yields non-zero.
 *
 * The filter can be a function call:
 *
 *    <obj>-><fun>(elem, <extra>...)
 *
 * or a mapping query:
 *
 *    <map>[elem]
 *
 * <obj> can both be an object reference or a filename. If omitted,
 * this_object() is used (this also works if the third argument is
 * neither a string nor an object).
 */

{
    string_t *rc;     /* Result string */
    string_t *str;    /* Argument string  */
    svalue_t *arg;    /* First argument the vm stack */
    mp_int    slen;   /* Argument string length */
    char     *src, *dest; /* String text work pointers */

    char     *flags;  /* Flag array, one flag for each element of <str>
                       * (in reverse order). */
    mp_int    res;    /* Number of surviving elements */

    res = 0;

    /* Locate the args on the stack, extract the string to filter
     * and allocate the flags vector.
     */
    arg = sp - num_arg + 1;

    str = arg->u.str;
    slen = (mp_int)mstrsize(str);

    /* Every element in flags is associated by index number with an
     * element in the vector to filter. The filter function is evaluated
     * for every string character, and the associated flag is set to 0
     * or 1 according to the result.
     * At the end, all 1-flagged elements are gathered and copied
     * into the result string.
     */

    if (arg[1].type == T_MAPPING)
    {
        mp_int cnt;

        /* --- Filter by mapping query --- */
        mapping_t *m;

        if (num_arg > 2) {
            errorf("Too many arguments to filter(array)\n");
        }
        /* Allocate memory for the flag array. Simultaneously an error
         * handler is pushed onto the stack (after the arguments) for freeing
         * the buffer in case of runtime errors. */
        flags = xalloc_with_error_handler((size_t)slen + 1);
        if (!flags)
        {
          errorf("Out of memory (%zu bytes) for temporary buffer in filter().\n",
                 (size_t)slen + 1);
        }
        sp = inter_sp;

        m = arg[1].u.map;
        
        for (src = get_txt(str), cnt = slen; --cnt >= 0; src++)
        {
            svalue_t key;

            put_number(&key,  *src);
            if (get_map_value(m, &key) == &const0)
            {
                flags[cnt] = 0;
                continue;
            }
            flags[cnt] = 1;
            res++;
        }

    } else {

        /* --- Filter by function call --- */

        int         error_index;
        callback_t  cb;
        mp_int cnt;

        assign_eval_cost();

        /* setup_efun_callback() will adopt and therefore remove the 
         * arguments from arg+1 on to arg+num_arg from the stack and update 
         * inter_sp. New top-of-stack will be arg. */
        error_index = setup_efun_callback(&cb, arg+1, num_arg-1);
        if (error_index >= 0)
        {
            vefun_bad_arg(error_index+2, arg);
            /* NOTREACHED */
            return arg;
        }
        /* push the callback structure onto the stack. */
        sp = arg + 1;
        put_callback(sp, &cb);

        /* Allocate memory for the flag array. Simultaneously an error
         * handler is pushed onto the stack (after the arguments) for freeing
         * the buffer in case of runtime errors. */
        inter_sp = sp;
        flags = xalloc_with_error_handler((size_t)slen + 1);
        if (!flags)
        {
            errorf("Out of memory (%"PRIdMPINT" bytes) for temporary buffer "
                "in filter().\n", slen + 1);
        }
        sp = inter_sp;
        
        /* Loop over all elements in p and call the filter.
         * w is the current element filtered.
         */
        for (src = get_txt(str), cnt = slen; --cnt >= 0; src++)
        {
            svalue_t *v;

            flags[cnt] = 0;

            if (current_object->flags & O_DESTRUCTED)
                continue;
                /* Don't call the filter anymore, but fill the
                 * flags array with 0es.
                 */

            if (!callback_object(&cb))
            {
                inter_sp = sp;
                errorf("object used by filter(array) destructed");
            }

            push_number(inter_sp, *src);

            v = apply_callback(&cb, 1);
            if (!v || (v->type == T_NUMBER && !v->u.number) )
                continue;

            flags[cnt] = 1;
            res++;
        }
    }

    /* flags[] holds the filter results, res is the number of
     * elements to keep. Now create the result vector.
     */
    rc = alloc_mstring(res);
    if (!rc)
    {
        errorf("Out of memory (%"PRIdMPINT" bytes) for result in filter().\n",
            slen+1);
    }
  
    for (src = get_txt(str), dest = get_txt(rc), flags = &flags[slen]
       ; res > 0 ; src++)
    {
        if (*--flags)
        {
            *dest++ = *src;
            res--;
        }
    }
  
    /* Cleanup. Arguments for the closure have already been removed. On the
     * stack are now the string, the mapping or callback structure and the
     * error handler. (Not using pop_n_elems() for 2 elements for saving loop 
     * and function call overhead.) */
    free_svalue(sp--);  /* errorhandler, buffer and flags are freed by this. */
    free_svalue(sp--);  /* mapping or callback structure. */
    free_mstring(str);  /* string, at arg == sp */
    sp->u.str = rc;     /* put result here */

    return sp;
} /* x_filter_string() */
Beispiel #13
0
/*-------------------------------------------------------------------------*/
struct_type_t *
struct_new_prototype ( string_t *name, string_t *prog_name )

/* Create a new prototype struct typeobject from the given data.
 * The references from the data are adopted, and the result is the
 * new typeobject with one reference.
 * When an error occurs, NULL is returned and the input data is freed.
 */

{
    struct_type_t * pSType;
    struct_name_t * pSName;
    hash32_t hash = hash2(name, prog_name);

    pSName = find_by_name(name, prog_name, hash);
    if (pSName == NULL)
    {
        /* No name yet, create one. */
        pSName = xalloc(STRUCT_NAME_MEMSIZE);
        if (pSName == NULL)
        {
            free_mstring(name);
            free_mstring(prog_name);
            return NULL;
        }
        size_struct_type += STRUCT_NAME_MEMSIZE;

        pSName->hash = hash;

        pSName->ref = 1;
        pSName->name = name;
        pSName->prog_name = prog_name;

        pSName->lpctype = NULL;
        pSName->current = NULL;

        if (!add_struct_name(pSName))
        {
            free_struct_name(pSName);
            return NULL;
        }
    }
    else
    {
        ref_struct_name(pSName);
        free_mstring(name);
        free_mstring(prog_name);
    }

    pSType = xalloc(STRUCT_TYPE_MEMSIZE);
    if (pSType != NULL)
    {
        pSType->ref = 1;
        pSType->name = pSName;
        pSType->unique_name = NULL;
        pSType->prog_id = 0;
        pSType->num_members = 0;
        pSType->member = NULL;
        pSType->base = NULL;

        num_struct_type++;
        size_struct_type += STRUCT_TYPE_MEMSIZE;
    }
    else
    {
        free_struct_name(pSName);
    }

    return pSType;
} /* struct_new_prototype() */
Beispiel #14
0
/*-------------------------------------------------------------------------*/
void
remove_unreferenced_structs (void)

/* Free all structs in the table which are not marked as referenced.
 * This function must be called before freeing all unreferenced strings!
 */

{
    size_t num;

    if (!table || !table_size)
        return;
    
    for (num = 0; num < table_size; num++)
    {
        struct_name_t * this, * prev;

        for (prev = NULL, this = table[num]; this != NULL; )
        {
            if (!test_memory_reference(this))
            {
                prev = this;
                this = this->next;
            }
            else
            {
                struct_name_t * next = this->next;
                if (prev)
                    prev->next = next;
                else
                    table[num] = next;

                num_types--;

                /* Now we deallocate the memory for the struct name
                 * structure.
                 */
                size_struct_type -= STRUCT_NAME_MEMSIZE;

                dprintf2(gcollect_outfd, "struct name %x '%s' was left "
                                         "unreferenced, freeing now.\n"
                                       , (p_int) this
                                       , (p_int) get_txt(this->name)
                        );

                /* Reference all strings and free them, to avoid unnecessary
                 * 'string unreferenced' diagnostics.
                 */
                count_ref_from_string(this->name);
                free_mstring(this->name);
                count_ref_from_string(this->prog_name);
                free_mstring(this->prog_name);

                /* Reference the memory (to update its flags) and free it */
                note_malloced_block_ref(this);
                xfree(this);

                this = next;
            }
        }
    } /* for (num) */

} /* remove_unreferenced_structs() */