Ejemplo n.º 1
0
/*-------------------------------------------------------------------------*/
string_t *
struct_t_unique_name (struct_type_t *pSType)

/* Also aliased to: struct_unique_name(struct_t *)
 *
 * Compose and return the unique name of struct type <pSType>.
 * The returned string reference is not counted.
 *
 * The value save/restore routines rely on the format of this string.
 */

{
    char name[MAXPATHLEN+256];

    if (pSType->unique_name)
        return pSType->unique_name;

    snprintf(name, sizeof(name), "%s %s #%"PRId32
                , get_txt(struct_t_name(pSType))
                , get_txt(struct_t_pname(pSType))
                , struct_t_pid(pSType)
           );
    pSType->unique_name = new_mstring(name);

    return pSType->unique_name;
} /* struct_t_unique_name() */
Ejemplo n.º 2
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() */
Ejemplo n.º 3
0
int TB_handle_one(int cid)
{
  term *trm, *result;
  TBbool sndvoid = TBfalse;

  assert_valid_cid(cid);

  trm = TB_receive(cid);
  if(!trm) {
    err_fatal("contact with ToolBus lost.\n");
  }
  if(streq(get_txt(fun_sym(trm)), "rec-do")) {
    sndvoid = TBtrue;
  }
  result = connections[cid]->handler(cid, trm);
  if(result) {
    return TB_send(cid, result);
  }
  else if(sndvoid) {
    return TB_send(cid, TBmake("snd-void()"));
  }

  err_fatal("Unhandled case in TB_handle_one!\n");
  return -1;
}
Ejemplo n.º 4
0
/*-------------------------------------------------------------------------*/
string_t *
trim_all_spaces (const string_t * txt)

/* Trim the input string <txt> by removing all leading and trailing
 * space, and by folding embedded space runs into just one each.
 * Return the new string with one ref; the refcount of <txt> is not changed.
 *
 * Throw an error when out of memory.
 */

{
    char * dest;
    const char * src;
    size_t dest_ix, src_ix, srclen;
    string_t * rc;

    dest = alloca(mstrsize(txt));
    if (dest == NULL)
        errorf("Stack overflow (%zu bytes)\n", mstrsize(txt));

    src = get_txt((string_t *const)txt);
    srclen = mstrsize(txt);
    src_ix = 0;
    dest_ix = 0;

    /* Blank out trailing spaces */
    while (srclen > 0 && src[srclen-1] == ' ')
        srclen--;

    /* Skip leading spaces */
    while (src_ix < srclen && *src == ' ')
        src_ix++, src++;

    /* Copy characters, but fold embedded spaces. */
    for ( ; src_ix < srclen; src_ix++, src++, dest_ix++)
    {
        dest[dest_ix] = *src;

        /* If this and the next character is a space, forward
         * src until the last space in this run.
         */
        if (' ' == *src)
        {
            while (src_ix+1 < srclen && ' ' == src[1])
                src_ix++, src++;
        }
    }

    memsafe(rc = new_n_mstring(dest, dest_ix), dest_ix, "trimmed result");
    return rc;
} /* trim_all_spaces() */
Ejemplo n.º 5
0
/*-------------------------------------------------------------------------*/
static INLINE hash32_t
hash2 (string_t * const pName, string_t * const pProgName)

/* Compute the hash from <pName> combined with <pProgName>.
 */

{
    hash32_t         hash;

    hash = mstr_get_hash(pName);
    hash = hash_string_chained("\n", 1, hash);
    hash = hash_string_chained(get_txt(pProgName), mstrsize(pProgName), hash);

    return hash;
} /* hash2() */
Ejemplo n.º 6
0
static term *tool_read_term(void)
{
  int nelem;
  term *trm, *rtrm;
  inport *inp;
  TBbool sndvoid = TBfalse;

  while(TBtrue){
    if(stand_alone){
      fprintf(stdout, "%s", single_prompt);
      fflush(stdout);
    }
    inp = NULL;
    nelem = read_from_any_channel(&inp);
    if(nelem < 0){
      err_warn("tool_read_term: cannot find ready input channel");
      continue;
    }
    if(inp && inp->term_port){
      if((trm = parse_buffer())){
	/*TBmsg("tool_read_term: ***%t***\n", trm);*/
	if(streq(get_txt(fun_sym(trm)), "rec-do"))
          sndvoid = TBtrue;
	rtrm = (*inp->callbackTerm)(trm);
	if(sndvoid)
	  return Snd_Void;
	else
	  return rtrm;
      }
    } else {
      if(inp)
	return (*inp->callbackChar)(inp->in);
    } 
  }
  return NULL; /* <PO> missing return from lcc */
}
Ejemplo n.º 7
0
/*-------------------------------------------------------------------------*/
svalue_t *
x_map_string (svalue_t *sp, int num_arg)

/* EFUN map() for strings
 *
 *   string map(string arg, string func, string|object ob, mixed extra...)
 *   string map(string arg, closure cl, mixed extra...)
 *   string map(string arg, mapping m)
 *
 * Call the function <ob>-><func>() resp. the closure <cl> for
 * every element of the array/struct/mapping/string <arg>, and return a result
 * made up from the returned values.
 *
 * It is also possible to map every entry through a lookup <m>[element]. If
 * the mapping entry doesn't exist, the original value is kept, otherwise the
 * result of the mapping lookup.
 *
 * Since <arg> is a string, only integer return values are allowed, of which
 * only the lower 8 bits are considered.
 *
 * If <ob> is omitted, or neither an object nor a string, then
 * this_object() is used.
 */

