The U Programming Language





Introduction.

     The U programming language (hereafter  referred  to  as
simply U) is a simple language reminiscent of C or awk. This
document is intended as a 'quick start' guide, rather than a
formal  language  definition,  since it is expected that the
language will be constantly changing and evolving.

1.  Hello World

     The primary means of sending text output  to  a  user's
terminal  in  U  is  via  the  echo command and its relative
echoto. Echo echoes its arguments back to the  caller,  per-
forming  type  conversion  on  numeric  values,  etc. C-like
escape sequences are recognized:

echo("hello world!\n");

will print "hello world!" followed by a newline.  Unlike  C,
there is no need for a main() function to call. Commands can
be executed inside or outside of a function.

echo("two plus two = ",2 + 2);

will print "two plus two =  4",  with  echo  converting  the
numeric  value generated by the arithmetic expression into a
text string automatically.  echo places no reasonable  limit
on  the number of parameters that can be passed to it in one
call; everything is printed in order, left to right.

2.  Variables

2.1.  Variable Types and Data Types

     Variables in U can be of several types. The interpreter
hides the details of the types from the user to the greatest
possible extent.  Currently, the existing types are as  fol-
lows:

o+ Numbers - the basic numeric type in U is the  integer.  In
fact,  there  is  no provision for floating point numbers at
all. Typical numerical operations such as  division,  multi-
plication, addition &c can be performed on numbers.

o+ Strings - the string type in U is a simple chunk of  text,



                       June 22, 1990





U Programming Language


with  the interpreter handling storage allocation (unlike C)
for the programmer. Numeric operations are NOT permitted  on
strings, with the exception of the equality operator.

o+ NULL - the data value NULL in U is a special data type  of
its  own.  Unlike C, it does not mean zero - it means nonex-
istence.  NULL is provided for many reasons, primarily being
error  checking,  and  to provide a fixed 'magic' value that
programmers can use.  Many of U's internal operators  return
NULL in the event of an error, or invalid argument. In real-
ity there is an error value that can be  attached  to  NULL,
and  accessed  by  the  user,  allowing  a user to determine
exactly why their operation resulted in a NULL. Examples  of
operations  that  can  result  in  NULL  are: calling a non-
function as if it were a function, attempting  to  access  a
non-existent  variable,  and  attempting  to  use a function
parameter that was not passed to a function.

o+ Objects - an object in U is a  numbered  entity  to  which
smaller  variables (called elements) can be bound. It is the
basic "star stuff" of a Ubermud universe. Objects are always
referred to by number, preceded with a sharp, or '#' symbol.
There is a special object - the system object, which can  be
abbreviated  with  the '@' symbol. This is always object #0,
but using the '@' syntax is preferred, since it is clearer.

o+ Lists - a list is an array of object  numbers.  There  are
functions  that  manipulate, search, add to, and delete from
lists. The list is used heavily in implementing a  universe,
since  lists  contain contents of rooms, player inventories,
and so forth. There is no heterogenous array type in U  (due
to  the  complexity  of  implementing it), so lists may only
consist of object numbers. This is less of a  drawback  than
it may seem, since arrays of strings can easily be gotten at
indirectly through the object number.

o+ Functions - a function or procedure is actually a  primary
data type in U. This permits assigning of functions to vari-
ables, and calling the function through that variable.  This
can  lead  to  confusing or very powerful code, depending on
how wisely it is used. There are some  restrictions  on  the
use  of  functions and their declaration, that are discussed
later. Functions can be passed as parameters to other  func-
tions,  assigned  to  temporary  variables,  or  assigned to
object elements,  which  are  described  in  greater  detail
later.

2.2.  Temporary Variables

     In U, a temporary variable can be used to  store  vola-
tile  information.  The temporary disappears after the func-
tion that it is in is terminated.  The  advantages  of  tem-
poraries is that they are quick and allocation and dealloca-
tion of  them  is  handled  by  the  system.  Due  to  their



                       June 22, 1990





Copyright, Marcus J. Ranum, 1990


ephemeral  nature,  however,  they cannot be used outside of
functions, without disappearing immediately. Temporaries CAN
be  made  to  last  outside  of  functions  by enclosing the
desired block of code in curly braces:

{
        $tmp = strtime();
        echo("$tmp is:",$tmp,"\n");
}

Here $tmp is set to whatever the function strtime returns (a
string  form  of  the  system clock), and is later handed to
echo for printing.

2.3.  Function Parameters

     In U, a function can be passed an arbitrary  number  of
parameters.   Unlike  C, where the parameters are named, the
parameters in a U function are accessed with  $-number  syn-
tax, similar to the Bourne shell's. A second function param-
eter variable $# contains the parameter  count  (zero  being
none).  This  allows  a  function  to  access its parameters
without having to name or type variables:

