
  Here's a summary of the biggest differencies between C and Lpc.

	o Files are never compiled, the source files are read directly
	  into the driver.

	o There are no such thing as pointers. Read em and weap.

	o you don't need a main(). In lpc functions are called directly
	  from the driver or when a command is typed.

	o there are many routines and functions that are hidden in the
          parser, equivalent to the kernal in UNIX, are basic system calls.

	o strings are not arrays the way they are in C the are much closer
	  to the strs of BASIC (you remember being forced to learn that trash
	  in High School right?).  String functions are implied i.e. you may
	  us the '+' operator to combine strings such that:
		ack=foo+bar; is equivelen to:
		strcpy(ack,foo);
		strcat(ack,bar);
	  Also ack[foo] does not refer to a character, it just return the
	  the integer value of the char foo.

	o lpc does not use typing.  this means that you can do nonsense like
	  this:

	  do_it()
	  {
		int i;

		i="ack";
		return i;
	  }
	  This is of course not recommendable and the compiler will warn you
	  if you use #pragma strinct_types

	o the object orientedness of lpc is mostly a illusion all your
	  doing is modifing shared parameters, so don't expect C++ kinds of
	  stuff to work

	o ++, --, +=, -=, *=, and /= can behave in strange ways, don't use
	  them in very complicated combinations.

	o All low- to high-level lpc objects are not held togethor like
  	  a tradtional program it is closer to writing a module for a large
	  program and using a incremental compilor apon each module independant
	  of all other modules

	o Lpc is tokinised and interpreted, not compiled.

	o -> is not used for membership, in fact there are no such thing as
	  structs in lpc.

:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

In article <1991Sep21.170218.5667@bronze.ucs.indiana.edu> kellehe@silver.ucs.ini
ana.edu (Mike Kelleher) writes:
>
>Most silly 3.0 questions, I hope there getting more intelligent as we go
>allong. Does anybody have a suggestions as a whole for secuirty measures in
>3.0? There are several calls like Get_rootid that really bother me.
>anyone got some suggestions?

The name 'root' has nothing to do with the login name 'root' on unix
systems. The only common thing is the spelling.

The 3.0 has a new security system, which is not used if -o is specified !

The new security system has been inspired by the Unix way of handling
user id (uid) and effective user id (euid), but is not exactly the same.

Every object will have a uid and a euid.  It is the euid that governs what
permissions the object will have. The euid can be changed.

The game driver only maintains these two values, represented as strings. It
is the master.c that defines what they mean. The values can be any string,
but one good way is to use the name of the wizard.

When an object wants to access a file, valid_read (or valid_write) will
be called in master.c, which will make a decision depending on the path
name of the file and the euid. The 2.4.5 game driver called the valid_read in
player.c, which was quite bad when there were no "current player".

The euid can be changed to only some other values by the object, but always
to the value of the uid. This is also defined by the master.c object.

There is no set-uid as in Unix, but there is a possibility to transfer
your euid to another objects uid. If object A do seteuid(0), then any
object B can do export_uid(A) which will set the uid of A to the euid
of B.

There are some special rules (which I won't list here) which define what
happens when an object makes another object become loaded. These rules are
currently hard-coded in the game driver, but will probably also be transfered
to master.c. In general, a loaded object either gets the same uid as the euid
of the loader, or 0 (means no permission).

This new security system is in many ways compatible with the old system. The
big difference is that when a wizard A makes a room be loaded that was defined
by wizard B, then you don't want that room to have uid A. Instead, it will
have 0, which means that it must set the euid to something to be able to
do any file access. This might seem arduos, but as all new mudlib systems
are defined in a hierarchical way, a single line in a single file will
(should :-) do it.

There are some interesting problems resulting from this. For example, a
player.c object can't call save_object() without preparations because it
doesn't normally have permission to modifiy player save files.

This is solved by talking with the master.c. The player object first sets its
euid to 0, then calls a special request function in master.c which will
give the player object the "root" uid. Now, the object can do the save,
set back to euid 0 and return control to master.c. Of course, the master.c
will validate that it is actually the player object, not something
made by a wizard.

Even if an object has euid "root", it can't access files outside the
mudlib directory. This is never ever supposed to be possible.

The wizlist modifications are now based on the uid of the object. That means
that "root" can show up, as well as "backbone".

Lars Pensj|
lars@cd.chalmers.se

:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

Types declarations

Types can be used at four places: Declaring type of global  vari-
ables.  Declaring type of functions.  Declaring type of arguments
to functions.  Declaring type of local  variables  to  functions.
Normally,  the type information is completely ignored, and can be
regarded purely sa documentation.  However, when the  basic  type
of  a function is declared, then a more strict type checking will
be enforced.  That means that the type of all arguments  must  be
defined.   And, the variables can only be used to store values of
the declared type.  The function is defined to return  an  unkown
type,  as  the compiler can't know the type.  This value must al-
ways be casted (when strict type checking is enabled).  Casting a
type is done by putting the type name inside a pair of '(' and An
example when querying the short description of an object:
(string)call_other(ob, "short");
There are two kinds of types.  Basic types,  and  special  types.
There  can  be  at most one basic type, but any number of special
types.  The strict type checking is only used  by  the  compiler,
not  by  the  runtime.  Hence, it is actually possible to store a
number in a string variable even when strict type checking is en-
abled.

Why use strict type checking ?  It is really recommended, because
the  compiler  will  find many errors at compile time, which will
save a lot of hard work.  It is in general much harder  to  trace
an  error  occuring at run time.  I recommend, that when a wizard
is having problem with an object and wants help,  that  he  first
must make all functions have declared types.


Basic types

An integer 32 bit number.   Pointer  to  an  object.   An  object
pointer  can mainly be used for two things.  Either giving as ar-
gument to functions, or used for  calling  functions  defined  by
that object with its specific instance of variables.  An unlimit-
ed string of characters.  A lot  of  operators  are  allowed  for
strings, like and etc.  This type is special, in that it is valid
to use in any context.  Thus, if everything was declared then the
compiler  would  never complain.  This is of course not the idea.
It is really only supposed to be used when a variable  really  is
going  to  contain different types of values.  This be avoided if
possible.  It is good coding practice, to allow  a  function  for
example  to return different types.  This type is only usable for
functions.  It means that the function will not return any value.
The compiler will complain (when type checking is enabled) if the
return value is used.


Arrays

Arrays are declared using a '*' with a basic type.  For  example,
declaring  an array of numbers: "int *arr;".  Use the type if you
want an array of arrays, or a mixed combination of types.


Special types

There are some special types, which can be given before the basic
type.  These special types can also be combined.  When using spe-
cial type before an statement, all symbols defined by inheritance
will  also get the special type The only special case is symbols,
which can not be redefined as in a statement.  Can be  given  for
both  functions  and variables.  Functions that are in object can
not be called through from another object.  And, they are not ac-
cessible  to  any  object that inherits This special type behaves
different for variables and functions.   It  is  similar  to  for
functions,  in  that  they  can not be called from other objects.
variables will be neither saved nor restored when  calling  or  A
function defined as will always be accessible from other objects,
even if is used.  All symbols defined as can not be redefined  by
inheritance.  They can still be used and accessed as usual.

:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