{
    string_t *res;
    string_t *str;
    svalue_t *arg;
    mp_int    len;
    char     *src, *dest;

    inter_sp = sp;

    arg = sp - num_arg + 1;

    str = arg->u.str;
    len = mstrsize(str);

    if (arg[1].type == T_MAPPING)
    {
        /* --- Map through mapping --- */

        mapping_t *m;

        if (num_arg > 2) {
            inter_sp = sp;
            errorf("Too many arguments to map(string)\n");
        }
        m = arg[1].u.map;

        res = alloc_mstring(len);
        if (!res)
            errorf("(map_string) Out of memory: string[%"PRIdMPINT
                   "] for result\n", len);
      
        push_string(inter_sp, res); /* In case of errors */

        for (src = get_txt(str), dest = get_txt(res); --len >= 0; src++, dest++)
        {
            svalue_t key, *v;

            put_number(&key, *src);
            v = get_map_value(m, &key);
            if (v == &const0)
                *dest = *src;
            else
            {
                if (v->type != T_NUMBER)
                {
                    errorf("(map_string) Illegal value: %s, expected string\n"
                         , typename(v->type)
                         );
                }
                *dest = (v->u.number & 0xFF);
            }
        }
Ejemplo n.º 8
0
void
fill_header_from_mapping (svalue_t *key, svalue_t *val, void *extra) {
    psyc_modifier_t *m = extra;
    char oper = 0;
    char *name, *value;
    size_t namelen, valuelen, i;
    uint8_t type;
    svalue_t vsp, *lval;

    psycList list;
    psycString *elems = NULL;

    if (key->type != T_STRING) {
	errorf("fill_header_from_mapping: key type %d not supported\n", key->type);
	return; // not reached
    }

    name = get_txt(key->u.str);
    namelen = mstrsize(key->u.str);
    type = psyc_getVarType2(name, namelen);

    if (m->num_values > 1)
	oper = val[1].u.number;
    if (!oper)
	oper = C_GLYPH_OPERATOR_SET;

    switch (val->type) {
	case T_STRING:
	    value = get_txt(val->u.str);
	    valuelen = mstrsize(val->u.str);
	    break;

	case T_NUMBER:
	case T_OBJECT:
	    vsp.type = val->type;
	    switch (val->type) {
		case T_NUMBER:
		    if (type == PSYC_TYPE_DATE)
			vsp.u.number = val->u.number - PSYC_EPOCH;
		    else
			vsp.u.number = val->u.number;
		    break;
		case T_OBJECT:
		    vsp.u.ob = val->u.ob;
		    break;
	    }

	    f_to_string(&vsp);	// generates an mstring
	    value = get_txt(vsp.u.str);
	    valuelen = mstrsize(vsp.u.str);
	    break;

	case T_POINTER:
	    if (VEC_SIZE(val->u.vec)) {
		elems = pxalloc(sizeof(psycString) * VEC_SIZE(val->u.vec));
		if (!elems) {
		    errorf("Out of memory in fill_header_from_mapping for elems\n");
		    return; // not reached
		}

		for (i = 0; i < VEC_SIZE(val->u.vec); i++) {
		    lval = &(val->u.vec->item[i]);
		    switch (lval->type) {
			case T_STRING:
			    elems[i] = (psycString){mstrsize(lval->u.str), get_txt(lval->u.str)};
			    break;
			case T_NUMBER:
			case T_OBJECT:
			    vsp.type = lval->type;
			    switch (lval->type) {
				case T_NUMBER:
				    vsp.u.number = lval->u.number;
				    break;
				case T_OBJECT:
				    vsp.u.ob = lval->u.ob;
				    break;
			    }

			    f_to_string(&vsp);
			    elems[i] = (psycString){mstrsize(vsp.u.str), get_txt(vsp.u.str)};
			    break;
			default:
			    errorf("fill_header_from_mapping: list value type %d not supported\n", lval->type);
			    return; // not reached
		    }
		}
	    }

	    list = psyc_newList(elems, VEC_SIZE(val->u.vec), PSYC_LIST_CHECK_LENGTH);
	    valuelen = list.length;
	    value = pxalloc(valuelen);
	    if (!value) {
		errorf("Out of memory in fill_header_from_mapping for list value\n");
		return; // not reached
	    }

	    psyc_renderList(&list, value, valuelen);
	    break;

	default:
	    errorf("fill_header_from_mapping: value type %d not supported\n", val->type);
	    return; // not reached
    }

    m->header->modifiers[m->header->lines++] =
	psyc_newModifier2(oper, name, namelen, value, valuelen, m->flag);
}
Ejemplo n.º 9
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() */
Ejemplo n.º 10
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() */
Ejemplo n.º 11
0
/*--------------------------------------------------------------------*/
string_t *
intersect_strings (const string_t * p_left, const string_t * p_right, Bool bSubtract)

/* !bSubtract: Intersect string <left> with string <right> and return
 *   a newly allocated string with all those characters which are in
 *   both strings.
 * bSubtract:  Subtract string <right> from string <left> and return
 *   a newly allocated string with all those characters which are in
 *   <left> but not in <right>.
 * The order of the characters returned is their order of appearance
 * in <left>.
 */

{
    size_t   len_left, len_right, len_out;
    size_t   ix_left, ix_right;
    long   * pos;
    CBool  * matches;
    const char * left_txt;
    char * left, * right, * result_txt;
    string_t *result;

    len_left = mstrsize(p_left);
    len_right = mstrsize(p_right);

    xallocate(matches, len_left+1, "intersection matches");
      /* +1 so that smalloc won't complain when given an empty left string */

    for (ix_left = 0; ix_left < len_left; ix_left++)
        matches[ix_left] = bSubtract ? MY_TRUE : MY_FALSE;

    /* Sort the two strings */
    left = sort_string(p_left, len_left, &pos);
    right = sort_string(p_right, len_right, NULL);

    /* Intersect the two strings by mutual comparison.
     * Each non-matched character in left gets is pos[] set to -1.
     */
    len_out = bSubtract ? len_left : 0;
    for ( ix_left = 0, ix_right = 0
        ; ix_left < len_left && ix_right < len_right
        ; )
    {
        if (left[ix_left] < right[ix_right])
            ix_left++;
        else if (left[ix_left] > right[ix_right])
            ix_right++;
        else /* left[ix_left] == right[ix_right]) */
        {
            if (!bSubtract)
            {
                matches[pos[ix_left]] = MY_TRUE;
                len_out++;
            }
            else
            {
                matches[pos[ix_left]] = MY_FALSE;
                len_out--;
            }
            ix_left++;
        }
    }

    /* Create the result: copy all flagged characters */
    memsafe(result = alloc_mstring(len_out), len_out, "intersection result");
    left_txt = get_txt((string_t *const)p_left);
    result_txt = get_txt(result);
    for (ix_left = 0, ix_right = 0; ix_left < len_left; ix_left++)
        if (matches[ix_left])
            result_txt[ix_right++] = left_txt[ix_left];

    /* Free intermediate results */
    xfree(pos);
    xfree(matches);
    xfree(left);
    xfree(right);

    return result;
} /* intersect_strings() */
Ejemplo n.º 12
0
/*--------------------------------------------------------------------*/
static char *
sort_string (const string_t * p_in, size_t len, long ** pos)

/* Sort the characters of string <in> (with length <len>) by their numeric
 * values and return a newly allocated memory block with the sorted string.
 * If <pos> is not NULL, it will be set to a newly allocated memory block
 * giving the original positions of the characters in the sorted string.
 *
 * We use Mergesort to sort the strings.
 * TODO: Use Quicksort instead of Mergesort?
 */

{
    const char * in;  /* Input string */
    char   * out;     /* Result string */
    long   * outpos;  /* Result position array */
    char   * tmp;     /* Temporary string */
    long   * tmppos;  /* Temporary position array */
    size_t   step;
    size_t   i, j;

    in = get_txt((string_t *const)p_in);
    out = xalloc(len+1);
    tmp = xalloc(len+1);
    if (!out || !tmp)
    {
        if (out)
            xfree(out);
        if (tmp)
            xfree(tmp);
        errorf("(sort_string) Out of memory (2 * %zu bytes) for temporaries.\n"
             , len+1);
    }
    out[len] = '\0';
    tmp[len] = '\0';

    if (pos)
    {
        outpos = xalloc(len * sizeof(*outpos) + 1);
        tmppos = xalloc(len * sizeof(*outpos) + 1);
          /* +1 so that smalloc won't complain when given an empty string */
        if (!outpos || !tmppos)
        {
            if (out)
                xfree(out);
            if (tmp)
                xfree(tmp);
            if (outpos)
                xfree(outpos);
            if (tmppos)
                xfree(tmppos);
            errorf("(sort_string) Out of memory (2 * %zu bytes) for positions.\n"
                 , len*sizeof(*outpos)+1);
        }
    }
    else
    {
        outpos = NULL;
        tmppos = NULL;
    }

    /* First Mergesort pass: comparison of adjacent characters
     * and initialisation of the out arrays.
     */
    for (i = 0; i < len; i += 2)
    {
        if (i == len-1)
        {
            out[i] = in[i];
            if (outpos)
                outpos[i] = i;
        }
        else if (in[i] <= in[i+1])
        {
            out[i] = in[i];
            out[i+1] = in[i+1];
            if (outpos)
            {
                outpos[i] = i;
                outpos[i+1] = i+1;
            }
        }
        else /* (in[i] > in[i+1]) */
        {
            out[i] = in[i+1];
            out[i+1] = in[i];
            if (outpos)
            {
                outpos[i] = i+1;
                outpos[i+1] = i;
            }
        }
    } /* for(initial pass) */

    /* Mergesort loop: perform the mergesort passes with increasing steps.
     * Invariant: out is the (semi-sorted) data, tmp is the scratchspace.
     */
    for (step = 2; step < len; step *= 2)
    {
        size_t start, dest, left;

        /* Exchange out and tmp */
        {
            char *tmp2;
            long *tmp2pos;

            tmp2 = out; out = tmp; tmp = tmp2;
            if (outpos)
            {
                tmp2pos = outpos; outpos = tmppos; tmppos = tmp2pos;
            }
        }

        for (start = 0, dest = 0; start <= len; start += 2*step)
        {
            for ( i = start, j = start+step, left = 2 * step
                ; left && dest < len
                ; left--, dest++
                )
            {
                if (i >= start+step
                 || i >= len)
                {
                    if (j < len)
                    {
                        out[dest] = tmp[j];
                        if (outpos)
                            outpos[dest] = tmppos[j];
                        j++;
                    }
                }
                else if (j >= start+2*step
                      || j >= len)
                {
                    if (i < len)
                    {
                        out[dest] = tmp[i];
                        if (outpos)
                            outpos[dest] = tmppos[i];
                        i++;
                    }
                }
                else if (tmp[i] <= tmp[j])
                {
                    out[dest] = tmp[i];
                    if (outpos)
                        outpos[dest] = tmppos[i];
                    i++;
                }
                else /* (tmp[i] > tmp[i+step]) */
                {
                    out[dest] = tmp[j];
                    if (outpos)
                        outpos[dest] = tmppos[j];
                    j++;
                }
            } /* for (sort run) */
        } /* for (start) */
    } /* for(step) */

    /* Free the temporary data */
    if (tmppos)
        xfree(tmppos);
    xfree(tmp);

    /* Return the result */
    if (pos)
        *pos = outpos;

    return out;
} /* sort_string() */
Ejemplo n.º 13
0
svalue_t *
f_psyc_parse (svalue_t *sp) {
    char *buffer = NULL;
    svalue_t *sv;
    vector_t *v, *list;
    mapping_t *map;
    char oper = 0;
    psycString name = {0,0}, value = {0,0}, elems[MAX_LIST_SIZE], elem;
    psycParseListState listState;
    int ret, retl, type = -1, error = 0;
    size_t size, i;
    ssize_t n;
    time_t timmy;

    if (!psyc_dispatch_callback)
      psyc_dispatch_callback = new_tabled("psyc_dispatch");

    if (!psyc_error_callback)
      psyc_error_callback = new_tabled("psyc_error");

    assert_shadow_sent(current_object);
    psyc_state_t *state = O_GET_PSYC_STATE(current_object);
    if (!state) {
	state = pxalloc(sizeof(psyc_state_t));
	if (!state) {
	    errorf("Out of memory for psyc state struct.\n");
	    return sp; // not reached
	}
	O_GET_PSYC_STATE(current_object) = state;
	memset(state, 0, sizeof(psyc_state_t));

	state->parser = pxalloc(sizeof(psycParseState));
	if (!state->parser) {
	    errorf("Out of memory for psyc parse state struct.\n");
	    return sp; // not reached
	}
	psyc_initParseState(state->parser);
    }
    v = state->packet;

    if (sp->type == T_POINTER) {
	errorf("\npsyc_parse got %ld int* bytes... not supported yet\n",
	       VEC_SIZE(sp->u.vec));
	return sp; // not reached
    } else if (sp->type == T_STRING) {
#ifdef DEBUG
	printf("\npsyc_parse got a %ld bytes long string...\n", mstrsize(sp->u.str));
#endif
	if (state->remaining) {
	    // there are remaining bytes from the previous call to psyc_parse,
	    // copy them together with the newly arrived data
	    buffer = pxalloc(state->remaining_len + mstrsize(sp->u.str));
	    if (!buffer) {
		errorf("Out of memory for psyc_parse buffer.\n");
		return sp; // not reached
	    }
	    memcpy(buffer, state->remaining, state->remaining_len);
	    memcpy(buffer + state->remaining_len, get_txt(sp->u.str),
		   mstrsize(sp->u.str));
	    psyc_setParseBuffer2(state->parser, buffer,
				 state->remaining_len + mstrsize(sp->u.str));
	    pfree(state->remaining);
	    state->remaining = NULL;
	    state->remaining_len = 0;
	} else {
	    psyc_setParseBuffer2(state->parser, get_txt(sp->u.str),
				 mstrsize(sp->u.str));
	}
    } else {
	errorf("\npsyc_parse got type %d, not supported\n", sp->type);
	return sp; // not reached
    }

    do {
	ret = psyc_parse(state->parser, &oper, &name, &value);
#ifdef DEBUG
	printf("#%2d %c%.*s = %.*s\n", ret, oper ? oper : ' ',
	       (int)name.length, name.ptr, (int)value.length, value.ptr);
#endif
	if (!state->packet) {
	    state->packet = allocate_array(4);
	    if (!state->packet) {
		errorf("Out of memory for psyc_parse array.\n");
		return sp; // not reached
	    }
	    v = state->packet;

	    map = allocate_mapping(0, 2);	// empty mapping
	    if (!map) {
		errorf("Out of memory for psyc_parse routing header.\n");
		return sp; // not reached
	    }
	    put_mapping(&v->item[PACKET_ROUTING], map);
	    map = allocate_mapping(0, 2);	// empty mapping
	    if (!map) {
		errorf("Out of memory for psyc_parse entity header.\n");
		return sp; // not reached
	    }
	    put_mapping(&v->item[PACKET_ENTITY], map);
	}

	switch (ret) {
	    case PSYC_PARSE_ENTITY_START: case PSYC_PARSE_BODY_START:
		// save oper, name & value in state at the start of
		// incomplete entity or body
		state->oper = oper;
		state->name = mstring_alloc_string(name.length);
		memcpy(get_txt(state->name), name.ptr, name.length);
		if (!state->name) {
		    errorf("Out of memory for name.\n");
		    return sp; // not reached
		}

		// allocate memory for the total length of the value
		state->value_len = 0;
		state->value = mstring_alloc_string(psyc_getParseValueLength(state->parser));
		if (!state->value) {
		    errorf("Out of memory for value.\n");
		    return sp; // not reached
		}

		// fall thru
	    case PSYC_PARSE_ENTITY_CONT:  case PSYC_PARSE_BODY_CONT:
	    case PSYC_PARSE_ENTITY_END:   case PSYC_PARSE_BODY_END:
		// append value to tmp buffer in state
		memcpy(get_txt(state->value) + state->value_len, value.ptr, value.length);
		state->value_len += value.length;
	}

	if (ret == PSYC_PARSE_ENTITY_END || ret == PSYC_PARSE_BODY_END) {
	    // incomplete entity or body parsing done,
	    // set oper/name/value to the ones saved in state
	    oper = state->oper;
	    name.ptr = get_txt(state->name);
	    name.length = mstrsize(state->name);
	    value.ptr = get_txt(state->value);
	    value.length = mstrsize(state->value);
	}

	switch (ret) {
	    case PSYC_PARSE_ROUTING:
		sv = pxalloc(sizeof(svalue_t));

		// new_n_tabled fetches a reference of a probably existing
		// shared string
		put_string(sv, new_n_tabled(name.ptr, name.length));
		sv = get_map_lvalue(v->item[PACKET_ROUTING].u.map, sv);
		put_number(&sv[1], oper);
		// strings are capable of containing 0 so we can do this
		// for binary data too. let's use a tabled string even
		// for values of routing variables as they repeat a lot
		put_string(sv, new_n_tabled(value.ptr, value.length));
		break;

	    case PSYC_PARSE_ENTITY_START:
	    case PSYC_PARSE_ENTITY_CONT:
		break;

	    case PSYC_PARSE_ENTITY_END:
	    case PSYC_PARSE_ENTITY:
		sv = pxalloc(sizeof(svalue_t));

		if (ret == PSYC_PARSE_ENTITY)
		    put_string(sv, new_n_tabled(name.ptr, name.length));
		else // PSYC_PARSE_ENTITY_END
		    put_string(sv, make_tabled(state->name));

		sv = get_map_lvalue(v->item[PACKET_ENTITY].u.map, sv);
		put_number(&sv[1], oper);

		type = psyc_getVarType(&name);

		switch (type) {
		    case PSYC_TYPE_DATE: // number + PSYC_EPOCH
			if (psyc_parseDate(&value, &timmy))
			    put_number(sv, timmy);
			else
			    error = PSYC_PARSE_ERROR_DATE;
			break;
		    case PSYC_TYPE_TIME: // number
			if (psyc_parseTime(&value, &timmy))
			    put_number(sv, timmy);
			else
			    error = PSYC_PARSE_ERROR_TIME;
			break;
		    case PSYC_TYPE_AMOUNT: // number
			if (psyc_parseNumber(&value, &n))
			    put_number(sv, n);
			else
			    error = PSYC_PARSE_ERROR_AMOUNT;
			break;
		    case PSYC_TYPE_DEGREE: // first digit
			if (value.length && value.ptr[0] >= '0' && value.ptr[0] <= '9')
			    put_number(sv, value.ptr[0] - '0');
			else
			    error = PSYC_PARSE_ERROR_DEGREE;
			break;
		    case PSYC_TYPE_FLAG: // 0 or 1
			if (value.length && value.ptr[0] >= '0' && value.ptr[0] <= '1')
			    put_number(sv, value.ptr[0] - '0');
			else
			    error = PSYC_PARSE_ERROR_FLAG;
			break;
		    case PSYC_TYPE_LIST: // array
			size = 0;
			if (value.length) {
			    psyc_initParseListState(&listState);
			    psyc_setParseListBuffer(&listState, value);
			    elem = (psycString){0, 0};
			    do {
				retl = psyc_parseList(&listState, &elem);
				switch (retl) {
				    case PSYC_PARSE_LIST_END:
					retl = 0;
				    case PSYC_PARSE_LIST_ELEM:
					if (size >= MAX_LIST_SIZE) {
					    error = PSYC_PARSE_ERROR_LIST_TOO_LARGE;
					    break;
					}
					elems[size++] = elem;
					break;
				    default:
					error = PSYC_PARSE_ERROR_LIST;
				}
			    } while (retl > 0 && !error);
			}
			if (error) break;

			list = allocate_array(size);
			for (i = 0; i < size; i++)
			    put_string(&list->item[i], new_n_tabled(elems[i].ptr,
			                                            elems[i].length));

			put_array(sv, list);
			break;
		    default: // string
			if (ret == PSYC_PARSE_ENTITY)
			    // is it good to put entity variable values into the
			    // shared string table? probably yes.. but it's a guess
			    //t_string(sv, new_n_mstring(value.ptr, value.length));
			    put_string(sv, new_n_tabled(value.ptr, value.length));
			else // PSYC_PARSE_ENTITY_END
			    put_string(sv, state->value);
		}
		break;

	    case PSYC_PARSE_BODY_START:
	    case PSYC_PARSE_BODY_CONT:
		break;

	    case PSYC_PARSE_BODY_END:
		put_string(&v->item[PACKET_METHOD], make_tabled(state->name));
		put_string(&v->item[PACKET_BODY], state->value);
		break;

	    case PSYC_PARSE_BODY:
		// new_n_tabled gets the shared string for the method
		put_string(&v->item[PACKET_METHOD],
			   new_n_tabled(name.ptr, name.length));

		// allocate an untabled string for the packet body
		put_string(&v->item[PACKET_BODY],
			   new_n_mstring(value.ptr, value.length));
		break;

	    case PSYC_PARSE_COMPLETE:
		put_array(inter_sp, v);
		sapply(psyc_dispatch_callback, current_object, 1);
		state->packet = NULL;
		break;

	    case PSYC_PARSE_INSUFFICIENT:
		// insufficient data, save remaining bytes
		state->remaining_len = psyc_getParseRemainingLength(state->parser);
		if (state->remaining_len) {
		    state->remaining = pxalloc(state->remaining_len);
		    memcpy(state->remaining,
			   psyc_getParseRemainingBuffer(state->parser),
			   state->remaining_len);
		} else
		    state->remaining = NULL;

		ret = 0;
		break;

	    default:
		error = ret;
	}

	switch (ret) {
	    case PSYC_PARSE_BODY_END:
	    case PSYC_PARSE_ENTITY_END:
		// reset tmp buffers in state when incomplete
		// entity or body parsing is finished
		state->oper = 0;
		state->name = NULL;
		state->value = NULL;
	}
    } while (ret && !error);

    if (buffer)
	pfree(buffer);

    free_svalue(sp);
    put_number(sp, error);
    return sp;
} /* f_psyc_parse */
Ejemplo n.º 14
0
/*-------------------------------------------------------------------------*/
svalue_t * 
v_sl_exec (svalue_t * sp, int num_arg) 

/* EFUN sl_exec()
 *
 *   mixed* sl_exec(string statement, ...)
 *
 * Executes the SQL statement <statement> for the current
 * SQLite database. The SQL statement may contain wildcards like
 * '?' and '?nnn', where 'nnn' is an integer. These wildcards
 * can be given as further parameters to sl_exec. With '?nnn'
 * the number of a specific parameter can be given, the first
 * parameter has number 1.
 * 
 * If the statement returns data, sl_exec returns an array
 * with each row (which is itself an array of columns) as 
 * an element.
 */

{
    svalue_t *argp;
    sqlite_dbs_t *db;
    sqlite3_stmt *stmt;
    const char* tail;
    int err, rows, cols, num;
    struct sl_exec_cleanup_s * rec_data;
    vector_t * result;

    argp = sp - num_arg + 1; /* First argument: the SQL query */
    
    db = find_db (current_object);
    if (!db)
        errorf("The current object doesn't have a database open.\n");
    
    err = sqlite3_prepare(db->db, get_txt(argp->u.str), mstrsize(argp->u.str),
        &stmt, &tail);
    if(err)
    {
        const char* msg = sqlite3_errmsg(db->db);
        if(stmt)
            sqlite3_finalize(stmt);
        errorf("sl_exec: %s\n", msg);
        /* NOTREACHED */
    }
    
    /* Now bind all parameters. */
    for(argp++, num=1; argp <= sp; argp++, num++)
    {
        switch(argp->type)
        {
        default:
            sqlite3_finalize(stmt);
            errorf("Bad argument %d to sl_exec(): type %s\n",
                num+1, typename(argp->type));
            break; /* NOTREACHED */

        case T_FLOAT:
            sqlite3_bind_double(stmt, num, READ_DOUBLE(argp));
            break;

        case T_NUMBER:
            if (sizeof(argp->u.number) > 4)
                sqlite3_bind_int64(stmt, num, argp->u.number);
            else
                sqlite3_bind_int(stmt, num, argp->u.number);
            break;
    
        case T_STRING:
            sqlite3_bind_text(stmt, num, get_txt(argp->u.str),
                mstrsize(argp->u.str), SQLITE_STATIC);
            break;
        }
    }
    
    rows = 0;
    cols = sqlite3_column_count(stmt);

    rec_data = xalloc(sizeof(*rec_data));
    if(!rec_data)
    {
        sqlite3_finalize(stmt);
        errorf("(sl_exec) Out of memory: (%lu bytes) for cleanup structure\n",
            (unsigned long) sizeof(*rec_data));
    }
    rec_data->rows = NULL;
    rec_data->stmt = stmt;
    
    sp = push_error_handler(sl_exec_cleanup, &(rec_data->head));
    
    while((err = sqlite3_step(stmt)) == SQLITE_ROW)
    {
        int col;
        sqlite_rows_t *this_row;

        rows++;
        this_row = pxalloc(sizeof(*this_row));
        if(!this_row)
            errorf("(sl_exec) Out of memory: (%lu bytes)\n",
                (unsigned long) sizeof(*this_row));

        this_row->last = rec_data->rows;
        rec_data->rows = this_row;
        this_row->row = NULL; /* Because allocate_array may throw an error. */

        this_row->row = allocate_array(cols);
        if(!this_row->row)
            errorf("(sl_exec) Out of memory: row vector\n");
    
        for(col = 0; col < cols; col++)
        {
            svalue_t * entry;
            STORE_DOUBLE_USED;

            entry = this_row->row->item + col;

            switch(sqlite3_column_type(stmt, col))
            {
            default:
                errorf( "sl_exec: Unknown type %d.\n"
                      , sqlite3_column_type(stmt, col));
                break;

            case SQLITE_BLOB:
                errorf("sl_exec: Blob columns are not supported.\n");
                break;

            case SQLITE_INTEGER:
                if (sizeof(entry->u.number) >= 8)
                    put_number(entry, sqlite3_column_int64(stmt, col));
                else
                    put_number(entry, sqlite3_column_int(stmt, col));
                break;

           case SQLITE_FLOAT:
                entry->type = T_FLOAT;
                STORE_DOUBLE(entry, sqlite3_column_double(stmt, col));
                break;

            case SQLITE_TEXT:
                put_c_n_string( entry
                              , (char *)sqlite3_column_text(stmt, col)
                              , sqlite3_column_bytes(stmt, col));
                break;

            case SQLITE_NULL:
                /* All elements from this_row->row are initialized to 0. */
                break;
            }
        }
    }

    sqlite3_finalize(stmt);
    rec_data->stmt = NULL;
    
    switch(err)
    {
    default:
        errorf("sl_exec: Unknown return code from sqlite3_step: %d.\n", err);
        break;

    case SQLITE_BUSY:
        errorf("sl_exec: Database is locked.\n");
        break;

    case SQLITE_ERROR:
        errorf("sl_exec: %s\n", sqlite3_errmsg(db->db));
        break;

    case SQLITE_MISUSE:
        errorf("sl_exec: sqlite3_step was called inappropriately.\n");
        break;

    case SQLITE_DONE:
        break;
    }

    if(rows)
    {
        sqlite_rows_t *this_row;

        result = allocate_array(rows);
        if(!result)
            errorf("(sl_exec) Out of memory: result vector\n");

        this_row = rec_data->rows;
        while(rows--)
        {
            put_array(result->item + rows, this_row->row);
            this_row->row = NULL;
            this_row = this_row->last;
        }
    }
    else
        result = NULL;

    // Pop arguments and our error handler.
    // Our error handler gets called and cleans the row stuff.
    sp = pop_n_elems(num_arg + 1, sp) + 1; 
 
    if(rows)
        put_array(sp,result);
    else
        put_number(sp, 0);

    return sp;
} /* v_sl_exec() */
Ejemplo n.º 15
0
    int
spf_check_host( struct spf *s, const yastr domain )
{
    int			    i, j, rc, qualifier, ret = SPF_RESULT_NONE;
    struct dnsr_result	    *dnsr_res, *dnsr_res_mech = NULL;
    struct dnsr_string      *txt;
    yastr		    record = NULL, redirect = NULL, domain_spec, tmp;
    size_t		    tok_count = 0;
    yastr		    *split = NULL;
    char		    *p;
    unsigned long	    cidr, cidr6;
    int			    mech_queries = 0;

    /* RFC 7208 3.1 DNS Resource Records
     * SPF records MUST be published as a DNS TXT (type 16) Resource Record
     * (RR) [RFC1035] only.
     */
    if (( dnsr_res = get_txt( domain )) == NULL ) {
	syslog( LOG_WARNING, "SPF %s [%s]: TXT lookup %s failed",
		s->spf_domain, domain, domain );
	return( SPF_RESULT_TEMPERROR );
    }

    for ( i = 0 ; i < dnsr_res->r_ancount ; i++ ) {
	if ( dnsr_res->r_answer[ i ].rr_type == DNSR_TYPE_TXT ) {
	    txt = dnsr_res->r_answer[ i ].rr_txt.txt_data;
	    /* RFC 7208 4.5 Selecting Records
	     * Starting with the set of records that were returned by the
	     * lookup, discard records that do not begin with a version section
	     * of exactly "v=spf1".  Note that the version section is
	     * terminated by either an SP character or the end of the record.
	     */
	    if (( strncasecmp( txt->s_string, "v=spf1", 6 ) == 0 ) &&
		    (( txt->s_string[ 6 ] == ' ' ) ||
		    ( txt->s_string[ 6 ] == '\0' ))) {
		if ( record != NULL ) {
		    /* RFC 7208 3.2 Multiple DNS Records
		     * A domain name MUST NOT have multiple records that would
		     * cause an authorization check to select more than one
		     * record.
		     */
		    syslog( LOG_ERR,
			    "SPF %s [%s]: multiple v=spf1 records found",
			    s->spf_domain, domain );
		    ret = SPF_RESULT_PERMERROR;
		    goto cleanup;
		}
		record = yaslempty( );
		/* RFC 7208 3.3 Multiple Strings in a Single DNS Record
		 * If a published record contains multiple character-strings,
		 * then the record MUST be treated as if those strings are
		 * concatenated together without adding spaces.
		 */
		for ( ; txt != NULL ; txt = txt->s_next ) {
		    record = yaslcat( record, txt->s_string );
		}
	    }
	}
    }

    if ( record == NULL ) {
	simta_debuglog( 1, "SPF %s [%s]: no SPF record found",
		s->spf_domain, domain );
	goto cleanup;
    }

    simta_debuglog( 2, "SPF %s [%s]: record: %s", s->spf_domain, domain, record );

    split = yaslsplitlen( record, yasllen( record ), " ", 1, &tok_count );

    /* Start at 1, 0 is v=spf1 */
    for ( i = 1 ; i < tok_count ; i++ ) {
	/* multiple spaces in a record will result in empty elements */
	if ( yasllen( split[ i ] ) == 0 ) {
	    continue;
	}


	/* RFC 7208 4.6.4 DNS Lookup Limits
	 * Some mechanisms and modifiers (collectively, "terms") cause DNS
	 * queries at the time of evaluation [...] SPF implementations MUST
	 * limit the total number of those terms to 10 during SPF evaluation,
	 * to avoid unreasonable load on the DNS.  If this limit is exceeded,
	 * the implementation MUST return "permerror".
	 */
	/* In real life strictly enforcing a limit of ten will break SPF
	 * evaluation of multiple major domains, so we use a higher limit.
	 */
	if ( s->spf_queries > 25 ) {
	    syslog( LOG_WARNING, "SPF %s [%s]: DNS lookup limit exceeded",
		    s->spf_domain, domain );
	    ret = SPF_RESULT_PERMERROR;
	    goto cleanup;
	}

	/* RFC 7208 4.6.2 Mechanisms
	 * The possible qualifiers, and the results they cause check_host() to
	 * return, are as follows:
	 *
	 * "+" pass
	 * "-" fail
	 * "~" softfail
	 * "?" neutral
	 *
	 * The qualifier is optional and defaults to "+".
	 */
	switch ( *split[ i ] ) {
	case '+':
	    qualifier = SPF_RESULT_PASS;
	    yaslrange( split[ i ], 1, -1 );
	    break;
	case '-':
	    qualifier = SPF_RESULT_FAIL;
	    yaslrange( split[ i ], 1, -1 );
	    break;
	case '~':
	    qualifier = SPF_RESULT_SOFTFAIL;
	    yaslrange( split[ i ], 1, -1 );
	    break;
	case '?':
	    qualifier = SPF_RESULT_NEUTRAL;
	    yaslrange( split[ i ], 1, -1 );
	    break;
	default:
	    qualifier = SPF_RESULT_PASS;
	    break;
	}

	if ( strncasecmp( split[ i ], "redirect=", 9 ) == 0 ) {
	    s->spf_queries++;
	    redirect = split[ i ];
	    yaslrange( redirect, 9, -1 );
	    simta_debuglog( 2, "SPF %s [%s]: redirect to %s",
		    s->spf_domain, domain, redirect );

	/* RFC 7208 5.1 "all"
	 * The "all" mechanism is a test that always matches.
	 */
	} else if ( strcasecmp( split[ i ], "all" ) == 0 ) {
	    simta_debuglog( 2, "SPF %s [%s]: matched all: %s",
		    s->spf_domain, domain, spf_result_str( qualifier ));
	    ret = qualifier;
	    goto cleanup;

	/* RFC 7208 5.2 "include"
	 * The "include" mechanism triggers a recursive evaluation of
	 * check_host().
	 */
	} else if ( strncasecmp( split[ i ], "include:", 8 ) == 0 ) {
	    s->spf_queries++;
	    yaslrange( split[ i ], 8, -1 );
	    simta_debuglog( 2, "SPF %s [%s]: include %s",
		    s->spf_domain, domain, split[ i ] );
	    rc = spf_check_host( s, split[ i ] );
	    switch ( rc ) {
	    case SPF_RESULT_NONE:
		ret = SPF_RESULT_PERMERROR;
		goto cleanup;
	    case SPF_RESULT_PASS:
		ret = qualifier;
		goto cleanup;
	    case SPF_RESULT_TEMPERROR:
	    case SPF_RESULT_PERMERROR:
		ret = rc;
		goto cleanup;
	    }

	/* RFC 7208 5.3 "a" */
	} else if (( strcasecmp( split[ i ], "a" ) == 0 ) ||
		( strncasecmp( split[ i ], "a:", 2 ) == 0 ) ||
		( strncasecmp( split[ i ], "a/", 2 ) == 0 )) {
	    s->spf_queries++;
	    yaslrange( split[ i ], 1, -1 );

	    if (( domain_spec = spf_parse_domainspec_cidr( s, domain,
		    split[ i ], &cidr, &cidr6 )) == NULL ) {
		/* Macro expansion failed, probably a syntax problem. */
		ret = SPF_RESULT_PERMERROR;
		goto cleanup;
	    }

	    rc = spf_check_a( s, domain, cidr, cidr6, domain_spec );

	    switch( rc ) {
	    case SPF_RESULT_PASS:
		simta_debuglog( 2, "SPF %s [%s]: matched a %s/%ld/%ld: %s",
			s->spf_domain, domain, domain_spec, cidr, cidr6,
			spf_result_str( qualifier ));
		yaslfree( domain_spec );
		ret = qualifier;
		goto cleanup;
	    case SPF_RESULT_TEMPERROR:
		yaslfree( domain_spec );
		ret = rc;
		goto cleanup;
	    default:
		break;
	    }

	    yaslfree( domain_spec );

	/* RFC 7208 5.4 "mx" */
	} else if (( strcasecmp( split[ i ], "mx" ) == 0 ) ||
		( strncasecmp( split[ i ], "mx:", 3 ) == 0 ) ||
		( strncasecmp( split[ i ], "mx/", 3 ) == 0 )) {
	    s->spf_queries++;
	    mech_queries = 0;
	    yaslrange( split[ i ], 2, -1 );

	    if (( domain_spec = spf_parse_domainspec_cidr( s, domain,
		    split[ i ], &cidr, &cidr6 )) == NULL ) {
		/* Macro expansion failed, probably a syntax problem. */
		ret = SPF_RESULT_PERMERROR;
		goto cleanup;
	    }

	    if (( dnsr_res_mech = get_mx( domain_spec )) == NULL ) {
		syslog( LOG_WARNING, "SPF %s [%s]: MX lookup %s failed",
			s->spf_domain, domain, domain_spec );
		yaslfree( domain_spec );
		ret = SPF_RESULT_TEMPERROR;
		goto cleanup;
	    }

	    for ( j = 0 ; j < dnsr_res_mech->r_ancount ; j++ ) {
		if ( dnsr_res_mech->r_answer[ j ].rr_type == DNSR_TYPE_MX ) {
		    /* RFC 7208 4.6.4 DNS Lookup Limits
		     * When evaluating the "mx" mechanism, the number of "MX"
		     * resource records queried is included in the overall
		     * limit of 10 mechanisms/modifiers that cause DNS lookups
		     */
		    s->spf_queries++;
		    rc = spf_check_a( s, domain, cidr, cidr6,
			    dnsr_res_mech->r_answer[ j ].rr_mx.mx_exchange );
		    switch( rc ) {
		    case SPF_RESULT_PASS:
			simta_debuglog( 2,
				"SPF %s [%s]: matched mx %s/%ld/%ld: %s",
				s->spf_domain, domain, domain_spec, cidr, cidr6,
				spf_result_str( qualifier ));
			ret = qualifier;
			dnsr_free_result( dnsr_res_mech );
			yaslfree( domain_spec );
			goto cleanup;
		    case SPF_RESULT_PERMERROR:
		    case SPF_RESULT_TEMPERROR:
			ret = rc;
			dnsr_free_result( dnsr_res_mech );
			yaslfree( domain_spec );
			goto cleanup;
		    default:
			break;
		    }
		}
	    }

	    dnsr_free_result( dnsr_res_mech );
	    yaslfree( domain_spec );

	/* RFC 7208 5.5 "ptr" (do not use) */
	} else if (( strcasecmp( split[ i ], "ptr" ) == 0 ) ||
		( strncasecmp( split[ i ], "ptr:", 4 ) == 0 )) {
	    s->spf_queries++;
	    mech_queries = 0;
	    if (( dnsr_res_mech = get_ptr( s->spf_sockaddr )) == NULL ) {
		/* RFC 7208 5.5 "ptr" (do not use )
		 * If a DNS error occurs while doing the PTR RR lookup,
		 * then this mechanism fails to match.
		 */
		continue;
	    }

	    if ( dnsr_res_mech->r_ancount == 0 ) {
		dnsr_free_result( dnsr_res_mech );
		continue;
	    }

	    if ( split[ i ][ 3 ] == ':' ) {
		domain_spec = yaslnew(( split[ i ] + 4 ),
			( yasllen( split[ i ] ) - 4 ));
	    } else {
		domain_spec = yasldup( domain );
	    }

	    for ( j = 0 ; j < dnsr_res_mech->r_ancount ; j++ ) {
		if ( dnsr_res_mech->r_answer[ j ].rr_type != DNSR_TYPE_PTR ) {
		    continue;
		}
		/* We only care if it's a pass; like the initial PTR query,
		 * DNS errors are treated as a non-match rather than an error.
		 */
		/* RFC 7208 4.6.4 DNS Lookup Limits
		 * the evaluation of each "PTR" record MUST NOT result in
		 * querying more than 10 address records -- either "A" or
		 * "AAAA" resource records.  If this limit is exceeded, all
		 * records  other than the first 10 MUST be ignored.
		 */
		if (( mech_queries++ < 10 ) && ( spf_check_a( s, domain, 32,
			128, dnsr_res_mech->r_answer[ j ].rr_dn.dn_name ) ==
			SPF_RESULT_PASS )) {
		    tmp = yaslauto(
			    dnsr_res_mech->r_answer[ j ].rr_dn.dn_name );
		    while (( yasllen( tmp ) > yasllen( domain_spec )) &&
			    ( p = strchr( tmp, '.' ))) {
			yaslrange( tmp, ( p - tmp + 1 ), -1 );
		    }
		    rc = strcasecmp( tmp, domain_spec );
		    yaslfree( tmp );
		    if ( rc == 0 ) {
			simta_debuglog( 2,
				"SPF %s [%s]: matched ptr %s (%s): %s",
				s->spf_domain, domain, domain_spec,
				dnsr_res_mech->r_answer[ j ].rr_dn.dn_name,
				spf_result_str( qualifier ));
			ret = qualifier;
			yaslfree( domain_spec );
			dnsr_free_result( dnsr_res_mech );
			goto cleanup;
		    }
		}
	    }

	    yaslfree( domain_spec );
	    dnsr_free_result( dnsr_res_mech );

	/* RFC 7208 5.6 "ip4" and "ip6"
	 * These mechanisms test whether <ip> is contained within a given
	 * IP network.
	 */
	} else if ( strncasecmp( split[ i ], "ip4:", 4 ) == 0 ) {
	    if ( s->spf_sockaddr->sa_family != AF_INET ) {
		continue;
	    }

	    yaslrange( split[ i ], 4, -1 );
	    if (( p = strchr( split[ i ], '/' )) != NULL ) {
		errno = 0;
		cidr = strtoul( p + 1, NULL, 10 );
		if ( errno ) {
		    syslog( LOG_WARNING,
			    "SPF %s [%s]: failed parsing CIDR mask %s: %m",
			    s->spf_domain, domain, p + 1 );
		    ret = SPF_RESULT_PERMERROR;
		    goto cleanup;
		}
		if ( cidr > 32 ) {
		    syslog( LOG_WARNING, "SPF %s [%s]: invalid CIDR mask: %ld",
			    s->spf_domain, domain, cidr );
		    ret = SPF_RESULT_PERMERROR;
		    goto cleanup;
		}
		yaslrange( split[ i ], 0, p - split[ i ] - 1 );
	    } else {
		cidr = 32;
	    }

	    if (( rc = simta_cidr_compare( cidr, s->spf_sockaddr, NULL,
		    split[ i ] )) < 0 ) {
		syslog( LOG_WARNING,
			"SPF %s [%s]: simta_cidr_compare failed for %s",
			s->spf_domain, domain, split[ i ] );
		ret = SPF_RESULT_PERMERROR;
		goto cleanup;
	    } else if ( rc == 0 ) {
		simta_debuglog( 2, "SPF %s [%s]: matched ip4 %s/%ld: %s",
			s->spf_domain, domain, split[ i ], cidr,
			spf_result_str( qualifier ));
		ret = qualifier;
		goto cleanup;
	    }

	} else if ( strncasecmp( split[ i ], "ip6:", 4 ) == 0 ) {
	    if ( s->spf_sockaddr->sa_family != AF_INET6 ) {
		continue;
	    }

	    yaslrange( split[ i ], 4, -1 );
	    if (( p = strchr( split[ i ], '/' )) != NULL ) {
		errno = 0;
		cidr = strtoul( p + 1, NULL, 10 );
		if ( errno ) {
		    syslog( LOG_WARNING,
			    "SPF %s [%s]: failed parsing CIDR mask %s: %m",
			    s->spf_domain, domain, p + 1 );
		}
		if ( cidr > 128 ) {
		    syslog( LOG_WARNING, "SPF %s [%s]: invalid CIDR mask: %ld",
			    s->spf_domain, domain, cidr );
		    ret = SPF_RESULT_PERMERROR;
		    goto cleanup;
		}
		yaslrange( split[ i ], 0, p - split[ i ] - 1 );
	    } else {
		cidr = 128;
	    }

	    if (( rc = simta_cidr_compare( cidr, s->spf_sockaddr, NULL,
		    split[ i ] )) < 0 ) {
		syslog( LOG_WARNING,
			"SPF %s [%s]: simta_cidr_compare failed for %s",
			s->spf_domain, domain, split[ i ] );
		ret = SPF_RESULT_PERMERROR;
		goto cleanup;
	    } else if ( rc == 0 ) {
		simta_debuglog( 2, "SPF %s [%s]: matched ip6 %s/%ld: %s",
			s->spf_domain, domain, split[ i ], cidr,
			spf_result_str( qualifier ));
		ret = qualifier;
		goto cleanup;
	    }

	/* RFC 7208 5.7 "exists" */
	} else if ( strncasecmp( split[ i ], "exists:", 7 ) == 0 ) {
	    s->spf_queries++;
	    yaslrange( split[ i ], 7, -1 );
	    if (( domain_spec =
		    spf_macro_expand( s, domain, split[ i ] )) == NULL ) {
		/* Macro expansion failed, probably a syntax problem. */
		ret = SPF_RESULT_PERMERROR;
		goto cleanup;
	    }

	    if (( dnsr_res_mech = get_a( domain_spec )) == NULL ) {
		syslog( LOG_WARNING, "SPF %s [%s]: A lookup %s failed",
			s->spf_domain, domain, domain_spec );
		yaslfree( domain_spec );
		ret = SPF_RESULT_TEMPERROR;
		goto cleanup;
	    }

	    if ( dnsr_res_mech->r_ancount > 0 ) {
		simta_debuglog( 2, "SPF %s [%s]: matched exists %s: %s",
			s->spf_domain, domain, domain_spec,
			spf_result_str( qualifier ));
		dnsr_free_result( dnsr_res_mech );
		yaslfree( domain_spec );
		ret = qualifier;
		goto cleanup;
	    }

	    yaslfree( domain_spec );
	    dnsr_free_result( dnsr_res_mech );

	} else {
	    for ( p = split[ i ] ; isalnum( *p ) ; p++ );

	    if ( *p == '=' ) {
		/* RFC 7208 6 Modifier Definitions
		 * Unrecognized modifiers MUST be ignored
		 */
		simta_debuglog( 1, "SPF %s [%s]: %s unknown modifier %s",
			s->spf_domain, domain, spf_result_str( qualifier ),
			split[ i ] );
	    } else {
		syslog( LOG_WARNING, "SPF %s [%s]: %s unknown mechanism %s",
			s->spf_domain, domain, spf_result_str( qualifier ),
			split[ i ] );
		ret = SPF_RESULT_PERMERROR;
		goto cleanup;
	    }
	}
    }

    if ( redirect != NULL ) {
	if (( domain_spec = spf_macro_expand( s, domain, redirect )) == NULL ) {
	    /* Macro expansion failed, probably a syntax problem. */
	    ret = SPF_RESULT_PERMERROR;
	} else {
	    ret = spf_check_host( s, domain_spec );
	    yaslfree( domain_spec );
	}
	if ( ret == SPF_RESULT_NONE ) {
	    ret = SPF_RESULT_PERMERROR;
	}

    } else {
	/* RFC 7208 4.7 Default Result
	 * If none of the mechanisms match and there is no "redirect" modifier,
	 * then the check_host() returns a result of "neutral", just as if
	 * "?all" were specified as the last directive.
	 */
	ret = SPF_RESULT_NEUTRAL;
	simta_debuglog( 2, "SPF %s [%s]: default result: %s", s->spf_domain,
		domain, spf_result_str( ret ));
    }

cleanup:
    if ( split != NULL ) {
	yaslfreesplitres( split, tok_count );
    }
    yaslfree( record );
    dnsr_free_result( dnsr_res );
    return( ret );
}
Ejemplo n.º 16
0
/*-------------------------------------------------------------------------*/
static bool
add_struct_name (struct_name_t * pSName)

/* Add the struct name <pSName> to the hash table.
 * The <pSName>->hash must already been computed.
 * Returns false on error.
 */

{
     size_t ix;

#ifdef DEBUG
     if (find_by_struct_name(pSName))
         fatal("struct type %s (%s) already in table.\n"
              , get_txt(pSName->name)
              , get_txt(pSName->prog_name)
              );
#endif

     if (!table)
     {
         table = pxalloc(sizeof(*table));
         if (table == NULL)
             return false;

         table_size = 1;
         table[0] = pSName;
         pSName->next = NULL;
         num_types = 1;
         return true;
     }

     ix = pSName->hash & (table_size-1);
     pSName->next = table[ix];
     table[ix] = pSName;

     num_types++;

     /* If chain lengths grow too much (more than 2 entries per bucket
      * on average), increase the table size
      */
     if (num_types > 2 * table_size && table_size * 2 < MAX_HASH32)
     {
         size_t new_size = 2 * table_size;
         struct_name_t ** table2;

         table2 = pxalloc(new_size * sizeof(*table2));
         if (table2)
         {
             memset(table2, 0, new_size * sizeof(*table2));

             /* Rehash all existing entries */
             for (ix = 0; ix < table_size; ix++)
             {
                 struct_name_t * this;

                 while (NULL != (this = table[ix]))
                 {
                     size_t ix2;

                     table[ix] = this->next;
                     ix2 = this->hash & (new_size-1);

                     this->next = table2[ix2];
                     table2[ix2] = this;
                 }
             } /* for() */

             pfree(table);
             table = table2;
             table_size = new_size;
         } /* if (table2) */
         else
             return false;
     } /* if (check for rehash condition) */

     return true;
} /* add_struct_name() */
Ejemplo n.º 17
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() */
Ejemplo n.º 18
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() */
Ejemplo n.º 19
0
svalue_t *
f_convert_charset (svalue_t *sp)

/* EFUN convert_charset()
 *
 *   string convert_charset(string str, string from_cs, string to_cs)
 *
 * Convert the string <str> from charset <from_cs> to charset <to_cs>
 * and return the converted string.
 *
 * The efun is only available on systems with libiconv.
 */

{
    iconv_t context;
    
    string_t *from_cs, *to_cs, *in_str, *out_str;

#if HAS_ICONV_NONCONST_IN
#   define ICONV_IN_CAST (char**)
#else
#   define ICONV_IN_CAST
#endif

    const char *pIn; /* Input string pointer */
    size_t in_len;   /* Input length */
    size_t in_left;  /* Input length left */

    char * out_buf;  /* Output buffer */
    size_t out_size; /* Size of the output buffer */
    size_t out_left; /* Size left in output buffer */
    char  *pOut;     /* Output string pointer */

    in_str = sp[-2].u.str;
    from_cs = sp[-1].u.str;
    to_cs = sp->u.str;

    pIn = get_txt(in_str);
    in_len = mstrsize(in_str);
    in_left = in_len;

    /* If the input string is empty, we can return immediately
     * (and in fact must since the allocator will balk at allocating 0 bytes)
     */
    if (!in_len)
    {
        sp -= 2;
        free_string_svalue(sp);
        free_string_svalue(sp+1);
        put_string(sp, sp[2].u.str);

        return sp;
    }

    /* Allocate a temporary output string */
    out_size = in_len > 65536 ? (in_len + 33) : (2 * in_len);
    out_left = out_size;

    xallocate(out_buf, out_size, "iconv buffer");
    pOut = out_buf;

    /* Open the iconv context */
    context = iconv_open(get_txt(to_cs), get_txt(from_cs));
    if (context == (iconv_t) -1)
    {
        xfree(out_buf);

        if (errno == EINVAL)
            errorf("convert_charset(): Conversion '%s' -> '%s' not supported.\n"
                 , get_txt(from_cs), get_txt(to_cs)
                );
        else
            errorf("convert_charset(): Error %d.\n", errno);
        /* NOTREACHED */
        return sp;
    }

    /* Convert the string, reallocating the output buffer where necessary */
    while (in_left)
    {
        size_t rc;

        rc = iconv(context, ICONV_IN_CAST &pIn, &in_left, &pOut, &out_left);
        if (rc == (size_t)-1)
        {
            if (errno == E2BIG)
            {
                /* Reallocate output buffer */
                size_t newsize;
                char * tmp;

                newsize = out_size + (in_len > 128 ? in_len : 128);
                tmp = rexalloc(out_buf, newsize);
                if (!tmp)
                {
                    iconv_close(context);
                    xfree(out_buf);
                    outofmem(newsize, "iconv buffer");
                    /* NOTREACHED */
                    return sp;
                }
                out_buf = tmp;
                pOut = out_buf + out_size;
                out_left = newsize - out_size;
                out_size = newsize;

                continue;
            }

            /* Other error: clean up */
            iconv_close(context);
            xfree(out_buf);

            if (errno == EILSEQ)
            {
                errorf("convert_charset(): Invalid character sequence at "
                       "index %td\n", 
                       (ptrdiff_t)(pIn - get_txt(in_str)));
                /* NOTREACHED */
                return sp;
            }

            if (errno == EINVAL)
            {
                errorf("convert_charset(): Incomplete character sequence at "
                       "index %td\n", (ptrdiff_t)(pIn - get_txt(in_str)));
                /* NOTREACHED */
                return sp;
            }

            errorf("convert_charset(): Error %d at index %td\n"
                 , errno, (ptrdiff_t)(pIn - get_txt(in_str))
                 );
            /* NOTREACHED */
            return sp;
        } /* if (rc < 0) */
    } /* while (in_left) */

    /* While the actual conversion is complete, the output stream may now
     * be in a non-base state. Add the necessary epilogue to get back
     * to the base state.
     */
    while(1)
    {
        size_t rc;
        rc = iconv(context, NULL, NULL, &pOut, &out_left);
        if (rc == (size_t)-1)
        {
            if (errno == E2BIG)
            {
                /* Reallocate output buffer */
                size_t newsize;
                char * tmp;

                newsize = out_size + (in_len > 128 ? in_len : 128);
                tmp = rexalloc(out_buf, newsize);
                if (!tmp)
                {
                    iconv_close(context);
                    xfree(out_buf);
                    outofmem(newsize, "iconv buffer");
                    /* NOTREACHED */
                    return sp;
                }
                out_buf = tmp;
                pOut = out_buf + out_size;
                out_left = newsize - out_size;
                out_size = newsize;

                continue;
            }

            /* Other error: clean up */
            iconv_close(context);
            xfree(out_buf);

            if (errno == EILSEQ)
            {
                errorf("convert_charset(): Invalid character sequence at "
                       "index %td\n", (ptrdiff_t)(pIn - get_txt(in_str)));
                /* NOTREACHED */
                return sp;
            }

            if (errno == EINVAL)
            {
                errorf("convert_charset(): Incomplete character sequence at "
                       "index %td\n", (ptrdiff_t)(pIn - get_txt(in_str)));
                /* NOTREACHED */
                return sp;
            }

            errorf("convert_charset(): Error %d at index %td\n"
                 , errno, (ptrdiff_t)(pIn - get_txt(in_str))
                 );
            /* NOTREACHED */
            return sp;
        } /* if (rc < 0) */

        /* At this point, the iconv() succeeded: we're done */
        break;
    } /* while(1) */
    
    iconv_close(context);

    /* Get the return string and prepare the return arguments */
    out_str = new_n_mstring(out_buf, out_size - out_left);
    xfree(out_buf);
    if (!out_str)
    {
        outofmem(out_size - out_left, "convert_charset() result");
        /* NOTREACHED */
        return sp;
    }

    free_string_svalue(sp--);
    free_string_svalue(sp--);
    free_string_svalue(sp);
    put_string(sp, out_str);
    
    return sp;
} /* f_convert_charset() */
Ejemplo n.º 20
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() */
Ejemplo n.º 21
0
svalue_t *
f_psyc_render(svalue_t *sp) {
    uint8_t i;
    vector_t *v;
    string_t *out;
    char *meth, *body;
    size_t mlen, blen;
    mapping_t *map;

    psycPacket packet;
    psycHeader headers[2];

    // unless (sp->type == T_POINTER) return sp;
    v = sp->u.vec;
    if (VEC_SIZE(v) == PACKET_BODY + 1) {
	for (i = PACKET_ROUTING; i <= PACKET_ENTITY; i++) {
	    headers[i].lines = 0;
	    if (v->item[i].type == T_MAPPING) {
		map = v->item[i].u.map;
		if (!MAP_SIZE(map)) continue;

		headers[i].modifiers = malloc(sizeof(psycModifier) * MAP_SIZE(v->item[i].u.map));
		if (!headers[i].modifiers) {
		    errorf("Out of memory in psyc_render for modifier table.\n");
		    return sp; // not reached
		}

		walk_mapping(map, &fill_header_from_mapping,
		             &(psyc_modifier_t) {
		                 &headers[i], map->num_values,
		                 i == PACKET_ROUTING ?
		                     PSYC_MODIFIER_ROUTING :
		                     PSYC_MODIFIER_CHECK_LENGTH
		             });
	    }
	    // else ... ignoring possibly invalid args
	}
    } else {
	errorf("Wrong number of elements (%" PRIdMPINT ") "
	       "in array argument to psyc_render()\n", VEC_SIZE(v));
	return sp; // not reached
    }

    if (v->item[PACKET_METHOD].type == T_STRING) {
	meth = get_txt(v->item[PACKET_METHOD].u.str);
	mlen = mstrsize(v->item[PACKET_METHOD].u.str);
    } else {
	meth = NULL;
	mlen = 0;
    }

    if (v->item[PACKET_BODY].type == T_STRING) {
	body = get_txt(v->item[PACKET_BODY].u.str);
	blen = mstrsize(v->item[PACKET_BODY].u.str);
    } else {
	body = NULL;
	blen = 0;
    }

    packet = psyc_newPacket2(headers[PACKET_ROUTING].modifiers,
                             headers[PACKET_ROUTING].lines,
                             headers[PACKET_ENTITY].modifiers,
                             headers[PACKET_ENTITY].lines,
                             meth, mlen, body, blen,
                             PSYC_PACKET_CHECK_LENGTH);

#ifdef DEBUG
    printf("rendering... packet.length = %ld\n", packet.length);
#endif
    // alloc_mstring creates an *untabled* string suitable for tmp data 
    memsafe(out = alloc_mstring(packet.length), packet.length, "f_psyc_render");
    psyc_render(&packet, get_txt(out), packet.length);

    free_svalue(sp);
    put_string(sp, out);
    // stack should take care of freeing the string after use
    return sp;

} /* f_psyc_render */