/************************************************************************** * file: SYNTAX_CHECKER.c , Check syntax of all files Part of DIKUMUD * * Usage: QUICK AND DIRTY!! * * Copyright (C) 1990, 1991 - see 'license.doc' for complete information. * ***************************************************************************/ #include <stdio.h> #include <string.h> #include <ctype.h> #include <time.h> #include "../structs.h" #include "../utils.h" #include "../comm.h" #include "../handler.h" #include "../limits.h" /* structure for the reset commands */ struct reset_com { char command; /* current command */ bool if_flag; /* if TRUE: exe only if preceding exe'd */ int arg1; /* */ int arg2; /* Arguments to the command */ int arg3; /* */ /* * Commands: * * 'M': Read a mobile * * 'O': Read an object * * 'G': Give obj to mob * * 'P': Put obj in obj * * 'G': Obj to char * * 'E': Obj to char equip * * 'D': Set state of door * */ }; /* zone definition structure. for the 'zone-table' */ struct zone_data { char *name; /* name of this zone */ int lifespan; /* how long between resets (minutes) */ int age; /* current age of this zone (minutes) */ int top; /* upper limit for rooms in this zone */ int reset_mode; /* conditions for reset (see below) */ int number; /* virtual number of this zone */ struct reset_com *cmd; /* command table for reset */ /* * Reset mode: * * 0: Don't reset, and don't update age. * * 1: Reset if no PC's are located in zone. * * 2: Just reset. * */ }; /* element in monster and object index-tables */ struct index_data { int virtual; /* virtual number of this mob/obj */ int number; /* number of existing units of this mob/obj */ long pos; /* pos in file */ int (*func)(); /* special procedure for this mob/obj */ }; /* for queueing zones for update */ struct reset_q_element { int zone_to_reset; /* ref to zone_data */ struct reset_q_element *next; }; /* structure for the update queue */ struct reset_q_type { struct reset_q_element *head; struct reset_q_element *tail; } reset_q; struct player_index_element { char *name; int nr; }; struct help_index_element { char *keyword; long pos; }; char *fread_string(FILE *fl); /************************************************************************** * declarations of most of the 'global' variables * ************************************************************************ */ struct room_data *world; /* dyn alloc'ed array of rooms */ int top_of_world = 0; /* ref to the top element of world */ struct obj_data *object_list = 0; /* the global linked list of obj's */ struct char_data *character_list = 0; /* global l-list of chars */ struct zone_data *zone_table; /* table of reset data */ int top_of_zone_table = 0; struct message_list fight_messages[MAX_MESSAGES]; /* fighting messages */ struct player_index_element *player_table = 0; /* index to player file */ int top_of_p_table = 0; /* ref to top of table */ int top_of_p_file = 0; FILE *mob_f, /* file containing mob prototypes */ *obj_f, /* obj prototypes */ *wld_f, /* World file */ *zon_f; struct index_data *mob_index; /* index table for mobile file */ struct index_data *obj_index; /* index table for object file */ struct index_data *wld_index; struct help_index_element *help_index = 0; int top_of_mobt = 0; /* top of mobile index table */ int top_of_objt = 0; /* top of object index table */ int top_of_wldt = 0; extern struct time_data time_info; /* the infomation about the time */ /* local procedures */ void boot_zones(void); void setup_dir(FILE *fl, int room, int dir); void allocate_room(int new_top); void boot_world(void); struct index_data *generate_indices(FILE *fl, int *top); void build_player_index(void); void char_to_store(struct char_data *ch, struct char_file_u *st); void store_to_char(struct char_file_u *st, struct char_data *ch); int is_empty(int zone_nr); void reset_zone(int zone); int file_to_string(char *name, char *buf); void renum_world(void); void renum_zone_table(void); void reset_time(void); void clear_char(struct char_data *ch); /************************************************************************* * routines for booting the system * *********************************************************************** */ void assume(int faktisk, int antal, int place, char *errmsg) { if (antal != faktisk) { printf("Error has occured at #%d.\n\r", place); printf("Message is: %s\n\r", errmsg); printf("Actual number read is %d\n\r", faktisk); exit(); } } /* generate index table for object, monster or world file*/ struct index_data *generate_indices(FILE *fl, int *top) { int i = 0, antal; struct index_data *index; long pos; char buf[82]; rewind(fl); for (; ; ) { if (fgets(buf, 81, fl)) { if (*buf == '#') { /* allocate new cell */ if (!i) /* first cell */ CREATE(index, struct index_data, 1); else if (!(index = (struct index_data *) realloc(index, (i + 1) * sizeof(struct index_data )))) { printf("load indices"); exit(); } antal = sscanf(buf, "#%d", &index[i].virtual); assume(antal, 1, index[i].virtual, "Next string with E/A/$"); index[i].pos = ftell(fl); index[i].number = index[i].virtual; index[i].func = 0; i++; } else if (*buf == '$') /* EOF */ break; } else { printf("Error when generating index, based upon #xxxx numbers.\n\r"); printf(" Probably error at end of file.\n\r"); exit(); } } index[i-1].number = -1; *top = i - 1; return(index); } int exist_index(struct index_data *index_list, int top, int num) { int i, found; found = FALSE; for (i = 0; (i <= top) && !(found); i++) if (index_list[i].number == num) found = TRUE; if (!found) { printf("Reference to non-existent number #%d\n\r", num); } return (found); } /* check the rooms */ void check_world(FILE *fl) { int room_nr = 0, zone = 0, dir_nr, virtual_nr, flag, tmp, old_virtual; char *temp, chk[50]; struct extra_descr_data *new_descr; int antal; char *temp2; world = 0; character_list = 0; object_list = 0; rewind(fl); old_virtual = -1; do { antal = fscanf(fl, " #%d\n", &virtual_nr); assume(antal, 1, virtual_nr, "Reading #xxx"); if (old_virtual > virtual_nr) assume(0, 1, virtual_nr, "Error - #'s not in order."); old_virtual = virtual_nr; temp = fread_string(fl); if (flag = (*temp != '$')) /* a new record to be read */ { temp2 = fread_string(fl); antal = fscanf(fl, " %d ", &tmp); assume(antal, 1, virtual_nr, "In room basic 3 numbers"); antal = fscanf(fl, " %d ", &tmp); assume(antal, 1, virtual_nr, "In room basic 3 numbers"); antal = fscanf(fl, " %d ", &tmp); assume(antal, 1, virtual_nr, "In room basic 3 numbers"); for (; ; ) { antal = fscanf(fl, " %s \n", chk); assume(antal, 1, virtual_nr, "Reading D/E/S string"); if (*chk == 'D') /* direction field */ setup_dir(fl, virtual_nr, atoi(chk + 1)); else if (*chk == 'E') /* extra description field */ { temp2 = fread_string(fl); /* Description */ temp2 = fread_string(fl); /* Keywords */ } else if (*chk == 'S') /* end of current room */ break; else assume(FALSE, 0, virtual_nr, "MISSING D/E or S"); } } } while (flag); } /* read direction data */ void setup_dir(FILE *fl, int room, int dir) { int tmp, antal; char *temp; temp = fread_string(fl); temp = fread_string(fl); antal = fscanf(fl, " %d ", &tmp); assume(antal, 1, room, "One of three Direction data"); antal = fscanf(fl, " %d ", &tmp); assume(antal, 1, room, "One of three Direction data"); antal = fscanf(fl, " %d ", &tmp); assume(antal, 1, room, "One of three Direction data"); exist_index(wld_index, top_of_wldt, tmp); } #define NEW_ZONE_SYSTEM xxx /* load the zone table and command tables */ void check_zones(FILE *fl) { int line_no; int antal, tmp1, tmp2, tmp3, tmp4; int zon = 0, cmd_no = 0, ch, expand; char *check, buf[81]; char cmd_type; rewind(fl); line_no = 1; for (; ; ) { antal = fscanf(fl, " #%*d\n"); assume(antal, 0, line_no++, "Zone number not found"); check = fread_string(fl); line_no++; if (*check == '$') break; /* end of file */ /* alloc a new zone */ #ifdef NEW_ZONE_SYSTEM antal = fscanf(fl, " %d ", &zon); assume(antal, 1, line_no, "Zone Room < number not found"); #endif antal = fscanf(fl, " %d ", &zon); assume(antal, 1, line_no, "Life Span"); antal = fscanf(fl, " %d ", &zon); assume(antal, 1, line_no++, "Reset Mode"); /* read the command table */ cmd_no = 0; for (expand = 1; ; ) { fscanf(fl, " "); /* skip blanks */ antal = fscanf(fl, "%c", &cmd_type); assume(antal, 1, line_no, "Command type M/*/O/G/E/S missing"); if (cmd_type == 'S') break; if (cmd_type == '*') { expand = 0; fgets(buf, 80, fl); /* skip command */ line_no++; continue; } antal = fscanf(fl, " %d %d %d", &tmp1, &tmp2, &tmp3); assume(antal, 3, line_no, "Three values after command missing"); if (cmd_type == 'M' || cmd_type == 'O' || cmd_type == 'D' || cmd_type == 'P') { antal = fscanf(fl, " %d", &tmp4); assume(antal, 1, line_no, "Fourth value after command missing"); } switch (cmd_type) { case 'M' : exist_index(mob_index, top_of_mobt, tmp2); exist_index(wld_index, top_of_wldt, tmp4); break; case 'O' : exist_index(obj_index, top_of_objt, tmp2); exist_index(wld_index, top_of_wldt, tmp4); break; case 'G' : exist_index(obj_index, top_of_objt, tmp2); break; case 'E' : exist_index(obj_index, top_of_objt, tmp2); break; case 'P' : exist_index(obj_index, top_of_objt, tmp2); exist_index(obj_index, top_of_objt, tmp4); break; case 'D' : exist_index(wld_index, top_of_wldt, tmp2); break; case 'R' : exist_index(wld_index, top_of_wldt, tmp2); exist_index(obj_index, top_of_objt, tmp3); break; case '*' : break; deafult : printf("Illegal command type"); exit(); break; } fgets(buf, 80, fl); /* read comment */ line_no++; } } } /************************************************************************* * procedures for resetting, both play-time and boot-time * *********************************************************************** */ /* read a mobile from MOB_FILE */ void check_mobile(FILE *fl) { int virtual_nr, old_virtual, antal, flag; char *temp; char bogst; int i, skill_nr; long tmp, tmp2, tmp3; struct char_data *mob; char chk[10]; old_virtual = -1; rewind(fl); do { antal = fscanf(fl, " #%d\n", &virtual_nr); assume(antal, 1, virtual_nr, "Reading #xxx"); if (old_virtual > virtual_nr) assume(0, 1, virtual_nr, "Error - #'s not in order."); old_virtual = virtual_nr; temp = fread_string(fl); /* Namelist */ if (flag = (*temp != '$')) { /* a new record to be read */ /***** String data *** */ /* Name already read mob->player.name = fread_string(fl); */ temp = fread_string(fl); /* short description */ temp = fread_string(fl); /*long_description */ temp = fread_string(fl); /* player.description */ /* *** Numeric data *** */ antal = fscanf(fl, "%d ", &tmp); assume(antal, 1, virtual_nr, "ACT error"); antal = fscanf(fl, " %d ", &tmp); assume(antal, 1, virtual_nr, "affected_by error"); antal = fscanf(fl, " %d ", &tmp); assume(antal, 1, virtual_nr, "Monster Alignment Error"); antal = fscanf(fl, " %c \n", &bogst); assume(antal, 1, virtual_nr, "Simple/Detailed error"); if (bogst != 'S') printf("%c %d\n", bogst, bogst); if (bogst == 'S') { /* The new easy monsters */ antal = fscanf(fl, " %D ", &tmp); assume(antal, 1, virtual_nr, "Level error"); antal = fscanf(fl, " %D ", &tmp); assume(antal, 1, virtual_nr, "THAC0 error"); antal = fscanf(fl, " %D ", &tmp); assume(antal, 1, virtual_nr, "AC error"); antal = fscanf(fl, " %Dd%D+%D ", &tmp, &tmp2, &tmp3); assume(antal, 3, virtual_nr, "Hitpoints"); antal = fscanf(fl, " %Dd%D+%D \n", &tmp, &tmp2, &tmp3); assume(antal, 3, virtual_nr, "Damage error"); antal = fscanf(fl, " %D ", &tmp); assume(antal, 1, virtual_nr, "GOLD error"); antal = fscanf(fl, " %D \n", &tmp); assume(antal, 1, virtual_nr, "XP error"); antal = fscanf(fl, " %D ", &tmp); assume(antal, 1, virtual_nr, "POSITION error"); antal = fscanf(fl, " %D ", &tmp); assume(antal, 1, virtual_nr, "DEFAULT POS error"); antal = fscanf(fl, " %D \n", &tmp); assume(antal, 1, virtual_nr, "SEXY error"); } else { /* The old monsters are down below here */ printf("Detailed monsters can't be syntax-checked (yet).\n\r"); assume(0, 1, virtual_nr, "DETAIL ERROR"); exit(); /* *************************** fscanf(fl, " %D ", &tmp); mob->abilities.str = tmp; fscanf(fl, " %D ", &tmp); mob->abilities.intel = tmp; fscanf(fl, " %D ", &tmp); mob->abilities.wis = tmp; fscanf(fl, " %D ", &tmp); mob->abilities.dex = tmp; fscanf(fl, " %D \n", &tmp); mob->abilities.con = tmp; fscanf(fl, " %D ", &tmp); fscanf(fl, " %D ", &tmp2); mob->points.max_hit = 0; mob->points.hit = mob->points.max_hit; fscanf(fl, " %D ", &tmp); mob->points.armor = tmp; fscanf(fl, " %D ", &tmp); mob->points.mana = tmp; mob->points.max_mana = tmp; fscanf(fl, " %D ", &tmp); mob->points.move = tmp; mob->points.max_move = tmp; fscanf(fl, " %D ", &tmp); mob->points.gold = tmp; fscanf(fl, " %D \n", &tmp); GET_EXP(mob) = tmp; fscanf(fl, " %D ", &tmp); mob->specials.position = tmp; fscanf(fl, " %D ", &tmp); mob->specials.default_pos = tmp; fscanf(fl, " %D ", &tmp); mob->player.sex = tmp; fscanf(fl, " %D ", &tmp); mob->player.class = tmp; fscanf(fl, " %D ", &tmp); GET_LEVEL(mob) = tmp; fscanf(fl, " %D ", &tmp); mob->player.birth.hours = time_info.hours; mob->player.birth.day = time_info.day; mob->player.birth.month = time_info.month; mob->player.birth.year = time_info.year - tmp; fscanf(fl, " %D ", &tmp); mob->player.weight = tmp; fscanf(fl, " %D \n", &tmp); mob->player.height = tmp; for (i = 0; i < 3; i++) { fscanf(fl, " %D ", &tmp); GET_COND(mob, i) = tmp; } fscanf(fl, " \n "); for (i = 0; i < 5; i++) { fscanf(fl, " %D ", &tmp); mob->specials.apply_saving_throw[i] = tmp; } fscanf(fl, " \n "); mob->points.damroll = 0; mob->specials.damnodice = 1; mob->specials.damsizedice = 6; mob->points.hitroll = 0; ************************************* */ } } } while (flag); } /* read an object from OBJ_FILE */ void check_objects(FILE *fl) { int virtual_nr, old_virtual, antal, flag; char *temp; struct obj_data *obj; int tmp, i; char chk[256]; struct extra_descr_data *new_descr; old_virtual = -1; rewind(fl); antal = fscanf(fl, " %s \n", chk); assume(antal, 1, virtual_nr, "First #xxx number"); do { antal = sscanf(chk, " #%d\n", &virtual_nr); assume(antal, 1, virtual_nr, "Reading #xxx"); if (old_virtual > virtual_nr) assume(0, 1, virtual_nr, "Error - #'s not in order."); old_virtual = virtual_nr; temp = fread_string(fl); /* Namelist */ if (flag = (*temp != '$')) { /* a new record to be read */ /* *** string data *** */ /* temp = fread_string(fl); name has been read above */ temp = fread_string(fl); /* short */ temp = fread_string(fl); /* descr */ temp = fread_string(fl); /* action */ /* *** numeric data *** */ antal = fscanf(fl, " %d ", &tmp); assume(antal, 1, virtual_nr, "Error reading type flag"); antal = fscanf(fl, " %d ", &tmp); assume(antal, 1, virtual_nr, "Extra Flag"); antal = fscanf(fl, " %d ", &tmp); assume(antal, 1, virtual_nr, "wear_flags"); antal = fscanf(fl, " %d ", &tmp); assume(antal, 1, virtual_nr, "value[0]"); antal = fscanf(fl, " %d ", &tmp); assume(antal, 1, virtual_nr, "value[1]"); antal = fscanf(fl, " %d ", &tmp); assume(antal, 1, virtual_nr, "value[2]"); antal = fscanf(fl, " %d ", &tmp); assume(antal, 1, virtual_nr, "value[3]"); antal = fscanf(fl, " %d ", &tmp); assume(antal, 1, virtual_nr, "Weight"); antal = fscanf(fl, " %d \n", &tmp); assume(antal, 1, virtual_nr, "Cost"); antal = fscanf(fl, " %d \n", &tmp); assume(antal, 1, virtual_nr, "Cost Per Day"); /* *** extra descriptions *** */ while (fscanf(fl, " %s \n", chk), *chk == 'E') { temp = fread_string(fl); temp = fread_string(fl); } for ( i = 0 ; (i < MAX_OBJ_AFFECT) && (*chk == 'A') ; i++) { antal = fscanf(fl, " %d ", &tmp); assume(antal, 1, virtual_nr, "affected location"); antal = fscanf(fl, " %d \n", &tmp); assume(antal, 1, virtual_nr, "Modifier"); antal = fscanf(fl, " %s \n", chk); assume(antal, 1, virtual_nr, "Next string with E/A/$"); } } } while (flag); } /************************************************************************ * procs of a (more or less) general utility nature * ********************************************************************** */ /* read and allocate space for a '~'-terminated string from a given file */ char *fread_string(FILE *fl) { static char buf[MAX_STRING_LENGTH], tmp[100]; char *rslt; register char *point; int flag; bzero(buf, MAX_STRING_LENGTH); do { if (!fgets(tmp, MAX_STRING_LENGTH, fl)) { printf("fread_str"); exit(); } if (strlen(tmp) + strlen(buf) > MAX_STRING_LENGTH) { printf("fread_string: string too large (db.c, fread_string)"); exit(); } else strcat(buf, tmp); for (point = buf + strlen(buf) - 2; point >= buf && isspace(*point); point--) ; if (flag = (*point == '~')) if (*(buf + strlen(buf) - 3) == '\n') { *(buf + strlen(buf) - 2) = '\r'; *(buf + strlen(buf) - 1) = '\0'; } else *(buf + strlen(buf) - 2) = '\0'; else { *(buf + strlen(buf) + 1) = '\0'; *(buf + strlen(buf)) = '\r'; } } while (!flag); return(buf); } int main(int argc, char *argv[]) { char name[256]; if (argc != 2) { printf("Usage: (from /lib/world dir) %s world-number\n\r", argv[0]); exit(0); } sprintf(name, "wld/%s.wld", argv[1]); if (!(wld_f = fopen(name, "r"))) { printf("Could not open world file.\n\r"); exit(); } sprintf(name, "mob/%s.mob", argv[1]); if (!(mob_f = fopen(name, "r"))) { printf("Could not open mobile file.\n\r"); exit(); } sprintf(name, "obj/%s.obj", argv[1]); if (!(obj_f = fopen(name, "r"))) { printf("Could not open object file.\n\r"); exit(); } sprintf(name, "zon/%s.zon", argv[1]); if (!(zon_f = fopen(name, "r"))) { printf("Could not open zone file.\n\r"); exit(); } printf("Generating world file indexes.\n\r"); wld_index = generate_indices(wld_f, &top_of_wldt); printf("Generating mobile file indexes.\n\r"); mob_index = generate_indices(mob_f, &top_of_mobt); printf("Generating object file indexes.\n\r"); obj_index = generate_indices(obj_f, &top_of_objt); printf("Checking World File.\n\r"); check_world(wld_f); printf("Checking Mobile File (only simple mobiles).\n\r"); check_mobile(mob_f); printf("Checking Object File.\n\r"); check_objects(obj_f); printf("Checking Zone File.\n\r"); check_zones(zon_f); printf("\n\r\nCheck successfully completed without any obvious errors.\n\r"); fclose(zon_f); fclose(wld_f); fclose(mob_f); fclose(obj_f); }