Crossfire Server, Branch 1.12  R12190
gridarta-types-convert.c
Go to the documentation of this file.
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 }