sokoban.h

It is common practise to put configuration parameters as define'd values in include files. /*********************************************************************** You may wish to alter the following directory paths ***********************************************************************/ /**/ /* SCREENPATH: the name of the directioy where the screen file are held */ /**/ #define SCREENPATH "/usr/local/lib/sokoban/screens" /**/ /* SAVEPATH: the name of the path where save files are held */ /* Attention: Be sure that there are no other files with */ /* the name <username>.sav */ /**/ #define SAVEPATH "/usr/local/lib/sokoban" /**/ /* LOCKPATH: temporary file which is created to ensure that no users */ /* work with the scorefile at the same time */ /**/ #define LOCKFILE "/tmp/sok.lock" /**/ /* SCOREFILE: the full pathname of the score file */ /**/ #define SCOREFILE "/usr/local/lib/sokoban/sok.score" /**/ /* MAXUSERNAME: defines the maximum length of a system's user name */ /**/ #define MAXUSERNAME 10 Potential for obscure error in ``MAXUSERNAME''. The user's name is found from a system call, ``getpwuid''. This returns a pointer to a structure of type ``passwd'' with a field char *pw_name; This field may be of any length, not just 10. The Unix standard does not specify a limit. The global variable char *username; is set to point to this in ``main'', and later may be copied to an array of players in function ``makescore''. This is done by a ``strcpy'', not a ``strncpy'' so may overwrite a piece of memory if the name is actually longer than ``MAXUSERNAME'', causing a random crash at some stage. /**/ /* MAXSCOREENTRIES: defines the maximum numner of entries in the scoretable */ /**/ #define MAXSCOREENTRIES 50 /**/ /* SUPERUSER: defines the name of the game superuser */ /**/ #define SUPERUSER "root" /**/ /* PASSWORD: defines the password necessary for creating a new score file */ /**/ #define PASSWORD "nabokos" This is a simple game, but storing a password in plain text is not really a good idea. It will appear as a string in the program, and may be tracked down. /**/ /* OBJECT: this typedef is used for internal and external representation */ /* of objects */ /**/ typedef struct { char obj_intern; /* internal representation of the object */ char obj_display; /* display char for the object */ short invers; /* if set to 1 the object will be shown invers */ } OBJECT; This structure never got a structure name, only a typedef synonym. That doesn't matter, because it isn't a recursive structure requiring a self-reference. /**/ /* You can now alter the definitions below. /* Attention: Do not alter `obj_intern'. This would cause an error */ /* when reading the screenfiles */ /**/ static OBJECT player = { '@', '@', 0 }, playerstore = { '+', '@', 1 }, store = { '.', '.', 0 }, packet = { '$', '$', 0 }, save = { '*', '$', 1 }, ground = { ' ', ' ', 0 }, wall = { '#', ' ', 1 }; That was a nasty piece of code! You should never define (i.e. associate a name with a piece of memory) any variables in include files. What happens here is subtle. Each ``.c'' file includes this file. So, after the preprocessor has been over the ``.c'' file, it now contains a copy of the above definition.

The definition is for a static variable, so that it only has file scope. That is, each file has a set of variables ``player'', ``playerstore'', etc that are local to that file. So in file sok.c there is variable ``player'', and in file ``score.c'' there is a variable ``player'' and these are not the same variable!

The intent is to allow you to customise the appearance of each object. This would be better done in the include file by

#define PLAYER {'@', '@', 0} extern OBJECT player; and in one of the files (say sok.c) OBJECT player = PLAYER; as a global variable.

Anyway, after all that, the effect is to create structure variables with all fields intialised. The statement

OBJECT player = {'@', '@', 0}; is equivalent to OBJECT player; player.obj_intern = '@'; player.obj_display = '@'; player.invers = 0; (although this would not be legal C). /************************************************************************* ********************** DO NOT CHANGE BELOW THIS LINE ********************* *************************************************************************/ The following stuff is all good practise. Note the prefix ``E_'' (for error). This means there is less likelihood of name clashes with other define's. #define MAXROW 20 #define MAXCOL 40 typedef struct { short x, y; } POS; #define E_FOPENSCREEN 1 #define E_PLAYPOS1 2 #define E_ILLCHAR 3 #define E_PLAYPOS2 4 #define E_TOMUCHROWS 5 #define E_TOMUCHCOLS 6 #define E_ENDGAME 7 #define E_NOUSER 9 #define E_FOPENSAVE 10 #define E_WRITESAVE 11 #define E_STATSAVE 12 #define E_READSAVE 13 #define E_ALTERSAVE 14 #define E_SAVED 15 #define E_TOMUCHSE 16 #define E_FOPENSCORE 17 #define E_READSCORE 18 #define E_WRITESCORE 19 #define E_USAGE 20 #define E_ILLPASSWORD 21 #define E_LEVELTOOHIGH 22 #define E_NOSUPER 23 #define E_NOSAVEFILE 24