2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 //#define FGD_VERBOSE // define this for extra info in the log.
27 \brief .fgd entity description format
29 FGD loading code by Dominic Clifton - Hydra (Hydra@Hydras-World.com)
34 This module loads .fgd files, fgd files are split into classes:
37 point classes (aka fixed size entities)
38 solid classes (aka brush entity)
40 This program first scans each file, building up a list structures
41 in memory that contain the information for all the classes found
44 Then the program looks at each of the non-base classes in the list
45 and build the eclass_t structure from each one.
47 Classes can request information in other classes.
49 Solid/Base and Point/Base classes can have the same names as other
50 classes but there can be only one of each solid/point/base class with
77 - sets e->skinpath when it finds an iconsprite(<filename>) token.
80 - Core now supports > 8 spawnflags, changes reflected here too.
81 - FIXED: mins/maxs were backwards when only w,h,d were in the FGD
82 (as opposed to the actual mins/maxs being in the .def file)
83 - Made sure all PointClass entities were fixed size entities
84 and gave them a default bounding box size if a size() setting
85 was not in the FGD file.
86 - Removed the string check for classes requesting another class
87 with the same name, adjusted Find_Class() so that it can search
88 for baseclasses only, this fixes the problem with PointClass "light"
89 requesting the BaseClass "light".
92 - bleh, It turns out that non-baseclasses can request non-baseclasses
93 so now I've changed Find_Class() so that it can ignore a specific class
94 (i.e. the one that's asking for others, so that classes can't request
95 themselves but they can request other classes of any kind with the
97 - made all spawnflag comments appear in one place, rather than being scattered
98 all over the comments if a requested class also had some spawnflags
101 - not using skinpath for sprites anymore, apprently we can code a model
102 module to display sprites and model files.
103 - model() tags are now supported.
108 * add support for setting the eclass_t's modelpath.
109 (not useful for CS, but very useful for HL).
111 * need to implement usage for e->skinpath in the core.
113 * cleanup some areas now that GetTokenExtra() is available
114 (some parts were written prior to it's creation).
116 * Import the comments between each BaseClass's main [ ] set.
117 (unfortunatly they're // cstyle comments, which GetToken skips over)
118 But still ignore comments OUTSIDE the main [ ] set.
122 _QERScripLibTable g_ScripLibTable;
123 _EClassManagerTable g_EClassManagerTable;
124 _QERFuncTable_1 g_FuncTable;
125 _QERFileSystemTable g_FileSystemTable;
128 void Eclass_ScanFile (char *filename);
130 const char* EClass_GetExtension()
135 CSynapseServer* g_pSynapseServer = NULL;
136 CSynapseClientFGD g_SynapseClient;
139 #pragma GCC visibility push(default)
141 extern "C" CSynapseClient* SYNAPSE_DLL_EXPORT Synapse_EnumerateInterfaces( const char *version, CSynapseServer *pServer ) {
143 #pragma GCC visibility pop
145 if (strcmp(version, SYNAPSE_VERSION))
147 Syn_Printf("ERROR: synapse API version mismatch: should be '" SYNAPSE_VERSION "', got '%s'\n", version);
150 g_pSynapseServer = pServer;
151 g_pSynapseServer->IncRef();
152 Set_Syn_Printf(g_pSynapseServer->Get_Syn_Printf());
154 g_SynapseClient.AddAPI(ECLASS_MAJOR, "fgd", sizeof(_EClassTable));
155 g_SynapseClient.AddAPI(SCRIPLIB_MAJOR, NULL, sizeof(g_ScripLibTable), SYN_REQUIRE, &g_ScripLibTable);
156 g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(g_FuncTable), SYN_REQUIRE, &g_FuncTable);
157 g_SynapseClient.AddAPI(ECLASSMANAGER_MAJOR, NULL, sizeof(g_EClassManagerTable), SYN_REQUIRE, &g_EClassManagerTable);
159 // Needs a 'default' option for this minor because we certainly don't load anything from wad files :)
160 g_SynapseClient.AddAPI(VFS_MAJOR, "wad", sizeof(g_FileSystemTable), SYN_REQUIRE, &g_FileSystemTable);
162 return &g_SynapseClient;
165 bool CSynapseClientFGD::RequestAPI(APIDescriptor_t *pAPI)
167 if (!strcmp(pAPI->major_name, ECLASS_MAJOR))
169 _EClassTable* pTable= static_cast<_EClassTable*>(pAPI->mpTable);
171 pTable->m_pfnGetExtension = &EClass_GetExtension;
172 pTable->m_pfnScanFile = &Eclass_ScanFile;
177 Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo());
183 const char* CSynapseClientFGD::GetInfo()
185 return ".fgd eclass module built " __DATE__ " " RADIANT_VERSION;
188 // ------------------------------------------------------------------------------------------------
190 #define CLASS_NOCLASS 0
191 #define CLASS_BASECLASS 1
192 #define CLASS_POINTCLASS 2
193 #define CLASS_SOLIDCLASS 3
195 char *classnames[] = {"NOT DEFINED","BaseClass","PointClass","SolidClass"};
197 #define OPTION_NOOPTION 0
198 #define OPTION_STRING 1
199 #define OPTION_CHOICES 2
200 #define OPTION_INTEGER 3
201 #define OPTION_FLAGS 4
203 char *optionnames[] = {"NOT DEFINED","String","Choices","Integer","Flags"};
205 typedef struct choice_s {
210 typedef struct option_s {
215 GSList *choices; // list of choices_t
218 typedef struct class_s {
219 int classtype; // see CLASS_* above.
221 GSList *l_baselist; // when building the eclass_t, other class_s's with these names are required.
224 GSList *l_optionlist; // when building the eclass_t, other class_s's with these names are required.
226 bool gotsize; // if set then boundingbox is valid.
227 vec3_t boundingbox[2]; // mins, maxs
229 bool gotcolor; // if set then color is valid.
230 vec3_t color; // R,G,B, loaded as 0-255
232 char *model; // relative path + filename to a model (.spr/.mdl) file, or NULL
236 ===========================================================
239 ===========================================================
241 char *strlower (char *start)
253 char *addstr(char *dest,char *source)
258 int len = strlen(dest);
259 ptr = (char *) malloc (len + strlen(source) + 1);
261 strcpy(ptr+len,source);
267 dest = strdup(source);
272 int getindex(unsigned int a)
274 unsigned int count = 0;
276 for (;b != a;count++)
285 void ClearGSList (GSList* lst)
291 p = g_slist_remove (p, p->data);
296 free a choice_t structure and it's contents
298 void Free_Choice(choice_t *p)
300 if (p->name) free(p->name);
306 ===========================================================
309 ===========================================================
313 free an option_t structure and it's contents
315 void Free_Option(option_t *p)
317 if (p->epairname) free(p->epairname);
318 if (p->optiondefault) free(p->optiondefault);
319 if (p->optioninfo) free(p->optioninfo);
320 GSList *l = p->choices;
323 Free_Choice ((choice_t *)l->data);
324 l = g_slist_remove (l, l->data);
330 free a class_t structure and it's contents
332 void Free_Class(class_t *p)
334 GSList *l = p->l_optionlist;
337 Free_Option ((option_t *)l->data);
338 l = g_slist_remove (l, l->data);
341 if (p->classname) free(p->classname);
346 find a class in the list
348 class_t *Find_Class(GSList *l,char *classname, class_t *ignore)
350 for (GSList *clst = l; clst != NULL; clst = clst->next)
352 class_t *c = (class_t *)clst->data;
357 // NOTE: to speed up we could make all the classnames lower-case when they're initialised.
358 if (!stricmp(c->classname,classname))
368 Import as much as possible from a class_t into an eclass_t
369 Note: this is somewhat recursive, as a class can require a class that requires a class and so on..
371 void EClass_ImportFromClass(eclass_t *e, GSList *l_classes, class_t *bc)
375 // We allocate 16k here, but only the memory actually used is kept allocated.
376 // this is just used for building the final comments string.
377 // Note: if the FGD file contains comments that are >16k (per entity) then
378 // radiant will crash upon loading such a file as the eclass_t will become
380 // FIXME: we could add some length checking when building "newcomments", but
381 // that'd slow it down a bit.
382 char newcomments[16384] = "";
384 //Note: we override the values already in e.
385 //and we do it in such a way that the items that appear last in the l_baselist
386 //represent the final values.
390 sprintf(newcomments,"%s\n",bc->description);
391 e->comments = addstr(e->comments,newcomments);
392 newcomments[0] = 0; // so we don't add them twice.
396 // import from other classes if required.
400 // this class requires other base classes.
402 for (GSList *bclst = bc->l_baselist; bclst != NULL; bclst = bclst->next)
404 char *requestedclass = (char *)bclst->data;
406 // class_t *rbc = Find_Class(l_classes, requestedclass, true);
407 class_t *rbc = Find_Class(l_classes, requestedclass, bc);
409 // make sure we don't request ourself!
412 Sys_Printf ("WARNING: baseclass '%s' tried to request itself!\n", bclst->data);
418 Sys_Printf ("WARNING: could not find the requested baseclass '%s' when building '%s'\n", requestedclass,bc->classname);
423 EClass_ImportFromClass(e, l_classes, rbc);
432 memcpy(e->mins,bc->boundingbox[0],sizeof( vec3_t ));
433 memcpy(e->maxs,bc->boundingbox[1],sizeof( vec3_t ));
436 // Hydra: apparently, this would be bad.
440 // Hydra - NOTE: e->skinpath is not currently used by the editor but the code
441 // to set it is used by both this eclass_t loader and the .DEF eclass_t loader.
442 // TODO: implement using e->skinpath.
446 e->skinpath = strdup(bc->sprite);
456 e->modelpath = strdup(bc->model);
462 memcpy(e->color,bc->color,sizeof( vec3_t ));
463 sprintf (color, "(%f %f %f)", e->color[0], e->color[1], e->color[2]);
464 e->texdef.SetName(color);
467 // SPAWNFLAGS and COMMENTS
468 if (bc->l_optionlist)
470 for (GSList *optlst = bc->l_optionlist; optlst != NULL; optlst = optlst->next)
472 option_t *opt = (option_t*) optlst->data;
474 if (opt->optiontype != OPTION_FLAGS)
476 // add some info to the comments.
479 sprintf(newcomments+strlen(newcomments),"%s '%s' %s%s\n",
481 opt->optioninfo ? opt->optioninfo : "",
482 opt->optiondefault ? ", Default: " : "",
483 opt->optiondefault ? opt->optiondefault : "");
487 sprintf(newcomments+strlen(newcomments),"%s %s%s\n",
489 opt->optiondefault ? ", Default: " : "",
490 opt->optiondefault ? opt->optiondefault : "");
495 switch(opt->optiontype)
499 for (choicelst = opt->choices; choicelst != NULL; choicelst = choicelst->next)
501 choice_t *choice = (choice_t*) choicelst->data;
503 int index = getindex(choice->value);
505 if (index < MAX_FLAGS)
507 strcpy(e->flagnames[index],choice->name);
511 Sys_Printf ("WARNING: baseclass '%s' has a spawnflag out of range, ignored!\n", bc->classname);
515 case OPTION_CHOICES :
516 strcat(newcomments," Choices:\n");
517 for (choicelst = opt->choices; choicelst != NULL; choicelst = choicelst->next)
519 choice_t *choice = (choice_t*) choicelst->data;
520 sprintf(newcomments+strlen(newcomments)," %5d - %s\n",choice->value,choice->name);
528 if (e->name) free(e->name);
529 e->name = strdup(bc->classname);
531 // fixed size initialisation
532 if (bc->classtype == CLASS_POINTCLASS)
535 // some point classes dont seem to have size()'s in the fgd, so set up a default here..
536 if ((e->mins[0] == 0) && (e->mins[1] == 0) && (e->mins[2] == 0) &&
537 (e->maxs[0] == 0) && (e->maxs[1] == 0) && (e->maxs[2] == 0))
547 if (e->texdef.GetName() == NULL)
549 // no color specified for this entity in the fgd file
551 // Note: if this eclass_t is not fully built, then this may be
552 // overridden with the correct color.
555 e->color[1] = 0.5; // how about a nice bright pink, mmm, nice! :)
558 sprintf (color, "(%f %f %f)", e->color[0], e->color[1], e->color[2]);
559 e->texdef.SetName(color);
566 e->comments = addstr(e->comments,newcomments);
571 create the eclass_t structures and add to the global list.
573 void Create_EClasses(GSList *l_classes)
576 // loop through the loaded structures finding all the non BaseClasses
577 for (GSList *clst = l_classes; clst != NULL; clst = clst->next)
579 class_t *c = (class_t *)clst->data;
581 if (c->classtype == CLASS_BASECLASS) // not looking for these.
584 eclass_t *e = (eclass_t *) malloc( sizeof( eclass_s ));
585 memset(e,0,sizeof( eclass_s ));
587 EClass_ImportFromClass(e, l_classes, c );
589 // radiant will crash if this is null, and it still could be at this point.
592 e->comments=strdup("No description available, check documentation\n");
595 // dump the spawnflags to the end of the comments.
599 havespawnflags = false;
600 for (i = 0 ; i < MAX_FLAGS ; i++)
602 if (*e->flagnames[i]) havespawnflags = true;
608 e->comments = addstr(e->comments,"Spawnflags\n");
609 for (i = 0 ; i < MAX_FLAGS ; i++)
611 if (*e->flagnames[i])
613 sprintf(spawnline," %d - %s\n", 1<<i, e->flagnames[i]);
614 e->comments = addstr(e->comments,spawnline);
619 Eclass_InsertAlphabetized (e);
621 // Hydra: ttimo, I don't think this code is required...
624 Set_Eclass_Found(true);
625 if ( Get_Parsing_Single() )
629 Sys_Printf ("FGD Loaded %d entities.\n", count);
632 void Eclass_ScanFile (char *filename)
637 GSList *l_classes = NULL;
638 char token_debug[1024]; //++Hydra FIXME: cleanup this.
642 char *token = Token();
644 QE_ConvertDOSToUnixName( temp, filename );
646 size = vfsLoadFullPathFile (filename, (void**)&data);
649 Sys_FPrintf (SYS_ERR, "Eclass_ScanFile: %s not found\n", filename);
652 Sys_Printf ("ScanFile: %s\n", temp);
654 // start parsing the file
655 StartTokenParsing(data);
657 // build a list of base classes first
669 } while (token[0] != '@');
671 strcpy(temp,token+1); // skip the @
673 classtype = CLASS_NOCLASS;
674 if (!stricmp(temp,"BaseClass")) classtype = CLASS_BASECLASS;
675 if (!stricmp(temp,"PointClass")) classtype = CLASS_POINTCLASS;
676 if (!stricmp(temp,"SolidClass")) classtype = CLASS_SOLIDCLASS;
680 class_t *newclass = (class_t *) malloc( sizeof(class_s) );
681 memset( newclass, 0, sizeof(class_s) );
682 newclass->classtype = classtype;
686 GetTokenExtra(false,"(",false); // option or =
687 strcpy(token_debug,token);
689 if (!strcmp(token,"="))
697 if (!strcmp(token,"base"))
699 GetTokenExtra(false,"(",true); // (
701 if (!strcmp(token,"("))
703 while (GetTokenExtra(false,",)",false)) // option) or option,
705 newclass->l_baselist = g_slist_append (newclass->l_baselist, strdup(token));
707 GetTokenExtra(false,",)",true); // , or )
708 if (!strcmp(token,")"))
714 else if (!strcmp(token,"size"))
716 // parse (w h d) or (x y z, x y z)
718 GetTokenExtra(false,"(",true); // (
719 if (!strcmp(token,"("))
721 int sizedone = false;
727 GetToken(false); // number) or number ,
730 if (temp[len-1] == ')') sizedone = true;
735 // only one set of cordinates supplied, change the W,H,D to mins/maxs
736 newclass->boundingbox[0][0] = 0 - (w / 2);
737 newclass->boundingbox[1][0] = w / 2;
738 newclass->boundingbox[0][1] = 0 - (h / 2);
739 newclass->boundingbox[1][1] = h / 2;
740 newclass->boundingbox[0][2] = 0 - (d / 2);
741 newclass->boundingbox[1][2] = d / 2;
742 newclass->gotsize = true;
746 newclass->boundingbox[0][0] = w;
747 newclass->boundingbox[0][1] = h;
748 newclass->boundingbox[0][2] = d;
750 newclass->boundingbox[1][0] = atof(token);
752 newclass->boundingbox[1][1] = atof(token);
754 GetToken(false); // "number)" or "number )"
757 if (temp[len-1] == ')')
760 GetToken(false); // )
761 newclass->boundingbox[1][2] = atof(temp);
763 GetTokenExtra(false,")",false); // number
764 newclass->boundingbox[1][2] = atof(token);
765 newclass->gotsize = true;
766 GetTokenExtra(false,")",true); // )
770 else if (!strcmp(token,"color"))
772 GetTokenExtra(false,"(",true); // (
773 if (!strcmp(token,"("))
775 // get the color values (0-255) and normalize them if required.
777 newclass->color[0] = atof(token);
778 if (newclass->color[0] > 1)
779 newclass->color[0]/=255;
781 newclass->color[1] = atof(token);
782 if (newclass->color[1] > 1)
783 newclass->color[1]/=255;
787 if (temp[len-1] == ')') temp[len-1] = 0;
788 newclass->color[2] = atof(temp);
789 if (newclass->color[2] > 1)
790 newclass->color[2]/=255;
791 newclass->gotcolor = true;
794 else if (!strcmp(token,"iconsprite"))
796 GetTokenExtra(false,"(",true); // (
797 if (!strcmp(token,"("))
799 GetTokenExtra(false,")",false); // filename)
800 // the model plugins will handle sprites too.
801 // newclass->sprite = strdup(token);
802 newclass->model = strdup(token);
803 GetTokenExtra(false,")",true); // )
806 else if (!strcmp(token,"model"))
808 GetTokenExtra(false,"(",true); // (
809 if (!strcmp(token,"("))
811 GetTokenExtra(false,")",false); // filename)
812 newclass->model = strdup(token);
813 GetTokenExtra(false,")",true); // )
819 GetToken(false); // skip it.
825 GetToken(false); // =
826 strcpy(token_debug,token);
827 if (!strcmp(token,"="))
830 newclass->classname = strdup(token);
833 // Get the description
834 if (newclass->classtype != CLASS_BASECLASS)
837 if (!strcmp(token,":"))
840 newclass->description = strdup(token);
841 } else UnGetToken(); // no description
844 // now build the option list.
845 GetToken(true); // [ or []
847 if (strcmp(token,"[]")) // got some options ?
849 if (!strcmp(token,"["))
852 bool optioncomplete = false;
858 if (!strcmp(token,"]"))
859 break; // no more options
861 // parse the data and build the option_t
865 char *ptr = strchr(temp,'(');
870 newoption = (option_t *) malloc ( sizeof( option_s ));
871 memset( newoption, 0, sizeof( option_s ));
874 newoption->epairname = strdup(temp);
877 if (ptr[len-1] != ')')
882 if (!strcmp(ptr,"integer"))
884 newoption->optiontype = OPTION_INTEGER;
886 else if (!strcmp(ptr,"choices"))
888 newoption->optiontype = OPTION_CHOICES;
890 else if (!strcmp(ptr,"flags"))
892 newoption->optiontype = OPTION_FLAGS;
896 newoption->optiontype = OPTION_STRING;
899 switch (newoption->optiontype)
902 case OPTION_INTEGER :
903 if (!TokenAvailable())
905 optioncomplete = true;
908 GetToken(false); // :
909 strcpy(token_debug,token);
910 if ((token[0] == ':') && (strlen(token) > 1))
912 newoption->optioninfo = strdup(token+1);
917 newoption->optioninfo = strdup(token);
919 if (TokenAvailable()) // default value ?
922 if (!strcmp(token,":"))
926 newoption->optiondefault = strdup(token);
927 optioncomplete = true;
933 optioncomplete = true;
937 case OPTION_CHOICES :
938 GetTokenExtra(false,":",true); // : or :"something like this" (bah!)
939 strcpy(token_debug,token);
940 if ((token[0] == ':') && (strlen(token) > 1))
942 if (token[1] == '\"')
944 strcpy(temp,token+2);
947 if (!GetToken(false))
952 if (temp[len-1] == '\"')
959 newoption->optioninfo = strdup(temp);
964 newoption->optioninfo = strdup(token);
966 GetToken(false); // : or =
967 strcpy(token_debug,token);
968 if (!strcmp(token,":"))
971 newoption->optiondefault = strdup(token);
979 GetToken(false); // : or =
980 strcpy(token_debug,token);
981 if (strcmp(token,"=")) // missing ?
985 strcpy(token_debug,token);
986 if (strcmp(token,"[")) // missing ?
992 GetTokenExtra(true,":",true); // "]" or "number", or "number:"
993 strcpy(token_debug,token);
994 if (!strcmp(token,"]")) // no more ?
996 optioncomplete = true;
1001 if (temp[len-1] == ':')
1007 GetToken(false); // :
1008 if (strcmp(token,":")) // missing ?
1011 if (!TokenAvailable())
1013 GetToken(false); // the name
1015 newchoice = (choice_t *) malloc ( sizeof( choice_s ));
1016 memset( newchoice, 0, sizeof( choice_s ));
1018 newchoice->value = atoi(temp);
1019 newchoice->name = strdup(token);
1021 newoption->choices = g_slist_append(newoption->choices, newchoice);
1023 // ignore any remaining tokens on the line
1024 while (TokenAvailable()) GetToken(false);
1026 // and it we found a "]" on the end of the line, put it back in the queue.
1027 if (!strcmp(token,"]")) UnGetToken();
1033 // add option to the newclass
1039 // add it to the list.
1040 newclass->l_optionlist = g_slist_append(newclass->l_optionlist, newoption);
1045 Sys_Printf ("%WARNING: Parse error occured in '%s - %s'\n",classnames[newclass->classtype],newclass->classname);
1046 Free_Option(newoption);
1053 UnGetToken(); // shouldn't get here.
1057 // add it to our list.
1058 l_classes = g_slist_append (l_classes, newclass);
1063 // finished with the file now.
1066 Sys_Printf ("FGD scan complete, building entities...\n");
1068 // Once we get here we should have a few (!) lists in memory that we
1069 // can extract all the information required to build a the eclass_t structures.
1071 Create_EClasses(l_classes);
1075 GSList *p = l_classes;
1078 class_t *tmpclass = (class_t *)p->data;
1081 // DEBUG: dump the info...
1082 Sys_Printf ("%s: %s (", classnames[tmpclass->classtype],tmpclass->classname);
1083 for (GSList *tmp = tmpclass->l_baselist; tmp != NULL; tmp = tmp->next)
1085 if (tmp != tmpclass->l_baselist)
1089 Sys_Printf ("%s", (char *)tmp->data);
1091 if (tmpclass->gotsize)
1093 sprintf(temp,"(%.0f %.0f %.0f) - (%.0f %.0f %.0f)",tmpclass->boundingbox[0][0],
1094 tmpclass->boundingbox[0][1],
1095 tmpclass->boundingbox[0][2],
1096 tmpclass->boundingbox[1][0],
1097 tmpclass->boundingbox[1][1],
1098 tmpclass->boundingbox[1][2]);
1099 } else strcpy(temp,"No Size");
1100 Sys_Printf (") '%s' Size: %s",tmpclass->description ? tmpclass->description : "No description",temp);
1101 if (tmpclass->gotcolor)
1103 sprintf(temp,"(%d %d %d)",tmpclass->color[0],
1105 tmpclass->color[2]);
1106 } else strcpy(temp,"No Color");
1107 Sys_Printf (" Color: %s Options:\n",temp);
1108 if (!tmpclass->l_optionlist)
1110 Sys_Printf (" No Options\n");
1114 option_t *tmpoption;
1117 for (olst = tmpclass->l_optionlist, count = 1; olst != NULL; olst = olst->next, count ++)
1119 tmpoption = (option_t *)olst->data;
1120 Sys_Printf (" %d, Type: %s, EPair: %s\n", count,optionnames[tmpoption->optiontype], tmpoption->epairname );
1122 choice_t *tmpchoice;
1125 for (clst = tmpoption->choices, ccount = 1; clst != NULL; clst = clst->next, ccount ++)
1127 tmpchoice = (choice_t *)clst->data;
1128 Sys_Printf (" %d, Value: %d, Name: %s\n", ccount, tmpchoice->value, tmpchoice->name);
1135 // free the baselist.
1136 ClearGSList(tmpclass->l_baselist);
1137 Free_Class (tmpclass);
1138 p = g_slist_remove (p, p->data);