func @.foo
{
        if($# > 0)
                echo("the first parameter is \"",$1,"\"\n");
}

@.foo("bar!");

Here a function  is  called  with  one  parameter.  A  check
against  the  parameter  count  is  made,  and if there is a
parameter, the first one is printed. The example above  pro-
duces the following output:

the first parameter is "bar!"

note the escaped quotes preceded by the '\' character in the
parameters to echo.

     It is forbidden to use the parameter variables  outside
a  function;  attempting  to do so will abort compilation of
the program at that point.

2.4.  Elements

     The element is the most important type of  variable  in
U,  and  will  be gone into in greater depth later. Elements
are formed of an object number, and the name of  a  variable
stored  in  that  object.   An object can have any number of
elements stored in it, provided they are all uniquely named.
Some examples of elements are:



                       June 22, 1990





U Programming Language


        #44.foo;
        @.fuzzy;
        #55.this.that;

The @.fuzzy syntax is an example of using '@' to specify the
system  object. It could be written as #0.fuzzy as well.  In
the case of #55.this.that, there is a level  of  indirection
added.  When  the value is presented to the interpreter, the
interpreter will first check the contents  of  #55.this.  If
#55.this is itself an object number, it will then search the
contents of that object for variable name that. This can  be
done  to  any number of levels, though there will not likely
be need for more than one or two levels of indirection. If a
variable  in an indirection is not an object number, or does
not exist, then a "badly formed object specifier"  error  is
generated. For example:

        #55.foo = 666;
        #44.bar = #55;
        echo("indirecting:",#44.bar.foo,"\n");

Will print:

        indirecting:666

Since the object number #55 is stored in #44.bar,  which  is
looked  up  first, reducing #44.bar.foo to #55.foo, which is
in turn looked up, giving the number 666.

     An element can be a value of the type  of  any  of  the
data  types permitted in U. Elements are treated essentially
as variables in expressions:

        #44.foo = 12;
        $tmp = 2;
        #55.bar = #44.foo * $tmp;

But they can just as easily be treated as functions:

        #33.bar("this is a test\n");

        $tmp = #33.bar;
        $tmp("this is a test\n");

In both of  the  examples  above,  the  function  stored  in
#33.bar is called with the message: "this is a test\n".

2.5.  Accessing Elements Via Strings

     Elements can be accessed by coercing a string into  the
name  of  an  object's element. This is done by providing an
arbitrary expression which returns a string  in  the  object
element specifier:




                       June 22, 1990





Copyright, Marcus J. Ranum, 1990


        #33.("foo") = 55;

The program above would convert the string value "foo"  into
an element name and search #33 for it. Parenthesized expres-
sions can be mixed at will with other element names:

        #33.foo.("bar") = 55;
        $array = 1;
        echo(#33.(str("foo",$array)));

In the examples above, #33.foo.bar would be set to  55,  and
in  the second #33.foo1 would be echoed. Note that there are
some restrictions on string to variable coercion.  The  max-
imum  length  of  an  element  name is less than the maximum
length of a string, and attempts to coerce a  name  that  is
too  long  will  automatically set the value to NULL. If the
expression fails to return a string, the element name forma-
tion fails, and the value is set to NULL.

     While string-to-variable coercion is a  powerful  func-
tion,  it is also an indicator of a failing in the design of
the language  that  encompasses  it.   In  the  case  of  U,
string-to-variable  coercion  is  incorporated to get around
the lack of support for heterogenous arrays. Programmers are
urged  to  use  string-to-variable coercion sparingly, if at
all, and primarly to use it as a means of  examining  things
from the command line.

2.6.  Making Elements Go Away

     Elements attached  to  an  object  can  be  de-assigned
(annihilated)  by  assigning  them to NULL. This frees their
storage in the database, and removes them  from  the  index.
Objects  themselves  cannot  be  destroyed  in  this  simple
manner.

3.  Functions

3.1.  Basics of Functions

     A U function is similar to a C function in that it  can
take  a  list  of  parameters of varying types, and return a
single value. Unlike C, U does not have a notion of pointers
as parameters, so it is difficult for a U function to modify
something passed as a parameter.  Furthermore, unlike  C,  U
functions cannot modify the values of their numbered parame-
ters. Assignments to $1-N or $# are syntax errors, and abort
compilation. Functions that do not explicitly return a value
return NULL(function returned no value) to  the  caller,  if
the value of the function is taken. Functions can return any
legitimate U data type, including other functions.






                       June 22, 1990





U Programming Language


3.2.  Declaring a Function

     A function is declared in the form of:

func #object-number . name
{
        statements;
}

The object-number may be '@',  if  the  function  is  to  be
attached  to the system object, but otherwise it must be the
number of an existing object that the programmer has permis-
sion  to write to. The curly braces are optional, and may be
omitted if the function is a  single  statement.  Take  this
simple function:

func #33.days
{
        $tmp = $1 * 24 * 60 * 60;
        echo("in ",$1," days, it will be ",strtime($tmp),"\n");
}

which prints what it will be in a number of days  passed  to
the  function as a parameter. Obviously, the function should
check for the existence of a parameter,  since  $1  will  be
NULL if it was called with no parameters.

3.3.  Returning From a Function

     In the example of #33.days above, the  function  "drops
off the end" of the code. This causes the function to return
to the caller, and leaves the value  NULL  for  the  calling
function  to  access, should it so desire.  A specific value
can be returned to the caller using the return operator,  or
NULL  can  be specifically returned to indicate an error. To
simplify this instance, the  return  operator  can  be  used
without a value, implicitly returning NULL.

func #33.bad
{
        if($# != 3) {
                echo("three arguments expected!\n");
                return;
        }
        return($1 + $2 + $3);
}

echo(#33.bad(4,5),"\n");

echo(#33.bad(4,5,6),"\n");

This overly simplistic example checks  its  argument  count,
and returns its parameters added together. In the first case
where it is called above  with  two  parameters,  the  error



                       June 22, 1990





Copyright, Marcus J. Ranum, 1990


message  will  be  printed,  and NULL will be returned. echo
quietly refuses to print NULL (since NULL does  not  exist),
so  there would be be a newline printed, but no other output
than the error message.  In the second  call,  the  function
returns  15,  which  is passed to echo, and is printed, with
the newline.

4.  Conditionals

     U's conditionals are the if and else syntax so familiar
to C programmers. Conditionals take the form of:

if ( expression )
        statements;

if ( expression )
        statements1;
else
        statements2;

The expression can be any legal U expression. If the expres-
sion  evaluates to a non-empty string, or a non-zero numeric
value, the statement following is executed. In  the  if-else
syntax,  the  second  set  of statements are executed in the
case that the condition of the first failed. U  has  the  C-
like  boolean  operators  '&&' and '||', and and or, respec-
tively. As in C, if statements can be cascaded and nested.

     One crucial difference exists between C and U if state-
ments:  unlike  in C, all the clauses in the conditional are
evaluated (C stops when the condition is manifestly true  or
false). Thus:

if(foo() && bar()) {
        ...
}

will evaluate foo() and bar() both, while in C,  bar()  will
never be called if foo() returns 0.

5.  For Statements

5.1.  Problems With For Statements, While Loops, and  Recur-
sion

     U does not have C-like for and while  statments,  since
they permit a programmer to write code that loops eternally.
This is intolerable in a multi-user game, and, in fact, they
turn  out  to  be  unnecessary. Another problem is recursive
functions, or functions that call each other endlessly  back
and forth. The U interpreter handles these simply by permit-
ting recursion until the reasonably large internal stack  is
overflowed,  and  then returning NULL when any further func-
tion  calls  are  attempted.  This  effectively  halts   the



                       June 22, 1990





U Programming Language


recursion,  causing  it  to  "unwind" itself normally. Obvi-
ously, a function that recursively generates a  huge  amount
of  text  output  will  still be a tremendous annoyance, but
controlling such things cannot be done within the software.

5.2.  Syntax of For Statements

     Since a MUD deals primarily with lists of things, U has
syntax for iterating across lists, and across the parameters
to a function. The syntax of for loops takes two forms:

        for $tmp in ( expression-returning a list)
                statements;

        foreacharg $tmp
                statements;

In the first case, the temporary variable  $tmp  is  succes-
sively  set  to each element number for every element on the
list. If the expression fails to return a list,  or  returns
an  empty  list,  the statements are not executed at all. In
the foreacharg loop, the value of $tmp is  successively  set
to  each  parameter  that  the  function  was  called  with.
foreacharg cannot be used outside of a function, as this  is
a syntax error. In the following example:

        #11.str = "string 1";
        #22.str = "string 2";
        #33.str = "string 3";
        #33.list = listnew(#11,#22,#33);

        foreach $tmp in (#33.list) {
                echo($tmp,".str is:",$tmp.str);
        }

This creates a list containing the object numbers #11,  #22,
and  #33,  and  iterates  across the list, printing (succes-
sively) the values of #11.str, #22.str, and #33.str. In  the
next example:

func #33.bar
{
        $cnt = 0;
        foreacharg $tmp {
                $cnt = $cnt + 1;
                echo("parameter ",$cnt,"=",$tmp,"\n");
        }
        echo("total parameters:",$cnt,"\n");
}

#33.bar(4,"foo",strtime());

The following is printed:




                       June 22, 1990





Copyright, Marcus J. Ranum, 1990


parameter 1=4
parameter 2=foo
parameter 3=Fri May 11 16:24:21 EDT 1990
total parameters:3


6.  References

6.1.  Generating References

     U stores all objects and  object  elements  except  for
those  in the system table (#0) in a database with an index.
A reference is used in U to make two or more  index  entries
that  "point"  at the same basic object. This allows objects
that wish to share the same element values to do it  easily,
and  provides  performance  advantages  as  well  as  saving
storage space. Additionally, references  are  used  in  some
internal  built-in functions to manipulate index entries for
permissions and ownership purposes. A reference to an object
element  is generated by placing and ampersand '&' character
before the name of the element. EG:

        &#33.foo;
        &$tmp.foo;
        &#44.bar.baz;
        &@.froz;

All of these are examples of legal  references.  It  is  not
legal  syntax  to take a reference of anything but an object
element. IE:

        !
        &$tmp;
        &@;

are all  illegal  references,  producing  syntax  errors  at
compile-time.

6.2.  Assigning to References

     When an assignment is made to a reference,  instead  of
saving a copy of the data, a pointer to the copy of the data
is saved. It must be emphasized that this is NOT  a  perfor-
mance  expensive  operation,  rather  the  contrary. For all
intents and purposes, a referenced  object  is  exactly  the
same  as any other stored object. When an assignment is made
to a referenced element, the contents of the  reference  are
NOT overwritten, the reference is broken, and new storage is
allocated for the assigned element. For example:

        #33.foo = "foo!";
        #44.foop = &#33.foo;
        echo(#33.foo,#44.foop,"\n");




                       June 22, 1990





U Programming Language


        #44.foop = "bar!";
        echo(#33.foo,#44.foop,"\n");

The first time echo prints: "foo!foo!" followed  by  a  new-
line.  The second call to echo prints "foo!bar!" followed by
a newline. In certain cases it may be desirable to change to
contents  of  a reference. This can be done by prefixing the
assignment operator with an asterisk. This causes  the  con-
tents  of  the  reference  to be set, changing the value for
every element that "points" to it.

        #33.foo = "foo!";
        #44.foop = &#33.foo;
        echo(#33.foo,#44.foop,"\n");

        *#44.foop = "bar!";
        echo(#33.foo,#44.foop,"\n");

As in the previous example, the first call  to  echo  prints
"foo!foo!" and the newline. The second prints "bar!bar!" and
the newline. This can be invaluable for implementing objects
that change their appearance globally, but a programmer does
not want to have to maintain individually, such as a  desti-
nation list for a teleporter system.

6.3.  Restrictions on References

     It is illegal to make a reference to object elements in
#0,  the  system  object.  This is because the entire system
object is stored only in main memory, not on disk (it is the
repository of that which must be fast). Thus, a reference to
something in #0 would become "stale" as soon as  the  server
was shut down. Assigning the contents of a reference to NULL
is a special case, and causes only  that  one  link  to  the
referenced object to be broken. This is due to the fact that
there is no idea how many object elements  actually  "point"
to that referenced element.

7.  Run-Time User Contexts

7.1.  User-Id and Effective User-Id

     When a U program is executing, there are  several  spe-
cial values attached to the running program. Primarily these
consist of the user-id  and  the  effective  user-id.  These
values  are  used  as the basis for all permissions in U. At
any time when a player is connected to the  U-server,  their
login  has a user-id associated with it. Typically this will
be the object number of their 'self' in the game (though  it
need  not  be).   The effective user-id is almost always the
same as the user-id, but it can  be  changed  under  certain
circumstances (see Setuid Function below) or if the person's
connection is flagged with a "Wizard Bit"  in  the  password
file. In the case of a connection with the "Wizard Bit" set,



                       June 22, 1990





Copyright, Marcus J. Ranum, 1990


the players user-id will be their object number,  but  their
effective  user-id  will be that of #0, the Creator, who has
absolute power over all things in the universe. At  runtime,
built-in  functions  may  also alter a connections effective
user-id, though it is impossible to alter the  user-id,  and
for good reason, since the user-id determines where any tex-
tual output intended for a  player  should  go.  Should  two
objects  somehow share the same user-id, they would both get
each other's output.

7.2.  Selves and Actors

     At run-time, certain special  object  number  variables
are  defined,  and can be used in functions to reference the
player who triggered the  current  function  calls,  or  the
object  number  of the current function's root object. These
values are #actor, #caller and #self.  When a function  uses
#actor  as  an object number, it is replaced with the object
number of the player whose input  is  currently  being  pro-
cessed.  This is very, very useful:

func @.take
{
        ...
        foreach $who in (#actor.location.players)
                echoto($who,#actor.name," picks up ",$thing.name,"\n");
        ...
}

Suppose the object number of the person who typed the 'take'
command  in were #44. This function would iterate across the
list  of  players  in  #44.location.players,   echoing   the
player's  name, and so forth to them. This permits functions
to be written in a manner that is fairly independent of  who
or  what  calls them. The #self special object identifier is
similar, but identifies the object  number  of  the  current
function's root object. This allows a function to modify its
proper root object. Suppose we have a radio that we wish  to
have alter its description depending on whether or not it is
turned on. We might write:

func #44.turnon
{
        ...
        if(#self.on == NULL) {
                #self.on = 1;
                #self.description = "a blaring ghetto-blaster...";
        }
        ...
}

Granted, #44 could be substituted for #self in this example,
but  using  #self  makes it easier to make programs that are
object number independent. Another crucial  facet  of  #self



                       June 22, 1990





U Programming Language


arises  when a function that is called is acually a function
called with a reference. In such a case, using #44 would set
the  wrong  value  in  the  wrong  radio  depending on which
radio's function were called. Using  #self  guarantees  that
the  correct  root object number is applied. Using the func-
tion above:

        #55.turnon = &#44.turnon;
        #55.turnon();
        #44.turnon();

The first call, to #55.turnon()  would  modify  #55.on,  and
#55.description  since  #self would be object number #55. In
the second call, the value of #self would be  correctly  set
to #44.

     The #caller special  object  variable  is  replaced  at
run-time  with  the  object  number  of  the object that has
invoked the current function. If the  current  function  has
been  called directly from a player, or the monitor, #caller
is identical to #actor.

func #33.bar
{
        echo("self is ",#self,"\tcaller is ",#caller,"\n");
}

func #44.bar
{
        echo("self is ",#self,"\tcaller is ",#caller,"\n");
        #33.bar();
}

#44.bar();

In the example above, there are two functions, one of  which
calls  the  other,  and  is  in turn called from the monitor
directly. If this code were run with the  user-id  #55,  the
results would look like:

self is #44     caller is #55
self is #33     caller is #44

Since the first call to #44.bar  was  executed  directly  by
object #55, the #caller value is exactly the same as #actor.

8.  Permissions

     In U, all objects have a variety of permissions associ-
ated  with them.  Each object has an owner, and a masked set
of permissions flags, somewhat reminiscent  of  the  permis-
sions  bits  on a UNIX file.  Permissions can be granted for
read or write. The concept of execute permission is meaning-
less,  since  functions  are  a primary data type, and being



                       June 22, 1990





Copyright, Marcus J. Ranum, 1990


able to read them implies being able to execute them.  There
are   three   classes  of  permissions:  owner  permissions,
indirect permissions, and world permissions.  Owner  permis-
sions  are  checked  when the owner of a on object or object
element attempts to modify or access  it.  Indirect  permis-
sions  are  checked when a function that is running with the
effective user-id of the owner, but a different real user-id
tries  to  modify or access an object, and world permissions
are checked in all other cases. The purpose of the  indirect
mode  is to prevent objects from seriously damaging a player
or his internal data, as a result of  the  player's  action.
There  is no notion of 'groups' per se in U, since there are
really no classes of objects to group things by.

8.1.  Permissions on a Root Object

     When the system built-in function objectnew is  called,
it  allocates  a  new  empty  object, and returns its object
number. This empty object can have  elements  (data  values)
added  to  it  as  part  of  the  usual  assignment  process
described earlier. Whenever an  assignment  is  made  to  an
object  element that does not already exist, the permissions
on the root object are checked, and must be  in  a  mode  to
permit  writing  before  the  element  can be created. If an
attempt is made to destroy the root object, a check is  made
to  see if it is writeable. This makes it easy for an object
to be created that can have new  elements  added  to  it  by
other  than  the  player,  by  simply making the root object
world-writeable. This  also  makes  it  feasible  to  create
objects  that  can  be  destroyed  by  people other than the
owner, which is sometimes desirable. Read  permission  on  a
root object is (currently) meaningless.

8.2.  Permissions on an Object Element

     The same permissions bits exist for an  object  element
as for a root object, but some of the effects of permissions
bits are interpreted differently. If an assignment  is  made
to  an  element, the existing element must be in a mode that
permits writing by the caller, based on the effective  user-
id. This applies even if the assignment is to NULL, so it is
possible to create an object element in someone else's  root
object  that  they  cannot destroy. This is a feature rather
than a bug, as it permits the universe  rules  designers  to
make  some values outside the user's control. If, however, a
root  object  is  destroyed,  all  elements  are  destroyed,
regardless  of  ownership. There is an additional feature to
aid in designing universes: only the  universe  Creator  can
create  an element which has a name beginning with an under-
score '_' character.  This is to reserve a set of names  for
universe-implementations,  without  forcing  the  Creator to
always set values and permissions  to  "hold"  the  variable
names.




                       June 22, 1990





U Programming Language


8.3.  Permissions on a Function - the Setuid Bit

     A special permissions mode can be applied to functions,
which causes the function that is being executed to run with
its effective user-id to be that of the owner of  the  func-
tion.  This provides a controlled means for giving access to
objects without having to make the  object  world-writeable.
Setuid  functions owned by the Creator are especially useful
for implementing universe rules, since the Creator may  want
to  reserve  some  privileges  for  itseslf  (such as moving
objects in rooms). Setuid is a very powerful capability, but
can  also  cause serious problems if not used with care. Any
functions that are called by a setuid function inherit their
effective user-id from the setuid function. Thus, the writer
of a  setuid  function  must  be  careful  to  control  sub-
functions  that  are called, since a joker might take advan-
tage of permissions to destroy objects, or change their per-
missions and ownerships.

     The setuid model of  permissions  will  be  immediately
familiar  to anyone who has more than a nodding acquaintance
with UNIX.  Such a user will also know that 95% of the secu-
rity  loopholes  in  UNIX  are as a result of an incorrectly
applied setuid program. An  Ubermud  Creator  will  want  to
exercise  some  caution,  since a flaw in the universe rules
will allow players to assume the powers of a wizard. On  the
other  hand,  Ubermud  being a game, this can be fun - or at
least less serious than having a multi-user computer  broken
into. The possibility of destructive Uber-virusses is not to
be ignored, however.

8.4.  Changing Permissions

     Permissions on object elements and root objects can  be
altered  with  the  built-in  chmod() function. Chmod can be
given either the number of an object  (to  affect  the  root
object's  permissions), or a reference to an object element.
Chmod takes a second parameter, which is a string specifying
the  permissions modes for the three types: Owner, Indirect,
World. The types are signified with upper-case letters, fol-
lowed by a colon and a list of lower-case letters indicating
the desired mode for that type of permission.

        chmod(#33,"O:rw");
        chmod(&#33.bar,"O:rw,I:r,W:r");
        chmod(&#33.somefunc,"O:rw,I:r,W:rs");

The first example sets the permissions for the  root  object
of  #33  to be owner read and owner write. Since the permis-
sions for indirect and world are not  specified,  no  opera-
tions  are  permitted  to  anyone  but  the owner. Since the
object is a root object, the read permission does  not  mean
much,  but  the  lack  of world or indirect write permission
means that nobody but the owner can create new  elements  in



                       June 22, 1990





Copyright, Marcus J. Ranum, 1990


that object. The second example shows a reference to #33.bar
being passed to chmod, with a request to  set  that  element
only  as  owner  readable  and writeable, indirect and world
readable. This is, in fact, the  default  permissions  mode,
which is automatically set when an object or element is ini-
tially created or assigned to. The  third  example  shows  a
function  being marked as owner read and writeable, indirect
and world readable,  and  setuid.  To  flag  an  element  as
setuid,  the  's'  must  be marked within the world group of
permissions, as a reminder  to  the  programmer  that  world
access is being given to the owner's permissions.

8.5.  Changing Ownership

     Objects can be given  away  in  U,  as  can  individual
object elements.  Only the owner of an object or element (or
the Creator) can give an object away. Giving the root object
away  does not automatically change the ownership of all the
object elements in that object, nor does giving away a  sin-
gle  object  element  give any other permissions within that
object. The only change other than  ownership  that  occurrs
when  an  object  is  given  away  is that the setuid bit is
cleared if it is set in the gift. This  is  to  prevent  the
obvious  security  loophole.  Calls to the built-in function
that manages changing ownerships are done similarly to  set-
ting  permissions.   An  object number, or a reference to an
object element is given, and the object number of the  reci-
pient is provided as a second parameter:

        chown(#33,#44);
        chown(&#44.name,#44);

The first example above shows a root object #33 being  given
to #44. Note that #44 does not have to be a player. In fact,
the recipient does not even have to exist.  Object  elements
within the system object (#0) can be given away by the Crea-
tor if so desired, but the system object  itself  cannot  be
given  away.   Typically  ownership  changing  is  useful in
creating universe rules, where a creator may wish to  create
a  base  object  that  will be a player, and then give it to
itself. In some universes, or in some cases, the Creator may
not  want a player to own their base object. Such issues are
outside of the scope of this document.

9.  Built-In Functions

     U has a fairly  powerful  set  of  built-in  functions,
which can be called exactly like user-defined functions, and
return (or do not) values as appropriate. For  the  purposes
of  documenting  them,  they  are  listed below, in a manner
intended to be somewhat reminiscent of the manner in which C
functions  are  usually declared, with the return value, and
parameter types. Some U built-ins take  arbitrary  lists  of
parameters, some take specific parameters of given types. In



                       June 22, 1990





U Programming Language


the case of the latter, NULL is returned when the  parameter
count  is incorrect, or the wrong data type is provided as a
parameter.

9.1.  General Functions

NUM atoi(STR) - returns a numerical  representation  of  the
string,  or  zero. If a NUM or OBJ is passed to the function
by accident or on purpose, a type conversion  will  be  per-
formed,  and  the  corresponding NUM value will be returned.
NULL is returned if more than one parameter is given, or the
parameter is a function, list, or other type.

OBJ atoobj(STR) - converts a string  to  an  object  number,
with the same caveats and type conversions at atoi.

NUM catfile(object#,STR) - sends the contents  of  the  file
named  in  the  string parameter to the output buffer of the
player object listed  as  the  first  parameter.  Files  are
searched  for  in  a  subdirectory of the U-server's current
directory named "files" for security reasons.  If  the  file
cannot  be  opened, the player is informed as to the reason.
Files with a leading '/' character or a  '..'  in  them  are
forbidden,  and  will  not  be  printed.  In  the event of a
failure, the function returns NULL;  a  successful  call  is
indicated with a numeric zero return value.

INT disconnect(object#1,object#2,object#N) - disconnects the
specified  object  numbers  from the server if they are con-
nected.  This  function  must  be  run   with   user-id   or
effective-user-id  of  Creator.   Note  that since this is a
built-in command, the caller must generate their own call to
@._quit(),  or  whatever  is necessary to cleanly disconnect
the player.

NULL echo(arg1,arg2,argN) - echos its parameters  to  #actor
in  sequence,  performing  type conversion as necessary. NUM
values are converted to a text format, strings  are  printed
as  such,  and  object  numbers are printed preceeded with a
sharp '#'  character.  NULL  values  are  not  printed,  and
attempts  to print functions and lists prints either "<func-
tion>" or "<list>" respectively.

NULL echoto(object#,arg1,arg2,argN) - echoes its  parameters
just like echo, except that the output it sent to the player
matching object# if that player is connected. If the  desti-
nation  object number is not connected, the output is thrown
away.

NUM errno(NULL) - returns a  numeric  representation  of  an
error attached to a particular NULL value. Error values are:
          0 - No error.
          1 - Error. This is produced when  a  user  program
          returns NULL.



                       June 22, 1990





Copyright, Marcus J. Ranum, 1990


          2 - Out of memory. This indicates a memory alloca-
          tion condition within the server.
          3 - Numeric operation on  non-number.  This  indi-
          cates  an  attempt was made to perform a numerical
          operation on a non-numeric value.  The only numer-
          ical  operator that is permitted on non-numbers is
          the  equality  ("==")  operator,  which  functions
          between NULLs and strings.
          4 - Division by zero. This indicates  a  numerical
          division by zero was attempted.
          5 - Badly formed element specifier. This indicates
          an  attempt  was  made to create an element out of
          something invalid. For example, trying to make  an
          element out of a string value and an element name.
          (EG: $foo.bar where $foo = "foo").
          6 - Bad parameter type. A  built-in  function  was
          called  with  an  incorrect  parameter  type, or a
          missing or extra parameter.
          7 - Nonexistent object. An  attempt  was  made  to
          access  an  object or object element that does not
          exist. In the event that an object is not readable
          by a person, this value is returned, not a permis-
          sion denied value. This is  to  make  non-readable
          values completely and utterly "invisible".
          8 - Cannot reference object. An attempt  was  made
          to  take  a  reference of an object that cannot be
          referenced. This usually results from  an  attempt
          to  take  a  reference  of  a badly formed element
          specifier.  (EG: &$foo where $foo = "bar").
          9 - Function returned no value. An attempt to  use
          a  return  code  from  a function that returned no
          value results in the return code being NULL,  with
          this  value.  There  are  many cases where this is
          perfectly acceptable.
          10 - No such parameter. An attempt to use a  func-
          tion  parameter  that  was not passed returns this
          NULL. (EG: $4 in a function that was  only  called
          with two parameters).
          11 - I/O error (this is bad!). Something failed in
          the  disk-based  database  routines. This is very,
          very, very bad. Run about in a panic.
          12 - Permission denied. An  attempt  was  made  to
          operate  on  an  object  which has permissions set
          against the operation.
          13 - Not owner. An attempt was made to change  the
          ownership  of an object or object element that the
          caller does not own.
          14 - Stack over/underflow. Some form of  recursive
          or looping call was made, resulting in an eventual
          failed function call.

STR error(NULL) - returns  a  string  representation  of  an
error  message  attached to a particular NULL value. This is
useful for debugging or explaining why an operation failed.



                       June 22, 1990





U Programming Language


        $ret = #33.bar = "this is a test";
        if($ret == NULL)
                echo("operation failed: ",error($ret),"\n");

The above example is a typical means  of  performing  error-
checking withing a U function.

NUM islist(arg) - returns a numerical value of  one  if  the
parameter is a list. Numerical zero is returned otherwise.

NUM isnum(arg) - returns a numerical value  of  one  if  the
parameter is a number. Numerical zero is returned otherwise.

NUM isobj(arg) - returns a numerical value  of  one  if  the
parameter  is  an  object number. Numerical zero is returned
otherwise.

NUM isstr(arg) - returns a numerical value  of  one  if  the
parameter is a string. Numerical zero is returned otherwise.

NUM rand(optional arg) - returns a random number  from  zero
to  the  maximum  numeric  value allowed on the system. If a
single numeric parameter is given, the range of  the  number
returned will be between zero and the parameter. If a param-
eter that is non-numeric is provided, numeric zero is always
returned.

        echo("1d6=",rand(6) + 1,"\n");

The above would produce a random number as if  rolled  on  a
six-sided die.

NUM regcmp(string1,string2) -  returns  a  one  or  a  zero,
depending on whether or not string1 contains text matched by
the regular expression in string2. If the regular expression
in string2 is malformed, or a parameter is mis-matched, zero
is returned.

STR regexp(string1,string2) - returns a string consisting of
the  first  completely  matching substring in string1, using
the regular expression in string2. If there is no  match,  a
parameter  is  missing or mismatched, or the regular expres-
sion  is  malformed,  the  function  returns  NULL.  Regular
expressions  are similar to those used in egrep, and include
the '|' operator.

echo(regexp("this is a test","this[ ][a-z]"));

In the example above, the string "this is" would be returned
by regexp, and echoed.

INT shutdown() - shuts  the  server  down  gracefully.  This
function  must  be  run with user-id or effective-user-id of
Creator.



                       June 22, 1990





Copyright, Marcus J. Ranum, 1990


STR str(arg1,arg2,argN) - returns a  string  assembled  from
the  parameters  given. Conversion on the parameters by type
is performed in the same manner as in echo. This function is
very  useful  for  producing concatenated values for assign-
ments:

        #33.time = str("the time is:",strtime());

The above appends the returned value of strtime to  the  end
of the string, and assigns it to #33.time.

NUM strlen(STR) - returns the length of the string passed as
a  parameter. If the value is not given, or is not a string,
numeric zero is returned.

STR strtime(optional arg1) - returns a text string represen-
tation  of  the  system's  current  notion of the time. If a
numeric parameter is provided, the time string  returned  is
the  notion of the time as if it were at the given number of
seconds GMT since January 1, 1970.

NUM time() - returns the system's notion of how many seconds
it has been GMT since January 1, 1970.

9.2.  List Manipulation Functions

OBJLIST listadd(OBJLIST,object#1,object#2,object#N)

OBJLIST  listprepend(OBJLIST,object#1,object#2,object#N)   -
prepends  the given object numbers to the list provided as a
first parameter, and returns the new list. In the  event  of
an  parameter  type mismatch in the first parameter, NULL is
returned.  If  any  of  the  object  number  parameters  are
incorrect, the new value is silently ignored. If a new value
already exists in the old list, it is not  prepended  again,
and  retains  its  old position in the list. These two func-
tions are actually the same, under different names,  listadd
being included for brevity's sake.

OBJLIST   listappend(OBJLIST,object#1,object#2,object#N)   -
appends the given object numbers, in the same manner as lis-
tappend.

NUM listcount(OBJLIST) - returns a numerical  count  of  the
number of element numbers in the list provided. In the event
that parameter one is missing, or is not  a  list,  NULL  is
returned.

OBJLIST    listdrop(OBJLIST,object#1,object#2,object#N)    -
returns  a  new  list, consisting of the object numbers from
the list in the first parameter, with any occurrences of the
object numbers given as parameters omitted. In the case of a
call to listdrop completely emptying a list, an  empty  list
is returned.



                       June 22, 1990





U Programming Language


OBJNUM listelem(OBJLIST,NUM) - returns the object number  of
the  N-th element in the list. Unlike C, U lists are indexed
with the first element being element number 1. If the  index
number  given  is  higher  than  the  total number of object
numbers in the list, or the first parameter is not  a  list,
NULL is returned.

OBJLIST listmerge(OBJLIST,OBJLIST) - returns  a  new  object
list,  consisting  of  the  union  of  the lists provided as
parameters. Duplicates are suppressed. As  a  special  case,
either  of the two lists provided as parameters can be NULL,
which will effectively return the other list.

OBJLIST listnew(object#1,object#2,object#N) - returns a  new
object  list,  consisting of the object numbers given. If no
parameters are given, or all  the  provided  parameters  are
invalid, an empty list is returned.

NUM listsearch(OBJLIST,object#) - returns the  index  offset
of  the  given  object  number  in  the list, or NULL if the
object number is not in the list.  NULL  is  returned  if  a
parameter  is  missing,  or is of the wrong type. Since list
element offsets start at one, locating an object  number  in
the first 'slot' of the list returns numeric '1'.

OBJLIST listsetelem(OBJLIST,object#,NUM) - returns  a  list,
with  the object number at the numeric index set to the pro-
vided object number. If  there  are  not  that  many  object
numbers   in   the  list,  the  original  list  is  returned
unchanged. NULL is returned in the case of a missing parame-
ter, or incorrect parameter type.

9.3.  Object Manipulation Functions

NUM objectdestroy(object#) - destroys the  numbered  object,
if the caller has permission, destroying any object elements
bound to that object as well. NULL is returned in the  event
that  permission  is  denied.  In  the event of a successful
annihilation, numeric zero is returned. In some  implementa-
tions,  this permission requires that the caller's effective
user-id or real user-id be Creator.  This is to avoid  prob-
lems  with  players destroying objects that people are hold-
ing, etc, and is the default case.

NULL objectelements(object #) - lists the  elements  defined
in  an object to the caller's terminal. The caller must have
read permission on the base object, in order to invoke  this
function.

OBJNUM objectnew() - creates a new object  and  returns  its
number. The new object is the property of the caller, and is
created empty, with default permissions.

OBJNUM objectowner(object#, or reference to object  element)



                       June 22, 1990





Copyright, Marcus J. Ranum, 1990


-  returns  the  object number of the object owning the root
object or object element  provided.  In  the  event  of  the
object or element's non-existence, NULL is returned.

9.4.  Permissions and Environment Manipulation Functions

NUM chmod(object#,or reference to object element,STR) - sets
the permissions of the root object or object element, if the
caller is the owner of the root object  or  object  element.
The  string  can contain a coding of permissions values con-
sisting of any of: 'O', signifying  owner,  'I',  signifying
indirect, and 'W' signifying world, followed by a colon, and
any of 'w' for write, or 'r' for read.  Functions may have a
setuid  specifier  applied  to the world permissions set, by
using 's'. For examples, see above. In the event of failure,
NULL  or returned; numeric zero is returned if the operation
was a success.

NUM chown(object # or reference to object element,OBJNUM)  -
sets  the  ownership  of the specified root object or object
element to the object number provided. The call will fail if
the  caller is not the owner of the object being given away.
If a setuid bit is marked in the object's permissions it  is
cleared  as  part  of this process. In the event of failure,
NULL is returned; numeric zero is returned if the  operation
is successful.

OBJNUM geteuid() - returns the object number of the  current
caller's effective user-id.

OBJNUM getuid() - returns the object number of  the  current
caller's real user-id.

NUM setruid(OBJNUM) - sets the real user-id of  the  current
calling function to the object number specified as a parame-
ter.  This should only be used with extreme caution in  rare
circumstances,  as  it  affects the value returned by #actor
(unlike setuid). Its effect ends when the  current  call  is
completed.  If  called  directly  from the monitor, the real
user-id is not permanently changed.  This function can  only
be  called if the real or effective user-id of the caller is
the Creator. Successful calls return  numeric  zero;  failed
calls return numeric one.

NUM setuid(OBJNUM) -  sets  the  effective  user-id  of  the
current calling function to the object number specified as a
parameter.  This call will only succeed if the real  user-id
of  the  caller is the number being set to, or the caller is
Creator. In the event of failure, NULL is returned;  numeric
zero is returned if the operation succeeds.

9.5.  Matching Functions

OBJNUM   match(STR,OBJNUM    or    OBJLIST,STR,[OBJNUM    or



                       June 22, 1990





U Programming Language


OBJLIST,STR]..)  -  match  scans  the object list, accessing
each object number in the list for an element name  matching
the   provided   string.   An  arbitrary  number  of  object
list/string pairs can be  provided.  Once  each  element  is
accessed, it is compared against the first string given. The
object number of the best match found is  returned.  In  the
event  of  multiple matches, the returned object is selected
based on the order in which the lists  were  passed  to  the
function  (priority given the the first list). If a complete
match is made at any point, no further  searching  is  done.
This  is an especially useful function for matching a user's
input with objects in the surroundings:

        ...
        $nam = match("foo",#actor.carr,"name",#actor.loc,"name");
        if($nam != NULL) {
        ...

In the example above, a search is being made for things that
match  the  word  "foo".  The  first  list  searched  is the
#actor.carr list - each object in that list is checked for a
string  element named "name". After #actor.carr is searched,
#actor.loc is  searched,  also  for  string  elements  named
"name".  In the example above, if #actor.carr had the object
numbers #44 and #55 in the list, match would check to see if
there   was  a  string  stored  in  element  #44.name,  then
#55.name, and so on.

     Individual root object numbers can be passed to  match,
as well, so that:

        ...
        $nam = match("foo",#99,"name");
        if($nam != NULL) {
        ...

will return #99 if there is an element named "name"  in  #99
that  is "foo", or begins with "foo". Individual root object
numbers can be freely combined with lists in calls to match.

     An additional aspect of matching  is  the  magic  match
character, which can be used in strings to effect an "alias"
of sorts. The match character is inserted in a  string  with
an  escaped  semicolon:  '\;'. This causes match to re-start
matching a string whenever it encounters the semicolon. This
is useful in many ways.

        ...
        #99.name = "Rusty\;doofus";
        $nam = match("doof",#99,"name");
        if($nam != NULL) {
        ...

In the above  example,  match  will  retrieve  #99.name  and



                       June 22, 1990





Copyright, Marcus J. Ranum, 1990


compare "doof" with "Rusty", generating a failure. The match
character is then detected, which causes match  to  re-match
against "doofus", which succeeds and returns #99.

10.  Programming Hints, Traps, and Pitfalls.

     The mistake most commonly made  by  the  author  is  to
store  a  variable within an object, which has the same name
as a function within that object. The net effect of this  is
to  destroy the function when it is called. This is surpris-
ingly easy to do:

/* a function to turn #44 on, whatever #44 is */
func    #44.on
{
        ...
        /* if the thing is turned off, turn it on.. */
        if(#44.on == NULL) {
                #44.on = 1;
        }
        ...
}

The function runs  perfectly,  the  first  time.  Subsequent
calls  try  to  call  #44.on (which is now the numeric value
one) and return NULL (no such function). Realizing that  one
has done this in a program is infuriating in the extreme.

11.  Annotated Programming Examples

11.1.  A Room With Lights

     The following is an example of  a  room  with  a  light
switch  that  works.  Assuming here that room #1 has already
been created, and so on, the programmer binds a function  to
it as a light switch:

func #1.lights {
        if(#self.on == NULL) {
                $tmp = #self.on = 1;
                if($tmp == NULL) {
                        echo("the switch is broken0);
                        return;
                }
                @.emote("turns on the lights");
                #self.desc = "You see a dusty room, [...]";
                return;
        }
        #self.desc = "It is pitch dark in here";
        #self.on = NULL;
        @.emote("turns off the lights");
}
chmod(&#1.lights,"W:rs");




                       June 22, 1990





U Programming Language


The function checks to see if object element #self.on is set
- using that as a boolean value for the state of the lights.
Note that here, it is set and unset to NULL  rather  than  a
value.  When no value is desired, using NULL and non-NULL is
faster and saves  database  space  besides.   If  the  rooms
lights are off (#self.on == NULL), an attempt is made to set
the lights on. The value of the assign is  checked  to  make
sure that the operation was successful ($tmp == NULL implies
a broken switch). If that operation was successful,  a  call
is made to one of the universe's functions 'emote' (@.emote)
which presumably sends a string to anyone else  who  happens
to  be  in the room. The room then alters its description to
adapt for the lights being on, and returns.  If  the  lights
were  already  on,  the first case fails, and the lights are
turned off by resetting the description of the room and set-
ting the value of #self.on to NULL.

11.2.  More to come.

     More good examples to  be  added,  when  people  create
small nifty objects.




































                       June 22, 1990