Subject: bf experimenting

From: Quinn Avery <[email-masked]>
Date: Sun, 21 Nov 1993 20:10:00 -0800

Here's my stab at a builtin function.  I'd appreciate any warnings
 and programmatical suggestions.  Particularly, I wanna know if it'll
 cause any memory leaks or other terrible things.

static package
bf_fill(Var arglist, Byte next, void *vdata, Objid progr)
{   Var         r;
    char        *string, *filled, *str;
    char        filler = ' ';
    int         i, l, s, a, width;
 
 /* fill(string, width[, filler]) */
 /* Pad the given string to `width' characters. */
 /* If width is negative, right justify, else flush to the left. */
 /* `filler' defaults to a space. */
 
    string = arglist.v.list[1].v.str;
    width = arglist.v.list[2].v.num;
 
    if (arglist.v.list[0].v.num == 3)
      filler = *arglist.v.list[3].v.str;
 
    free_var(arglist);
 
    if (width == 0)
      return make_error_pack(E_INVARG);
 
    a = ((width < 0) ? -width : width);
 
    /* prevent failed malloc crashes */
    if (a > 1024)
      return make_error_pack(E_RANGE);
 
    s = strlen(string);
 
    if ((l = a - s) < 0) {
      r.type = TYPE_STR;
      r.v.str = string;
      return make_var_pack(substr(r, 1, a)); }
 
    filled = mymalloc(a * sizeof(char), M_STRING);
 
    for (i = 0; i < l; i++)
      filled[i] = filler;
 
    filled[a] = '\0';
 
    str = mymalloc((s + l + 1) * sizeof(char), M_STRING);
 
    if (width < 0)
      sprintf(str, "%s%s", filled, string);
    else
      sprintf(str, "%s%s", string, filled);
 
    str[s + l + 1] = '\0';
    r.type = TYPE_STR;
    r.v.str = str;
 
    return make_var_pack(r); }
..
    (void) register_function("fill", 2, 3, bf_fill, TYPE_STR, TYPE_NUM, TYPE_STR);

Also-- How and when is free_var to be called?  Should I free all my
 variables?  Should the above code work right?  It seems to include
 garbage in the returned string sometimes.

Has anyone written any server mods and put them out for ftp?  I'd like
 to learn by example.  Interested in an iassoc() hack.

Thanks for anything..

-quinn

---

From: Pavel Curtis <[email-masked]>
Date: Mon, 22 Nov 1993 10:29:56 -0800

> Date:	Sun, 21 Nov 1993 20:10:00 -0800
> From:	Quinn Avery <[email-masked]>
> 
> static package

You can't free arglist yet, since you're still using parts of it (the storage
for `string').  You should either bump the reference count for that part (by
saying `string = var_ref(arglist.v.list[1]).v.str;' above) or hold off freeing
arglist until later.  I recommend the former course.

>       return make_error_pack(E_RANGE);

This comment is, of course, wrong, since any allocation request at all could be
one to fail.  The style of the rest of the language is not to impose artificial
limits on the lengths of strings, lists, etc., so I'd remove this line.

>       return make_var_pack(substr(r, 1, a)); }

You would need a free_var(r) here after the call to substr() to avoid leaking
`string', assuming you did the `var_ref' call above.

>     filled = mymalloc(a * sizeof(char), M_STRING);

This is off by one; you need space for a null byte at the end of the string.
Remember, `l' could be equal to `a'.  Actually, though, you want `l + 1' here,
not `a' at all.

>     filled[a] = '\0';

This is the line that stores into the extra byte you didn't allocate.  In any
case, based upon what happens later, you want `filled[l]' here, anyway.

>     str = mymalloc((s + l + 1) * sizeof(char), M_STRING);

The sum here could be more simply written as `a + 1'.  Also, it's a shame that
you're allocating two strings when one would do.

>     (void) register_function("fill", 2, 3, bf_fill, TYPE_STR, TYPE_NUM, TYPE_STR);

Finally, I have to say that I wouldn't bother making this function into a
built-in, since it almost certainly isn't where the majority of any task's time
is going.  Even if it were, I'd make the built-in out of $string_utils:space
instead, since that's a much more generally-useful primitive in terms of which
this function could efficiently be written.

>  garbage in the returned string sometimes.

You want to call `free_var' whenever you're certain that you're done with some
reference to a MOO value.  Similarly, you want to call `var_ref' whenever you
want to `create' another, independent reference to such a value.  These two
functions manipulate the reference counts for strings and lists, freeing the
storage for them (and, in the case of lists, free_var-ing the elements) when
and if the reference count goes to zero.

>  to learn by example.  Interested in an iassoc() hack.

Release 1.8.0 will contain, finally, mechanisms whereby MOO programmers can
figure out just where all of the time/ticks are being spent in their code, so
that people can finally have some real information concerning which MOO verbs
could profitably be made into built-in functions.  My guess is that iassoc()
isn't such a candidate, but we shall (finally) see.

	Pavel