Crossfire Server, Branch 1.12
R12190
|
00001 00024 #include <stdlib.h> 00025 #include <stdio.h> 00026 #include <string.h> 00027 #include <assert.h> 00028 00029 #include "define.h" 00030 00031 const char *destination_dir = "../doc/Developers"; 00032 const char *field_dir = "fields"; 00033 const char *type_dir = "types"; 00036 typedef struct { 00037 char *field; 00038 char *name; 00039 char *description; 00040 } type_attribute; 00041 00043 typedef struct { 00044 int number; 00045 char *name; 00046 char *description; 00047 char *use; 00048 type_attribute **attributes; 00049 int attribute_count; 00050 char **required; 00051 int require_count; 00052 } type_definition; 00053 00055 type_definition **types = NULL; 00056 00057 int type_count = 0; 00058 00060 type_definition *default_type = NULL; 00061 00063 type_definition *fallback_type = NULL; 00064 00066 typedef struct { 00067 char *name; 00068 int count; 00069 char **fields; 00070 } ignore_list; 00071 00072 ignore_list **lists = NULL; 00073 int list_count = 0; 00074 00076 typedef struct { 00077 char **type; 00078 int *number; 00079 int count; 00080 char *description; 00081 } attribute_type; 00082 00084 typedef struct { 00085 char *field; 00086 attribute_type **types; 00087 int type_count; 00088 } attribute_definition; 00089 00090 attribute_definition **attributes = NULL; 00091 int attribute_count = 0; 00092 00094 typedef struct { 00095 const char *field; 00096 const char *code_name; 00097 } flag_definition; 00098 00100 static const flag_definition flags[] = { 00101 { "alive", "FLAG_ALIVE" }, 00102 { "wiz", "FLAG_WIZ" }, 00103 { "was_wiz", "FLAG_WAS_WIZ" }, 00104 { "applied", "FLAG_APPLIED" }, 00105 { "unpaid", "FLAG_UNPAID" }, 00106 { "can_use_shield", "FLAG_USE_SHIELD" }, 00107 { "no_pick", "FLAG_NO_PICK" }, 00108 { "client_anim_sync", "FLAG_CLIENT_ANIM_SYNC" }, 00109 { "client_anim_random", "FLAG_CLIENT_ANIM_RANDOM" }, 00110 { "is_animated", "FLAG_ANIMATE" }, 00111 { "monster", "FLAG_MONSTER" }, 00112 { "friendly", "FLAG_FRIENDLY" }, 00113 { "generator", "FLAG_GENERATOR" }, 00114 { "is_thrown", "FLAG_IS_THROWN" }, 00115 { "auto_apply", "FLAG_AUTO_APPLY" }, 00116 { "treasure", "FLAG_TREASURE" }, 00117 { "player sold", "FLAG_PLAYER_SOLD" }, 00118 { "see_invisible", "FLAG_SEE_INVISIBLE" }, 00119 { "can_roll", "FLAG_CAN_ROLL" }, 00120 { "overlay_floor", "FLAG_OVERLAY_FLOOR" }, 00121 { "is_turnable", "FLAG_IS_TURNABLE" }, 00122 { "is_used_up", "FLAG_IS_USED_UP" }, 00123 { "identified", "FLAG_IDENTIFIED" }, 00124 { "reflecting", "FLAG_REFLECTING" }, 00125 { "changing", "FLAG_CHANGING" }, 00126 { "splitting", "FLAG_SPLITTING" }, 00127 { "hitback", "FLAG_HITBACK" }, 00128 { "startequip", "FLAG_STARTEQUIP" }, 00129 { "blocksview", "FLAG_BLOCKSVIEW" }, 00130 { "undead", "FLAG_UNDEAD" }, 00131 { "scared", "FLAG_SCARED" }, 00132 { "unaggressive", "FLAG_UNAGGRESSIVE" }, 00133 { "reflect_missile", "FLAG_REFL_MISSILE" }, 00134 { "reflect_spell", "FLAG_REFL_SPELL" }, 00135 { "no_magic", "FLAG_NO_MAGIC" }, 00136 { "no_fix_player", "FLAG_NO_FIX_PLAYER" }, 00137 { "is_lightable", "FLAG_IS_LIGHTABLE" }, 00138 { "tear_down", "FLAG_TEAR_DOWN" }, 00139 { "run_away", "FLAG_RUN_AWAY" }, 00140 { "unique", "FLAG_UNIQUE" }, 00141 { "no_drop", "FLAG_NO_DROP" }, 00142 { "can_cast_spell", "FLAG_CAST_SPELL" }, 00143 { "can_use_scroll", "FLAG_USE_SCROLL" }, 00144 { "can_use_range", "FLAG_USE_RANGE" }, 00145 { "can_use_bow", "FLAG_USE_BOW" }, 00146 { "can_use_armour", "FLAG_USE_ARMOUR" }, 00147 { "can_use_weapon", "FLAG_USE_WEAPON" }, 00148 { "can_use_ring", "FLAG_USE_RING" }, 00149 { "has_ready_range", "FLAG_READY_RANGE" }, 00150 { "has_ready_bow", "FLAG_READY_BOW" }, 00151 { "xrays", "FLAG_XRAYS" }, 00152 { "is_floor", "FLAG_IS_FLOOR" }, 00153 { "lifesave", "FLAG_LIFESAVE" }, 00154 { "no_strength", "FLAG_NO_STRENGTH" }, 00155 { "sleep", "FLAG_SLEEP" }, 00156 { "stand_still", "FLAG_STAND_STILL" }, 00157 { "random_movement", "FLAG_RANDOM_MOVE" }, 00158 { "only_attack", "FLAG_ONLY_ATTACK" }, 00159 { "confused", "FLAG_CONFUSED" }, 00160 { "stealth", "FLAG_STEALTH" }, 00161 { "cursed", "FLAG_CURSED" }, 00162 { "damned", "FLAG_DAMNED" }, 00163 { "see_anywhere", "FLAG_SEE_ANYWHERE" }, 00164 { "known_magical", "FLAG_KNOWN_MAGICAL" }, 00165 { "known_cursed", "FLAG_KNOWN_CURSED" }, 00166 { "can_use_skill", "FLAG_CAN_USE_SKILL" }, 00167 { "been_applied", "FLAG_BEEN_APPLIED" }, 00168 { "has_ready_scroll", "FLAG_READY_SCROLL" }, 00169 { "can_use_rod", "FLAG_USE_ROD" }, 00170 { "can_use_horn", "FLAG_USE_HORN" }, 00171 { "make_invisible", "FLAG_MAKE_INVIS" }, 00172 { "inv_locked", "FLAG_INV_LOCKED" }, 00173 { "is_wooded", "FLAG_IS_WOODED" }, 00174 { "is_hilly", "FLAG_IS_HILLY" }, 00175 { "has_ready_skill", "FLAG_READY_SKILL" }, 00176 { "has_ready_weapon", "FLAG_READY_WEAPON" }, 00177 { "no_skill_ident", "FLAG_NO_SKILL_IDENT" }, 00178 { "is_blind", "FLAG_BLIND" }, 00179 { "can_see_in_dark", "FLAG_SEE_IN_DARK" }, 00180 { "is_cauldron", "FLAG_IS_CAULDRON" }, 00181 { "no_steal", "FLAG_NO_STEAL" }, 00182 { "one_hit", "FLAG_ONE_HIT" }, 00183 { "berserk", "FLAG_BERSERK" }, 00184 { "neutral", "FLAG_NEUTRAL" }, 00185 { "no_attack", "FLAG_NO_ATTACK" }, 00186 { "no_damage", "FLAG_NO_DAMAGE" }, 00187 { "activate_on_push", "FLAG_ACTIVATE_ON_PUSH" }, 00188 { "activate_on_release", "FLAG_ACTIVATE_ON_RELEASE" }, 00189 { "is_water", "FLAG_IS_WATER" }, 00190 { "use_content_on_gen", "FLAG_CONTENT_ON_GEN" }, 00191 { "is_buildable", "FLAG_IS_BUILDABLE" }, 00192 { "blessed", "FLAG_BLESSED" }, 00193 { "known_blessed", "FLAG_KNOWN_BLESSED" }, 00194 { NULL, NULL } 00195 }; 00196 00198 const flag_definition *find_flag(const char *name) { 00199 int flag; 00200 00201 for (flag = 0; flags[flag].field; flag++) 00202 if (!strcmp(flags[flag].field, name)) 00203 return &flags[flag]; 00204 return NULL; 00205 } 00206 00207 typedef struct { 00208 const char *code_name; 00209 int value; 00210 } type_name; 00211 00212 static type_name type_names[] = { 00213 { "PLAYER", PLAYER }, 00214 { "TRANSPORT", TRANSPORT }, 00215 { "ROD", ROD }, 00216 { "TREASURE", TREASURE }, 00217 { "POTION", POTION }, 00218 { "FOOD", FOOD }, 00219 { "POISON", POISON }, 00220 { "BOOK", BOOK }, 00221 { "CLOCK", CLOCK }, 00222 { "ARROW", ARROW }, 00223 { "BOW", BOW }, 00224 { "WEAPON", WEAPON }, 00225 { "ARMOUR", ARMOUR }, 00226 { "PEDESTAL", PEDESTAL }, 00227 { "ALTAR", ALTAR }, 00228 { "LOCKED_DOOR", LOCKED_DOOR }, 00229 { "SPECIAL_KEY", SPECIAL_KEY }, 00230 { "MAP", MAP }, 00231 { "DOOR", DOOR }, 00232 { "KEY", KEY }, 00233 { "TIMED_GATE", TIMED_GATE }, 00234 { "TRIGGER", TRIGGER }, 00235 { "GRIMREAPER", GRIMREAPER }, 00236 { "MAGIC_EAR", MAGIC_EAR }, 00237 { "TRIGGER_BUTTON", TRIGGER_BUTTON }, 00238 { "TRIGGER_ALTAR", TRIGGER_ALTAR }, 00239 { "TRIGGER_PEDESTAL", TRIGGER_PEDESTAL }, 00240 { "SHIELD", SHIELD }, 00241 { "HELMET", HELMET }, 00242 { "HORN", HORN }, 00243 { "MONEY", MONEY }, 00244 { "CLASS", CLASS }, 00245 { "AMULET", AMULET }, 00246 { "PLAYERMOVER", PLAYERMOVER }, 00247 { "TELEPORTER", TELEPORTER }, 00248 { "CREATOR", CREATOR }, 00249 { "SKILL", SKILL }, 00250 { "EXPERIENCE", EXPERIENCE }, 00251 { "EARTHWALL", EARTHWALL }, 00252 { "GOLEM", GOLEM }, 00253 { "THROWN_OBJ", THROWN_OBJ }, 00254 { "BLINDNESS", BLINDNESS }, 00255 { "GOD", GOD }, 00256 { "DETECTOR", DETECTOR }, 00257 { "TRIGGER_MARKER", TRIGGER_MARKER }, 00258 { "DEAD_OBJECT", DEAD_OBJECT }, 00259 { "DRINK", DRINK }, 00260 { "MARKER", MARKER }, 00261 { "HOLY_ALTAR", HOLY_ALTAR }, 00262 { "PLAYER_CHANGER", PLAYER_CHANGER }, 00263 { "BATTLEGROUND", BATTLEGROUND }, 00264 { "PEACEMAKER", PEACEMAKER }, 00265 { "GEM", GEM }, 00266 { "FIREWALL", FIREWALL }, 00267 { "CHECK_INV", CHECK_INV }, 00268 { "MOOD_FLOOR", MOOD_FLOOR }, 00269 { "EXIT", EXIT }, 00270 { "ENCOUNTER", ENCOUNTER }, 00271 { "SHOP_FLOOR", SHOP_FLOOR }, 00272 { "SHOP_MAT", SHOP_MAT }, 00273 { "RING", RING }, 00274 { "FLOOR", FLOOR }, 00275 { "FLESH", FLESH }, 00276 { "INORGANIC", INORGANIC }, 00277 { "SKILL_TOOL", SKILL_TOOL }, 00278 { "LIGHTER", LIGHTER }, 00279 { "WALL", WALL }, 00280 { "MISC_OBJECT", MISC_OBJECT }, 00281 { "MONSTER", MONSTER }, 00282 { "LAMP", LAMP }, 00283 { "DUPLICATOR", DUPLICATOR }, 00284 { "SPELLBOOK", SPELLBOOK }, 00285 { "CLOAK", CLOAK }, 00286 { "SPINNER", SPINNER }, 00287 { "GATE", GATE }, 00288 { "BUTTON", BUTTON }, 00289 { "CF_HANDLE", CF_HANDLE }, 00290 { "HOLE", HOLE }, 00291 { "TRAPDOOR", TRAPDOOR }, 00292 { "SIGN", SIGN }, 00293 { "BOOTS", BOOTS }, 00294 { "GLOVES", GLOVES }, 00295 { "SPELL", SPELL }, 00296 { "SPELL_EFFECT", SPELL_EFFECT }, 00297 { "CONVERTER", CONVERTER }, 00298 { "BRACERS", BRACERS }, 00299 { "POISONING", POISONING }, 00300 { "SAVEBED", SAVEBED }, 00301 { "WAND", WAND }, 00302 { "SCROLL", SCROLL }, 00303 { "DIRECTOR", DIRECTOR }, 00304 { "GIRDLE", GIRDLE }, 00305 { "FORCE", FORCE }, 00306 { "POTION_EFFECT", POTION_EFFECT }, 00307 { "EVENT_CONNECTOR", EVENT_CONNECTOR }, 00308 { "CLOSE_CON", CLOSE_CON }, 00309 { "CONTAINER", CONTAINER }, 00310 { "ARMOUR_IMPROVER", ARMOUR_IMPROVER }, 00311 { "WEAPON_IMPROVER", WEAPON_IMPROVER }, 00312 { "SKILLSCROLL", SKILLSCROLL }, 00313 { "DEEP_SWAMP", DEEP_SWAMP }, 00314 { "IDENTIFY_ALTAR", IDENTIFY_ALTAR }, 00315 { "SHOP_INVENTORY", SHOP_INVENTORY }, 00316 { "RUNE", RUNE }, 00317 { "TRAP", TRAP }, 00318 { "POWER_CRYSTAL", POWER_CRYSTAL }, 00319 { "CORPSE", CORPSE }, 00320 { "DISEASE", DISEASE }, 00321 { "SYMPTOM", SYMPTOM }, 00322 { "BUILDER", BUILDER }, 00323 { "MATERIAL", MATERIAL }, 00324 { NULL, 0 } 00325 }; 00326 00327 type_attribute *duplicate_attribute(type_attribute *attr) { 00328 type_attribute *ret = calloc(1, sizeof(type_attribute)); 00329 ret->field = strdup(attr->field); 00330 ret->name = strdup(attr->name); 00331 ret->description = strdup(attr->description); 00332 return ret; 00333 } 00334 00335 void free_attribute(type_attribute *attr) { 00336 free(attr->field); 00337 free(attr->name); 00338 free(attr->description); 00339 free(attr); 00340 } 00341 00346 type_attribute *get_attribute_for_type(type_definition *type, const char *attribute, int clean) { 00347 type_attribute *ret; 00348 int test; 00349 00350 for (test = 0; test < type->attribute_count; test++) { 00351 if (!strcmp(type->attributes[test]->field, attribute)) { 00352 ret = type->attributes[test]; 00353 if (clean) { 00354 free(ret->name); 00355 ret->name = NULL; 00356 free(ret->description); 00357 ret->description = NULL; 00358 } 00359 return ret; 00360 } 00361 } 00362 ret = calloc(1, sizeof(type_attribute)); 00363 ret->field = strdup(attribute); 00364 00365 type->attribute_count++; 00366 type->attributes = realloc(type->attributes, type->attribute_count*sizeof(type_attribute *)); 00367 type->attributes[type->attribute_count-1] = ret; 00368 00369 return ret; 00370 } 00371 00372 void copy_attributes(const type_definition *source, type_definition *type) { 00373 int attr; 00374 type_attribute *add; 00375 00376 assert(source); 00377 if (source->attribute_count == 0) 00378 return; 00379 00380 for (attr = 0; attr < source->attribute_count; attr++) { 00381 add = get_attribute_for_type(type, source->attributes[attr]->field, 1); 00382 add->name = strdup(source->attributes[attr]->name); 00383 if (source->attributes[attr]->description) 00384 add->description = strdup(source->attributes[attr]->description); 00385 } 00386 } 00387 00388 void copy_default_attributes(type_definition *type) { 00389 if (!default_type) 00390 return; 00391 copy_attributes(default_type, type); 00392 } 00393 00397 type_definition *get_type_definition(void) { 00398 type_definition *ret = calloc(1, sizeof(type_definition)); 00399 00400 ret->attribute_count = 0; 00401 ret->attributes = NULL; 00402 assert(ret->description == NULL); 00403 00404 if (default_type) 00405 copy_default_attributes(ret); 00406 00407 return ret; 00408 } 00409 00413 type_definition *find_type_definition(const char *name) { 00414 int type; 00415 00416 for (type = 0; type < type_count; type++) { 00417 if (!strcmp(types[type]->name, name)) 00418 return types[type]; 00419 } 00420 printf("type not found: %s\n", name); 00421 return NULL; 00422 } 00423 00425 int sort_type_attribute(const void *a, const void *b) { 00426 const type_attribute **la = (const type_attribute **)a; 00427 const type_attribute **lb = (const type_attribute **)b; 00428 00429 return strcmp((*la)->name, (*lb)->name); 00430 } 00431 00432 ignore_list *find_ignore_list(const char *name) { 00433 int list; 00434 00435 for (list = 0; list < list_count; list++) { 00436 if (strcmp(lists[list]->name, name) == 0) 00437 return lists[list]; 00438 } 00439 return NULL; 00440 } 00441 00445 char *read_line(char *buffer, int size, FILE *file) { 00446 return fgets(buffer, 200, file); 00447 } 00448 00450 void ignore_attribute(type_definition *type, const char *attribute) { 00451 int find; 00452 00453 for (find = 0; find < type->attribute_count; find++) { 00454 if (!strcmp(attribute, type->attributes[find]->field)) { 00455 /*printf("rem %s from %s\n", list->fields[attr], type->name);*/ 00456 free_attribute(type->attributes[find]); 00457 if (find < type->attribute_count-1) 00458 type->attributes[find] = type->attributes[type->attribute_count-1]; 00459 type->attribute_count--; 00460 return; 00461 } 00462 } 00463 } 00464 00466 void ignore_attributes(type_definition *type, ignore_list *list) { 00467 int attr; 00468 00469 if (!list) { 00470 printf("empty ignore list?\n"); 00471 return; 00472 } 00473 00474 for (attr = 0; attr < list->count; attr++) { 00475 ignore_attribute(type, list->fields[attr]); 00476 } 00477 } 00478 00480 void add_required_parameter(type_definition *type, const char *buf) { 00481 char *sn, *en, *sv, *ev; 00482 char value[200], name[200], temp[200]; 00483 const flag_definition *flag; 00484 00485 if (type == fallback_type) 00486 /* the "Misc" type has dummy requirements, don't take that into account. */ 00487 return; 00488 00489 sn = strstr(buf, "arch"); 00490 if (!sn) 00491 return; 00492 sn = strchr(sn, '"'); 00493 en = strchr(sn+1, '"'); 00494 sv = strstr(buf, "value"); 00495 sv = strchr(sv, '"'); 00496 ev = strchr(sv+1, '"'); 00497 00498 name[en-sn-1] = '\0'; 00499 strncpy(name, sn+1, en-sn-1); 00500 value[ev-sv-1] = '\0'; 00501 strncpy(value, sv+1, ev-sv-1); 00502 00503 type->require_count++; 00504 type->required = realloc(type->required, type->require_count*sizeof(char *)); 00505 00506 flag = find_flag(name); 00507 if (flag) 00508 snprintf(temp, 200, "@ref %s %s", flag->code_name, strcmp(value, "0") ? "set" : "unset"); 00509 else 00510 snprintf(temp, 200, "@ref object::%s = %s", name, value); 00511 type->required[type->require_count-1] = strdup(temp); 00512 } 00513 00515 void read_type(type_definition *type, FILE *file, const char *block_end) { 00516 char buf[200], tmp[200]; 00517 char *find, *end; 00518 type_attribute *attr; 00519 00520 while (read_line(buf, 200, file)) { 00521 if (strstr(buf, block_end) != NULL) { 00522 if (type->attribute_count) 00523 qsort(type->attributes, type->attribute_count, sizeof(type_attribute *), sort_type_attribute); 00524 return; 00525 } 00526 if (strstr(buf, "<description>") != NULL) { 00527 while (read_line(buf, 200, file)) { 00528 if (strstr(buf, "</description>") != NULL) 00529 break; 00530 00531 if (type->description) { 00532 type->description = realloc(type->description, strlen(type->description)+strlen(buf)+1); 00533 strcat(type->description, buf); 00534 } 00535 else 00536 type->description = strdup(buf); 00537 } 00538 find = strstr(type->description, "]]>"); 00539 if (find) 00540 type->description[find-type->description] = '\0'; 00541 while (type->description[strlen(type->description)-1] == '\n') 00542 type->description[strlen(type->description)-1] = '\0'; 00543 /*printf(" => desc = %s\n", type->description);*/ 00544 } 00545 00546 if (strstr(buf, "<ignore_list") != NULL) { 00547 find = strstr(buf, "name="); 00548 if (!find) 00549 return; 00550 find = strchr(find+1, '"'); 00551 if (!find) 00552 return; 00553 end = strchr(find+1, '"'); 00554 if (!end) 00555 return; 00556 tmp[end-find-1] = '\0'; 00557 strncpy(tmp, find+1, end-find-1); 00558 ignore_attributes(type, find_ignore_list(tmp)); 00559 } 00560 00561 if (strstr(buf, "<ignore>") != NULL) { 00562 while (read_line(buf, 200, file)) { 00563 if (strstr(buf, "</ignore>") != NULL) 00564 break; 00565 find = strstr(buf, "arch="); 00566 if (!find) 00567 continue; 00568 find = strchr(find+1, '"'); 00569 if (!find) 00570 continue; 00571 end = strchr(find+1, '"'); 00572 if (!end) 00573 continue; 00574 tmp[end-find-1] = '\0'; 00575 strncpy(tmp, find+1, end-find-1); 00576 ignore_attribute(type, tmp); 00577 } 00578 } 00579 00580 if (strstr(buf, "<required>") != NULL) { 00581 while (read_line(buf, 200, file)) { 00582 if (strstr(buf, "</required>") != NULL) 00583 break; 00584 add_required_parameter(type, buf); 00585 } 00586 } 00587 00588 if (strstr(buf, "<import_type") != NULL) { 00589 type_definition *import; 00590 00591 find = strstr(buf, "name="); 00592 if (!find) 00593 return; 00594 find = strchr(find+1, '"'); 00595 if (!find) 00596 return; 00597 end = strchr(find+1, '"'); 00598 if (!end) 00599 return; 00600 tmp[end-find-1] = '\0'; 00601 strncpy(tmp, find+1, end-find-1); 00602 import = find_type_definition(tmp); 00603 if (import) { 00604 /*printf("%s import %s\n", type->name, tmp);*/ 00605 copy_attributes(import, type); 00606 } 00607 else 00608 printf("%s: import %s not found\n", type->name, tmp); 00609 } 00610 00611 if (strstr(buf, "<attribute") != NULL) { 00612 if (strstr(buf, "/>") != NULL) 00613 continue; 00614 find = strstr(buf, "arch"); 00615 if (!find) 00616 continue; 00617 find = strchr(find, '"'); 00618 end = strchr(find+1, '"'); 00619 if (end == find+1) 00620 /* empty arch, meaning inventory or such, ignore. */ 00621 continue; 00622 00623 tmp[end-find-1] = '\0'; 00624 strncpy(tmp, find+1, end-find-1); 00625 /*printf(" => attr %s\n", tmp);*/ 00626 00627 attr = get_attribute_for_type(type, tmp, 1); 00628 00629 find = strstr(buf, "editor"); 00630 find = strchr(find, '"'); 00631 end = strchr(find+1, '"'); 00632 tmp[end-find-1] = '\0'; 00633 strncpy(tmp, find+1, end-find-1); 00634 attr->name = strdup(tmp); 00635 00636 while (read_line(buf, 200, file)) { 00637 if (strstr(buf, "</attribute>") != NULL) 00638 break; 00639 if (attr->description) { 00640 attr->description = realloc(attr->description, strlen(attr->description)+strlen(buf)+1); 00641 strcat(attr->description, buf); 00642 } 00643 else 00644 attr->description = strdup(buf); 00645 } 00646 if (attr->description) 00647 while (attr->description[strlen(attr->description)-1] == '\n') 00648 attr->description[strlen(attr->description)-1] = '\0'; 00649 00650 } 00651 } 00652 } 00653 00654 void dump_type(type_definition *type) { 00655 int attr; 00656 00657 printf("type: %s [%d]\n", type->name, type->number); 00658 printf(" attributes:\n"); 00659 for (attr = 0; attr < type->attribute_count; attr++) { 00660 printf(" %30s: %s\n", type->attributes[attr]->field, type->attributes[attr]->name); 00661 printf(" %s\n", type->attributes[attr]->description); 00662 } 00663 } 00664 00665 void dump_types(void) { 00666 int t; 00667 type_definition *type; 00668 00669 for (t = 0; t < type_count; t++) { 00670 type = types[t]; 00671 dump_type(type); 00672 } 00673 } 00674 00676 attribute_definition *get_attribute(const char *name) { 00677 int attr; 00678 attribute_definition *ret; 00679 00680 for (attr = 0; attr < attribute_count; attr++) { 00681 if (!strcmp(attributes[attr]->field, name)) 00682 return attributes[attr]; 00683 } 00684 00685 ret = calloc(1, sizeof(attribute_definition)); 00686 attribute_count++; 00687 attributes = realloc(attributes, attribute_count*sizeof(attribute_definition *)); 00688 attributes[attribute_count-1] = ret; 00689 00690 ret->field = strdup(name); 00691 00692 return ret; 00693 } 00694 00696 attribute_type *get_description_for_attribute(attribute_definition *attribute, const char *description) { 00697 int desc; 00698 attribute_type *add; 00699 00700 for (desc = 0; desc < attribute->type_count; desc++) { 00701 if (!description && !attribute->types[desc]->description) 00702 return attribute->types[desc]; 00703 if (description && attribute->types[desc]->description && !strcmp(description, attribute->types[desc]->description)) 00704 return attribute->types[desc]; 00705 } 00706 00707 add = calloc(1, sizeof(attribute_type)); 00708 attribute->type_count++; 00709 attribute->types = realloc(attribute->types, attribute->type_count*sizeof(attribute_type)); 00710 attribute->types[attribute->type_count-1] = add; 00711 00712 if (description) 00713 add->description = strdup(description); 00714 00715 return add; 00716 } 00717 00718 void add_type_to_attribute(attribute_definition *attribute, type_definition *type, int attr) { 00719 attribute_type *att; 00720 00721 att = get_description_for_attribute(attribute, type->attributes[attr]->description); 00722 att->count++; 00723 att->type = realloc(att->type, att->count*sizeof(const char *)); 00724 att->number = realloc(att->number, att->count*sizeof(int)); 00725 att->type[att->count-1] = strdup(type->name); 00726 att->number[att->count-1] = type->number; 00727 } 00728 00730 void read_ignore_list(const char *name, FILE *file) { 00731 char buf[200], tmp[200]; 00732 char *start, *end; 00733 ignore_list *list; 00734 00735 /*printf("il %s:", name);*/ 00736 list = calloc(1, sizeof(ignore_list)); 00737 list_count++; 00738 lists = realloc(lists, list_count*sizeof(ignore_list *)); 00739 lists[list_count-1] = list; 00740 list->name = strdup(name); 00741 00742 while (read_line(buf, 200, file)) { 00743 if (strstr(buf, "</ignore_list>") != NULL) { 00744 /*printf("\n");*/ 00745 return; 00746 } 00747 start = strstr(buf, "arch="); 00748 if (!start) 00749 continue; 00750 start = strchr(start+1, '"'); 00751 if (!start) 00752 continue; 00753 end = strchr(start+1, '"'); 00754 if (!end) 00755 continue; 00756 00757 tmp[end-start-1] = '\0'; 00758 strncpy(tmp, start+1, end-start-1); 00759 /*printf(" %s", tmp);*/ 00760 00761 list->count++; 00762 list->fields = realloc(list->fields, list->count*sizeof(char *)); 00763 list->fields[list->count-1] = strdup(tmp); 00764 } 00765 } 00766 00767 void dump_ignore_lists(void) { 00768 int list, field; 00769 00770 printf("ignore lists:\n"); 00771 for (list = 0; list < list_count; list++) { 00772 printf(" %s:", lists[list]->name); 00773 for (field = 0; field < lists[list]->count; field++) 00774 printf(" %s", lists[list]->fields[field]); 00775 printf("\n"); 00776 } 00777 } 00778 00780 static const char *in_living[] = { 00781 "Str", 00782 "Dex", 00783 "Con", 00784 "Wis", 00785 "Cha", 00786 "Int", 00787 "Pow", 00788 "wc", 00789 "ac", 00790 "hp", 00791 "maxhp", 00792 "sp", 00793 "maxsp", 00794 "grace", 00795 "maxgrace", 00796 "exp", 00797 "food", 00798 "dam", 00799 "luck", 00800 NULL 00801 }; 00802 00804 static const char *custom_attributes[] = { 00805 /* transports */ 00806 "weight_speed_ratio", 00807 "base_speed", 00808 "passenger_limit", 00809 "face_full", 00810 "anim_full", 00811 NULL 00812 }; 00813 00814 int is_custom_attribute(const char *attribute) { 00815 int val; 00816 00817 for (val = 0; custom_attributes[val] != NULL; val++) { 00818 if (!strcmp(custom_attributes[val], attribute)) { 00819 return 1; 00820 } 00821 } 00822 return 0; 00823 } 00824 00826 void write_attribute_reference(const char *attribute, FILE *file) { 00827 const flag_definition *flag = find_flag(attribute); 00828 int val; 00829 00830 if (flag) { 00831 fprintf(file, "%s", flag->code_name); 00832 return; 00833 } 00834 for (val = 0; in_living[val] != NULL; val++) { 00835 if (!strcmp(in_living[val], attribute)) { 00836 fprintf(file, "liv::%s", attribute); 00837 return; 00838 } 00839 } 00840 if (is_custom_attribute(attribute)) { 00841 fprintf(file, "page_custom_attributes \"%s\"", attribute); 00842 return; 00843 } 00844 if (strstr(attribute, "resist_")) { 00845 fprintf(file, "obj::resist"); 00846 return; 00847 } 00848 if (!strcmp(attribute, "connected")) { 00849 fprintf(file, "page_connected \"connection value\""); 00850 return; 00851 } 00852 fprintf(file, "obj::%s", attribute); 00853 } 00854 00856 void write_type_file(type_definition *type) { 00857 FILE *file; 00858 char buf[200]; 00859 int attr, req; 00860 00861 snprintf(buf, 200, "%s/%s/type_%d.dox", destination_dir, type_dir, type->number); 00862 file = fopen(buf, "w+"); 00863 00864 fprintf(file, "/**\n"); 00865 00866 /* auto-generate documentation for the type, so no need to change define.h */ 00867 if (type->number > 0) { 00868 for (req = 0; type_names[req].code_name != NULL; req++) { 00869 if (type_names[req].value == type->number) { 00870 fprintf(file, "@var %s\nSee @ref page_type_%d\n*/\n\n/**\n", type_names[req].qcode_name, type->number); 00871 break; 00872 } 00873 } 00874 } 00875 00876 fprintf(file, "@page page_type_%d %s\n\n", type->number, type->name); 00877 fprintf(file, "\n@section Description\n"); 00878 fprintf(file, "%s\n\n", type->description); 00879 if (type != fallback_type) { 00880 fprintf(file, "\n\nType defined by:\n"); 00881 if (type->number && type->number < OBJECT_TYPE_MAX) 00882 fprintf(file, "- @ref object::type = %d\n", type->number); 00883 for (req = 0; req < type->require_count; req++) 00884 fprintf(file, "- %s\n", type->required[req]); 00885 } 00886 00887 fprintf(file, "\n\n@section Attributes\n\n"); 00888 fprintf(file, "<table>\n\t<tr>\n\t\t<th>Attribute</th>\n\t\t<th>Field</th>\n\t\t<th>Description</th>\n\t</tr>\n"); 00889 for (attr = 0; attr < type->attribute_count; attr++) { 00890 fprintf(file, "\t<tr>\n\t\t<td>%s</td>\n\t\t<td>@ref ", type->attributes[attr]->name); 00891 write_attribute_reference(type->attributes[attr]->field, file); 00892 fprintf(file, "</td>\n\t\t<td>%s\n\t\t</td>\n\t</tr>\n", type->attributes[attr]->description ? type->attributes[attr]->description : "(no description)"); 00893 } 00894 00895 fprintf(file, "</table>\n*/\n"); 00896 00897 fclose(file); 00898 } 00899 00901 void write_type_index(void) { 00902 FILE *index; 00903 int type; 00904 char buf[200]; 00905 00906 snprintf(buf, 200, "%s/%s/types.dox", destination_dir, type_dir); 00907 index = fopen(buf, "w+"); 00908 fprintf(index, "/**\n@page type_index Type index\n"); 00909 00910 fprintf(index, "Types not listed here have the attributes defined in @ref page_type_0 \"this page\".\n\n"); 00911 00912 for (type = 0; type < type_count; type++) { 00913 fprintf(index, "-@ref page_type_%d \"%s\"\n", types[type]->number, types[type]->name); 00914 } 00915 00916 fprintf(index, "*/\n"); 00917 00918 fclose(index); 00919 } 00920 00922 void write_attribute_file(attribute_definition *attribute) { 00923 FILE *file; 00924 char buf[200]; 00925 int type, desc; 00926 const char *end; 00927 00928 snprintf(buf, 200, "%s/%s/field_%s.dox", destination_dir, field_dir, attribute->field); 00929 file = fopen(buf, "w+"); 00930 00931 fprintf(file, "/**\n@fn "); 00932 write_attribute_reference(attribute->field, file); 00933 00934 /* resistances are special, they'll be merged in the obj::resist paragraph, so specify the name. */ 00935 if (strstr(attribute->field, "resist_")) 00936 fprintf(file, "\n@section %s %s resistance\n", attribute->field, attribute->field+7); 00937 else 00938 fprintf(file, "\n@section Use\n"); 00939 00940 fprintf(file, "<table>\n\t<tr>\n\t\t<th>Type(s)</th>\n\t\t<th>Description</th>\n\t</tr>"); 00941 00942 for (desc = 0; desc < attribute->type_count; desc++) { 00943 assert(attribute->types[desc]->count > 0); 00944 00945 fprintf(file, "\t<tr>\n\t\t<td>\n"); 00946 00947 for (type = 0; type < attribute->types[desc]->count; type++) { 00948 if (type < attribute->types[desc]->count-1) 00949 end = ", "; 00950 else 00951 end = "\n"; 00952 fprintf(file, "@ref page_type_%d%s", attribute->types[desc]->number[type], end); 00953 } 00954 fprintf(file, "\t\t</td><td>%s</td>\n\t</tr>\n", attribute->types[desc]->description ? attribute->types[desc]->description : "(no description)"); 00955 } 00956 00957 fprintf(file, "\n*/\n"); 00958 00959 fclose(file); 00960 } 00961 00962 int main(int argc, char **argv) { 00963 FILE *xml; 00964 int number, attr, dummy; 00965 char buf[200], tmp[200]; 00966 char *start, *end; 00967 type_definition *type; 00968 00969 if (argc < 2) { 00970 printf("Syntax: %s /path/to/Gridarta/types.xml\n", argv[0]); 00971 return 1; 00972 } 00973 00974 /* dummy type number for special types. */ 00975 dummy = OBJECT_TYPE_MAX+50; 00976 00977 xml = fopen(argv[1], "r"); 00978 while (read_line(buf, 200, xml) != NULL) { 00979 if (buf[0] == '#') 00980 continue; 00981 if (strstr(buf, "<default_type>")) { 00982 default_type = get_type_definition(); 00983 default_type->name = strdup("(default type)"); 00984 read_type(default_type, xml, "</default_type>"); 00985 continue; 00986 } 00987 00988 if (strstr(buf, "<ignore_list") != NULL) { 00989 start = strstr(buf, "name="); 00990 start = strchr(start+1, '"'); 00991 end = strchr(start+1, '"'); 00992 tmp[end-start-1] = '\0'; 00993 strncpy(tmp, start+1, end-start-1); 00994 read_ignore_list(tmp, xml); 00995 continue; 00996 } 00997 00998 start = strstr(buf, "<type number"); 00999 if (start) { 01000 start = strchr(start, '"'); 01001 /*if (!start) 01002 break;*/ 01003 end = strchr(start+1, '"'); 01004 /*if (!end) 01005 break;*/ 01006 tmp[end-start-1] = '\0'; 01007 strncpy(tmp, start+1, end-start-1); 01008 /*printf("type %s ", tmp);*/ 01009 01010 number = atoi(tmp); 01011 start = strstr(end, "name="); 01012 start = strchr(start, '"'); 01013 end = strchr(start+1, '"'); 01014 tmp[end-start-1] = '\0'; 01015 strncpy(tmp, start+1, end-start-1); 01016 01017 if (!strcmp(tmp, "Misc")) { 01018 fallback_type = get_type_definition(); 01019 type = fallback_type; 01020 } 01021 else { 01022 if (number == 0) 01023 number = dummy++; 01024 type = get_type_definition(); 01025 type_count++; 01026 types = realloc(types, type_count*sizeof(type_definition *)); 01027 types[type_count-1] = type; 01028 } 01029 01030 #if 0 01031 if (!number || number >= OBJECT_TYPE_MAX || types[number] != NULL) { 01032 /*printf("=> skip\n");*/ 01033 while (read_line(buf, 200, xml) != NULL && strstr(buf, "</type>") == NULL) 01034 /*printf(" => skip %s\n", buf)*/; 01035 /*printf(" => end of skip\n");*/ 01036 continue; 01037 } 01038 #endif 01039 01040 type->number = number; 01041 01042 /*printf("nom %s\n", tmp);*/ 01043 type->name = strdup(tmp); 01044 01045 read_type(type, xml, "</type>"); 01046 } 01047 } 01048 01049 if (fallback_type->description) 01050 free(fallback_type->description); 01051 fallback_type->description = strdup("This type regroups all types who don't have a specific definition."); 01052 01053 for (number = 0; number < type_count; number++) { 01054 for (attr = 0; attr < types[number]->attribute_count; attr++) 01055 add_type_to_attribute(get_attribute(types[number]->attributes[attr]->field), types[number], attr); 01056 } 01057 01058 /* dump_types();*/ 01059 /* dump_type(default_type);*/ 01060 /* dump_ignore_lists();*/ 01061 01062 write_type_index(); 01063 for (number = 0; number < type_count; number++) 01064 write_type_file(types[number]); 01065 write_type_file(fallback_type); 01066 01067 for (attr = 0; attr < attribute_count; attr++) 01068 if (!is_custom_attribute(attributes[attr]->field)) 01069 write_attribute_file(attributes[attr]); 01070 01071 fclose(xml); 01072 free(types); 01073 return 0; 01074 }