ui_parse.c

Go to the documentation of this file.
00001 
00007 /*
00008 Copyright (C) 2002-2010 UFO: Alien Invasion.
00009 
00010 This program is free software; you can redistribute it and/or
00011 modify it under the terms of the GNU General Public License
00012 as published by the Free Software Foundation; either version 2
00013 of the License, or (at your option) any later version.
00014 
00015 This program is distributed in the hope that it will be useful,
00016 but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00018 
00019 See the GNU General Public License for more details.
00020 
00021 You should have received a copy of the GNU General Public License
00022 along with this program; if not, write to the Free Software
00023 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00024 
00025 */
00026 
00027 #include "../client.h"
00028 #include "ui_parse.h"
00029 #include "ui_main.h"
00030 #include "ui_data.h"
00031 #include "ui_internal.h"
00032 #include "ui_actions.h"
00033 #include "ui_icon.h"
00034 #include "ui_components.h"
00035 #include "node/ui_node_window.h"
00036 #include "node/ui_node_selectbox.h"
00037 #include "node/ui_node_abstractnode.h"
00038 #include "node/ui_node_abstractoption.h"
00039 
00040 #include "../../shared/parse.h"
00041 
00043 static qboolean UI_ParseProperty(void* object, const value_t *property, const char* objectName, const char **text, const char **token);
00044 static uiAction_t *UI_ParseActionList(uiNode_t *node, const char **text, const const char **token);
00045 static uiNode_t *UI_ParseNode(uiNode_t * parent, const char **text, const char **token, const char *errhead);
00046 
00048 static const value_t uiModelProperties[] = {
00049     {"model", V_CLIENT_HUNK_STRING, offsetof(uiModel_t, model), 0},
00050     {"need", V_NULL, 0, 0},
00051     {"anim", V_CLIENT_HUNK_STRING, offsetof(uiModel_t, anim), 0},
00052     {"skin", V_INT, offsetof(uiModel_t, skin), sizeof(int)},
00053     {"color", V_COLOR, offsetof(uiModel_t, color), sizeof(vec4_t)},
00054     {"tag", V_CLIENT_HUNK_STRING, offsetof(uiModel_t, tag), 0},
00055     {"parent", V_CLIENT_HUNK_STRING, offsetof(uiModel_t, parent), 0},
00056 
00057     {NULL, V_NULL, 0, 0},
00058 };
00059 
00063 static const char *reserved_tokens[] = {
00064     "this",
00065     "parent",
00066     "root",
00067     "null",
00068     "super",
00069     "node",
00070     "cvar",
00071     "int",
00072     "float",
00073     "string",
00074     "var",
00075     NULL
00076 };
00077 
00078 static qboolean UI_TokenIsReserved (const char *name)
00079 {
00080     const char **token = reserved_tokens;
00081     while (*token) {
00082         if (!strcmp(*token, name))
00083             return qtrue;
00084         token++;
00085     }
00086     return qfalse;
00087 }
00088 
00089 static qboolean UI_TokenIsValue (const char *name, qboolean isQuoted)
00090 {
00091     assert(name);
00092     if (isQuoted)
00093         return qtrue;
00094     /* is it a number */
00095     if ((name[0] >= '0' && name[0] <= '9') || name[0] == '-' || name[0] == '.')
00096         return qtrue;
00097     /* is it a var (*cvar:...) */
00098     if (name[0] == '*')
00099         return qtrue;
00100     if (!strcmp(name, "true"))
00101         return qtrue;
00102     if (!strcmp(name, "false"))
00103         return qtrue;
00104 
00105     /* uppercase const name */
00106     if ((name[0] >= 'A' && name[0] <= 'Z') || name[0] == '_') {
00107         qboolean onlyUpperCase = qtrue;
00108         while (*name != '\0') {
00109             if ((name[0] >= 'A' && name[0] <= 'Z') || name[0] == '_' || (name[0] >= '0' && name[0] <= '9')) {
00110                 /* available chars */
00111             } else {
00112                 return qfalse;
00113             }
00114             name++;
00115         }
00116         return onlyUpperCase;
00117     }
00118 
00119     return qfalse;
00120 }
00121 
00122 static qboolean UI_TokenIsName (const char *name, qboolean isQuoted)
00123 {
00124     assert(name);
00125     if (isQuoted)
00126         return qfalse;
00127     if ((name[0] >= 'a' && name[0] <= 'z') || (name[0] >= 'A' && name[0] <= 'Z') || name[0] == '_') {
00128         qboolean onlyUpperCase = qtrue;
00129         while (*name != '\0') {
00130             if (name[0] >= 'a' && name[0] <= 'z') {
00131                 onlyUpperCase = qfalse;
00132             } else if ((name[0] >= '0' && name[0] <= '9') || (name[0] >= 'A' && name[0] <= 'Z') || name[0] == '_') {
00133                 /* available chars */
00134             } else {
00135                 return qfalse;
00136             }
00137             name++;
00138         }
00139         return !onlyUpperCase;
00140     }
00141     return qfalse;
00142 }
00143 
00150 const value_t* UI_FindPropertyByName (const value_t* propertyList, const char* name)
00151 {
00152     const value_t* current = propertyList;
00153     while (current->string != NULL) {
00154         if (!Q_strcasecmp(name, current->string))
00155             return current;
00156         current++;
00157     }
00158     return NULL;
00159 }
00160 
00167 float* UI_AllocStaticFloat (int count)
00168 {
00169     float *result;
00170     assert(count > 0);
00171     ui_global.curadata = ALIGN_PTR(ui_global.curadata, sizeof(float));
00172     result = (float*) ui_global.curadata;
00173     ui_global.curadata += sizeof(float) * count;
00174     if (ui_global.curadata - ui_global.adata > ui_global.adataize)
00175         Com_Error(ERR_FATAL, "UI_AllocFloat: UI memory hunk exceeded - increase the size");
00176     return result;
00177 }
00178 
00185 vec4_t* UI_AllocStaticColor (int count)
00186 {
00187     vec4_t *result;
00188     assert(count > 0);
00189     ui_global.curadata = ALIGN_PTR(ui_global.curadata, sizeof(vec_t));
00190     result = (vec4_t*) ui_global.curadata;
00191     ui_global.curadata += sizeof(vec_t) * 4 * count;
00192     if (ui_global.curadata - ui_global.adata > ui_global.adataize)
00193         Com_Error(ERR_FATAL, "UI_AllocColor: UI memory hunk exceeded - increase the size");
00194     return result;
00195 }
00196 
00204 char* UI_AllocStaticString (const char* string, int size)
00205 {
00206     char* result = (char *)ui_global.curadata;
00207     ui_global.curadata = ALIGN_PTR(ui_global.curadata, sizeof(char));
00208     if (size != 0) {
00209         if (ui_global.curadata - ui_global.adata + size > ui_global.adataize)
00210             Com_Error(ERR_FATAL, "UI_AllocString: UI memory hunk exceeded - increase the size");
00211         strncpy((char *)ui_global.curadata, string, size);
00212         ui_global.curadata += size;
00213     } else {
00214         if (ui_global.curadata - ui_global.adata + strlen(string) + 1 > ui_global.adataize)
00215             Com_Error(ERR_FATAL, "UI_AllocString: UI memory hunk exceeded - increase the size");
00216         ui_global.curadata += sprintf((char *)ui_global.curadata, "%s", string) + 1;
00217     }
00218     return result;
00219 }
00220 
00225 uiAction_t *UI_AllocStaticAction (void)
00226 {
00227     if (ui_global.numActions >= UI_MAX_ACTIONS)
00228         Com_Error(ERR_FATAL, "UI_AllocAction: Too many UI actions");
00229     return &ui_global.actions[ui_global.numActions++];
00230 }
00231 
00242 qboolean UI_InitRawActionValue (uiAction_t* action, uiNode_t *node, const value_t *property, const char *string)
00243 {
00244     if (property == NULL) {
00245         action->type = EA_VALUE_STRING;
00246         action->d.terminal.d1.data = UI_AllocStaticString(string, 0);
00247         action->d.terminal.d2.integer = 0;
00248         return qtrue;
00249     }
00250 
00251     if (property->type == V_UI_ICONREF) {
00252         uiIcon_t* icon = UI_GetIconByName(string);
00253         if (icon == NULL) {
00254             Com_Printf("UI_ParseSetAction: icon '%s' not found (%s)\n", string, UI_GetPath(node));
00255             return qfalse;
00256         }
00257         action->type = EA_VALUE_RAW;
00258         action->d.terminal.d1.data = icon;
00259         action->d.terminal.d2.integer = property->type;
00260         return qtrue;
00261     } else {
00262         const int baseType = property->type & V_UI_MASK;
00263         if (baseType != 0 && baseType != V_UI_CVAR) {
00264             Com_Printf("UI_ParseRawValue: setter for property '%s' (type %d, 0x%X) is not supported (%s)\n", property->string, property->type, property->type, UI_GetPath(node));
00265             return qfalse;
00266         }
00267         ui_global.curadata = Com_AlignPtr(ui_global.curadata, property->type & V_BASETYPEMASK);
00268         action->type = EA_VALUE_RAW;
00269         action->d.terminal.d1.data = ui_global.curadata;
00270         action->d.terminal.d2.integer = property->type;
00272         ui_global.curadata += Com_EParseValue(ui_global.curadata, string, property->type & V_BASETYPEMASK, 0, property->size);
00273         return qtrue;
00274     }
00275 }
00276 
00280 static qboolean UI_ParseSetAction (uiNode_t *node, uiAction_t *action, const char **text, const char **token, const char *errhead)
00281 {
00282     const value_t *property;
00283     int type;
00284     uiAction_t* localAction;
00285 
00286     assert((*token)[0] == '*');
00287 
00288     Com_UnParseLastToken();
00289     action->d.nonTerminal.left = UI_ParseExpression(text);
00290 
00291     type = action->d.nonTerminal.left->type;
00292     if (type != EA_VALUE_CVARNAME && type != EA_VALUE_CVARNAME_WITHINJECTION
00293         && type != EA_VALUE_PATHPROPERTY && type != EA_VALUE_PATHPROPERTY_WITHINJECTION) {
00294         Com_Printf("UI_ParseSetAction: Cvar or Node property expected. Type '%i' found\n", type);
00295         return qfalse;
00296     }
00297 
00298     /* must use "equal" char between name and value */
00299     *token = Com_EParse(text, errhead, NULL);
00300     if (!*text)
00301         return qfalse;
00302     if (strcmp(*token, "=") != 0) {
00303         Com_Printf("UI_ParseSetAction: Assign sign '=' expected between variable and value. '%s' found in node %s.\n", *token, UI_GetPath(node));
00304         return qfalse;
00305     }
00306 
00307     /* get the value */
00308     if (type == EA_VALUE_CVARNAME || type == EA_VALUE_CVARNAME_WITHINJECTION) {
00309         action->d.nonTerminal.right = UI_ParseExpression(text);
00310         return qtrue;
00311     }
00312 
00313     property = (const value_t *) action->d.nonTerminal.left->d.terminal.d2.data;
00314 
00315     *token = Com_EParse(text, errhead, NULL);
00316     if (!*text)
00317         return qfalse;
00318 
00319     if (!strcmp(*token, "{")) {
00320         uiAction_t* actionList;
00321 
00322         if (property != NULL && property->type != V_UI_ACTION) {
00323             Com_Printf("UI_ParseSetAction: Property %s@%s do not expect code block.\n", UI_GetPath(node), property->string);
00324             return qfalse;
00325         }
00326 
00327         actionList = UI_ParseActionList(node, text, token);
00328         if (actionList == NULL)
00329             return qfalse;
00330 
00331         localAction = UI_AllocStaticAction();
00332         localAction->type = EA_VALUE_RAW;
00333         localAction->d.terminal.d1.data = actionList;
00334         localAction->d.terminal.d2.integer = V_UI_ACTION;
00335         action->d.nonTerminal.right = localAction;
00336 
00337         return qtrue;
00338     }
00339 
00340     if (!strcmp(*token, "(")) {
00341         Com_UnParseLastToken();
00342         action->d.nonTerminal.right = UI_ParseExpression(text);
00343         return qtrue;
00344     }
00345 
00346     /* @todo everything should come from UI_ParseExpression */
00347 
00348     if (UI_IsInjectedString(*token)) {
00349         localAction = UI_AllocStaticAction();
00350         localAction->type = EA_VALUE_STRING_WITHINJECTION;
00351         localAction->d.terminal.d1.data = UI_AllocStaticString(*token, 0);
00352         action->d.nonTerminal.right = localAction;
00353         return qtrue;
00354     }
00355 
00356     localAction = UI_AllocStaticAction();
00357     UI_InitRawActionValue(localAction, node, property, *token);
00358     action->d.nonTerminal.right = localAction;
00359     return qtrue;
00360 }
00361 
00365 static qboolean UI_ParseCallAction (uiNode_t *node, uiAction_t *action, const char **text, const char **token, const char *errhead)
00366 {
00367     uiAction_t *expression;
00368     uiAction_t *lastParam = NULL;
00369     int paramID = 0;
00370     expression = UI_ParseExpression(text);
00371     if (expression == NULL)
00372         return qfalse;
00373 
00374     if (expression->type != EA_VALUE_PATHNODE_WITHINJECTION && expression->type != EA_VALUE_PATHNODE && expression->type != EA_VALUE_PATHPROPERTY && expression->type != EA_VALUE_PATHPROPERTY_WITHINJECTION) {
00375         Com_Printf("UI_ParseCallAction: \"call\" keyword only support pathnode and pathproperty (node: %s)\n", UI_GetPath(node));
00376         return qfalse;
00377     }
00378 
00379     action->d.nonTerminal.left = expression;
00380 
00381     /* check parameters */
00382     *token = Com_EParse(text, errhead, NULL);
00383     if ((*token)[0] == '\0')
00384         return qfalse;
00385 
00386     /* there is no parameters */
00387     if (strcmp(*token, "(") != 0) {
00388         Com_UnParseLastToken();
00389         return qtrue;
00390     }
00391 
00392     /* read parameters */
00393     do {
00394         uiAction_t *param;
00395         paramID++;
00396 
00397         /* parameter */
00398         param = UI_ParseExpression(text);
00399         if (param == NULL) {
00400             Com_Printf("UI_ParseCallAction: problem with the %i parameter\n", paramID);
00401             return qfalse;
00402         }
00403         if (lastParam == NULL)
00404             action->d.nonTerminal.right = param;
00405         else
00406             lastParam->next = param;
00407         lastParam = param;
00408 
00409         /* separator */
00410         *token = Com_EParse(text, errhead, NULL);
00411         if (!*token)
00412             return qfalse;
00413         if (strcmp(*token, ",") != 0) {
00414             if (strcmp(*token, ")") == 0)
00415                 break;
00416             Com_UnParseLastToken();
00417             Com_Printf("UI_ParseCallAction: Invalidate end of 'call' after param %i\n", paramID);
00418             return qfalse;
00419         }
00420     } while(qtrue);
00421 
00422     return qtrue;
00423 }
00424 
00431 static uiAction_t *UI_ParseActionList (uiNode_t *node, const char **text, const const char **token)
00432 {
00433     const char *errhead = "UI_ParseActionList: unexpected end of file (in event)";
00434     uiAction_t *firstAction;
00435     uiAction_t *lastAction;
00436     uiAction_t *action;
00437     qboolean result;
00438 
00439     lastAction = NULL;
00440     firstAction = NULL;
00441 
00442     /* prevent bad position */
00443     if ((*token)[0] != '{') {
00444         Com_Printf("UI_ParseActionList: token \"{\" expected, but \"%s\" found (in event) (node: %s)\n", *token, UI_GetPath(node));
00445         return NULL;
00446     }
00447 
00448     while (qtrue) {
00449         int type = EA_NULL;
00450 
00451         /* get new token */
00452         *token = Com_EParse(text, errhead, NULL);
00453         if (!*token)
00454             return NULL;
00455 
00456         if ((*token)[0] == '}')
00457             break;
00458 
00459         type = UI_GetActionTokenType(*token, EA_ACTION);
00460         /* setter form */
00461         if (type == EA_NULL && (*token)[0] == '*')
00462             type = EA_ASSIGN;
00463 
00464         /* unknown, we break the parsing */
00465         if (type == EA_NULL) {
00466             Com_Printf("UI_ParseActionList: unknown token \"%s\" ignored (in event) (node: %s)\n", *token, UI_GetPath(node));
00467             return NULL;
00468         }
00469 
00470         /* add the action */
00471         action = UI_AllocStaticAction();
00473         if (lastAction)
00474             lastAction->next = action;
00475         if (!firstAction)
00476             firstAction = action;
00477         action->type = type;
00478 
00479         /* decode action */
00480         switch (action->type) {
00481         case EA_CMD:
00482             /* get parameter values */
00483             *token = Com_EParse(text, errhead, NULL);
00484             if (!*text)
00485                 return NULL;
00486 
00487             /* get the value */
00488             action->d.terminal.d1.string = UI_AllocStaticString(*token, 0);
00489             break;
00490 
00491         case EA_ASSIGN:
00492             result = UI_ParseSetAction(node, action, text, token, errhead);
00493             if (!result)
00494                 return NULL;
00495             break;
00496 
00497         case EA_CALL:
00498             result = UI_ParseCallAction(node, action, text, token, errhead);
00499             if (!result)
00500                 return NULL;
00501             break;
00502 
00503         case EA_DELETE:
00504             {
00505                 uiAction_t *expression;
00506                 expression = UI_ParseExpression(text);
00507                 if (expression == NULL)
00508                     return NULL;
00509 
00510                 if (expression->type != EA_VALUE_CVARNAME) {
00511                     Com_Printf("UI_ParseActionList: \"delete\" keyword only support cvarname (node: %s)\n", UI_GetPath(node));
00512                     return NULL;
00513                 }
00514 
00515                 action->d.nonTerminal.left = expression;
00516                 break;
00517             }
00518 
00519         case EA_ELIF:
00520             /* check previous action */
00521             if (!lastAction || (lastAction->type != EA_IF && lastAction->type != EA_ELIF)) {
00522                 Com_Printf("UI_ParseActionList: 'elif' must be set after an 'if' or an 'elif' (node: %s)\n", UI_GetPath(node));
00523                 return NULL;
00524             }
00525             /* then it execute EA_IF, no break */
00526         case EA_WHILE:
00527         case EA_IF:
00528             {
00529                 uiAction_t *expression;
00530 
00531                 /* get the condition */
00532                 expression = UI_ParseExpression(text);
00533                 if (expression == NULL)
00534                     return NULL;
00535                 action->d.nonTerminal.left = expression;
00536 
00537                 /* get the action block */
00538                 *token = Com_EParse(text, errhead, NULL);
00539                 if (!*text)
00540                     return NULL;
00541                 action->d.nonTerminal.right = UI_ParseActionList(node, text, token);
00542                 if (action->d.nonTerminal.right == NULL) {
00543                     if (action->type == EA_IF)
00544                         Com_Printf("UI_ParseActionList: block expected after \"if\" (node: %s)\n", UI_GetPath(node));
00545                     else if (action->type == EA_ELIF)
00546                         Com_Printf("UI_ParseActionList: block expected after \"elif\" (node: %s)\n", UI_GetPath(node));
00547                     else
00548                         Com_Printf("UI_ParseActionList: block expected after \"while\" (node: %s)\n", UI_GetPath(node));
00549                     return NULL;
00550                 }
00551                 break;
00552             }
00553 
00554         case EA_ELSE:
00555             /* check previous action */
00556             if (!lastAction || (lastAction->type != EA_IF && lastAction->type != EA_ELIF)) {
00557                 Com_Printf("UI_ParseActionList: 'else' must be set after an 'if' or an 'elif' (node: %s)\n", UI_GetPath(node));
00558                 return NULL;
00559             }
00560 
00561             /* get the action block */
00562             *token = Com_EParse(text, errhead, NULL);
00563             if (!*text)
00564                 return NULL;
00565             action->d.nonTerminal.left = NULL;
00566             action->d.nonTerminal.right = UI_ParseActionList(node, text, token);
00567             if (action->d.nonTerminal.right == NULL) {
00568                 Com_Printf("UI_ParseActionList: block expected after \"else\" (node: %s)\n", UI_GetPath(node));
00569                 return NULL;
00570             }
00571             break;
00572 
00573         default:
00574             assert(qfalse);
00575         }
00576 
00577         /* step */
00578         lastAction = action;
00579     }
00580 
00581     assert((*token)[0] == '}');
00582 
00583     /* return non NULL value */
00584     if (firstAction == NULL) {
00585         firstAction = UI_AllocStaticAction();
00586     }
00587 
00588     return firstAction;
00589 }
00590 
00591 static qboolean UI_ParseExcludeRect (uiNode_t * node, const char **text, const char **token, const char *errhead)
00592 {
00593     uiExcludeRect_t rect;
00594 
00595     /* get parameters */
00596     *token = Com_EParse(text, errhead, node->name);
00597     if (!*text)
00598         return qfalse;
00599     if ((*token)[0] != '{') {
00600         Com_Printf("UI_ParseExcludeRect: node with bad excluderect ignored (node \"%s\")\n", UI_GetPath(node));
00601         return qtrue;
00602     }
00603 
00604     do {
00605         *token = Com_EParse(text, errhead, node->name);
00606         if (!*text)
00607             return qfalse;
00609         if (!strcmp(*token, "pos")) {
00610             *token = Com_EParse(text, errhead, node->name);
00611             if (!*text)
00612                 return qfalse;
00613             Com_EParseValue(&rect, *token, V_POS, offsetof(uiExcludeRect_t, pos), sizeof(vec2_t));
00614         } else if (!strcmp(*token, "size")) {
00615             *token = Com_EParse(text, errhead, node->name);
00616             if (!*text)
00617                 return qfalse;
00618             Com_EParseValue(&rect, *token, V_POS, offsetof(uiExcludeRect_t, size), sizeof(vec2_t));
00619         }
00620     } while ((*token)[0] != '}');
00621 
00622     if (ui_global.numExcludeRect >= UI_MAX_EXLUDERECTS) {
00623         Com_Printf("UI_ParseExcludeRect: exluderect limit exceeded (max: %i)\n", UI_MAX_EXLUDERECTS);
00624         return qfalse;
00625     }
00626 
00627     /* copy the rect into the global structure */
00628     ui_global.excludeRect[ui_global.numExcludeRect] = rect;
00629 
00630     /* link only the first element */
00631     if (node->excludeRect == NULL) {
00632         node->excludeRect = &ui_global.excludeRect[ui_global.numExcludeRect];
00633     }
00634 
00635     ui_global.numExcludeRect++;
00636     node->excludeRectNum++;
00637 
00638     return qtrue;
00639 }
00640 
00641 static qboolean UI_ParseEventProperty (uiNode_t * node, const value_t *event, const char **text, const char **token, const char *errhead)
00642 {
00643     uiAction_t **action;
00644 
00645     /* add new actions to end of list */
00646     action = (uiAction_t **) ((byte *) node + event->ofs);
00647     for (; *action; action = &(*action)->next) {}
00648 
00649     /* get the action body */
00650     *token = Com_EParse(text, errhead, node->name);
00651     if (!*text)
00652         return qfalse;
00653 
00654     if ((*token)[0] != '{') {
00655         Com_Printf("UI_ParseEventProperty: Event '%s' without body (%s)\n", event->string, UI_GetPath(node));
00656         return qfalse;
00657     }
00658 
00659     Com_EnableFunctionScriptToken(qtrue);
00660 
00661     *action = UI_ParseActionList(node, text, token);
00662     if (*action == NULL)
00663         return qfalse;
00664 
00665     Com_EnableFunctionScriptToken(qfalse);
00666 
00667     /* block terminal already read */
00668     assert((*token)[0] == '}');
00669 
00670     return qtrue;
00671 }
00672 
00677 static qboolean UI_ParseProperty (void* object, const value_t *property, const char* objectName, const char **text, const char **token)
00678 {
00679     const char *errhead = "UI_ParseProperty: unexpected end of file (object";
00680     static const char *notWellFormedValue = "UI_ParseProperty: \"%s\" is not a well formed node name (it must be quoted, uppercase const, a number, or prefixed with '*')\n";
00681     size_t bytes;
00682     void *valuePtr = (void*) ((uintptr_t)object + property->ofs);
00683     int result;
00684     const int specialType = property->type & V_UI_MASK;
00685 
00686     if (property->type == V_NULL) {
00687         return qfalse;
00688     }
00689 
00690     switch (specialType) {
00691     case V_NOT_UI:  /* common type */
00692 
00693         *token = Com_EParse(text, errhead, objectName);
00694         if (!*text)
00695             return qfalse;
00696         if (!UI_TokenIsValue(*token, Com_ParsedTokenIsQuoted())) {
00697             Com_Printf(notWellFormedValue, *token);
00698             return qfalse;
00699         }
00700 
00701         if (property->type == V_TRANSLATION_STRING) {
00702             /* selectbox values are static arrays */
00703             char *target = (char*) valuePtr;
00704             const char *translatableToken = *token;
00705             assert(property->size);
00706             if (translatableToken[0] == '_')
00707                 translatableToken++;
00708             Q_strncpyz(target, translatableToken, property->size);
00709         } else {
00710             result = Com_ParseValue(object, *token, property->type, property->ofs, property->size, &bytes);
00711             if (result != RESULT_OK) {
00712                 Com_Printf("UI_ParseProperty: Invalid value for property '%s': %s\n", property->string, Com_GetLastParseError());
00713                 return qfalse;
00714             }
00715         }
00716         break;
00717 
00718     case V_UI_REF:
00719         *token = Com_EParse(text, errhead, objectName);
00720         if (!*text)
00721             return qfalse;
00722         if (!UI_TokenIsValue(*token, Com_ParsedTokenIsQuoted())) {
00723             Com_Printf(notWellFormedValue, *token);
00724             return qfalse;
00725         }
00726 
00727         /* a reference to data is handled like this */
00728         ui_global.curadata = Com_AlignPtr(ui_global.curadata, property->type & V_BASETYPEMASK);
00729         *(byte **) ((byte *) object + property->ofs) = ui_global.curadata;
00730 
00732         assert((*token)[0] != '*');
00733 
00734         /* sanity check */
00735         if ((property->type & V_BASETYPEMASK) == V_STRING && strlen(*token) > MAX_VAR - 1) {
00736             Com_Printf("UI_ParseProperty: Value '%s' is too long (key %s)\n", *token, property->string);
00737             return qfalse;
00738         }
00739 
00740         result = Com_ParseValue(ui_global.curadata, *token, property->type & V_BASETYPEMASK, 0, property->size, &bytes);
00741         if (result != RESULT_OK) {
00742             Com_Printf("UI_ParseProperty: Invalid value for property '%s': %s\n", property->string, Com_GetLastParseError());
00743             return qfalse;
00744         }
00745         ui_global.curadata += bytes;
00746 
00747         break;
00748 
00749     case V_UI_CVAR: /* common type */
00750         *token = Com_EParse(text, errhead, objectName);
00751         if (!*text)
00752             return qfalse;
00753         if (!UI_TokenIsValue(*token, Com_ParsedTokenIsQuoted())) {
00754             Com_Printf(notWellFormedValue, *token);
00755             return qfalse;
00756         }
00757 
00758         /* references are parsed as string */
00759         if ((*token)[0] == '*') {
00760             /* a reference to data */
00761             ui_global.curadata = Com_AlignPtr(ui_global.curadata, V_STRING);
00762             *(byte **) valuePtr = ui_global.curadata;
00763 
00764             /* sanity check */
00765             if (strlen(*token) > MAX_VAR - 1) {
00766                 Com_Printf("UI_ParseProperty: Value '%s' is too long (key %s)\n", *token, property->string);
00767                 return qfalse;
00768             }
00769 
00770             result = Com_ParseValue(ui_global.curadata, *token, V_STRING, 0, 0, &bytes);
00771             if (result != RESULT_OK) {
00772                 Com_Printf("UI_ParseProperty: Invalid value for property '%s': %s\n", property->string, Com_GetLastParseError());
00773                 return qfalse;
00774             }
00775             ui_global.curadata += bytes;
00776         } else {
00777             /* a reference to data */
00778             ui_global.curadata = Com_AlignPtr(ui_global.curadata, property->type & V_BASETYPEMASK);
00779             *(byte **) valuePtr = ui_global.curadata;
00780 
00781             /* sanity check */
00782             if ((property->type & V_BASETYPEMASK) == V_STRING && strlen(*token) > MAX_VAR - 1) {
00783                 Com_Printf("UI_ParseProperty: Value '%s' is too long (key %s)\n", *token, property->string);
00784                 return qfalse;
00785             }
00786 
00787             result = Com_ParseValue(ui_global.curadata, *token, property->type & V_BASETYPEMASK, 0, property->size, &bytes);
00788             if (result != RESULT_OK) {
00789                 Com_Printf("UI_ParseProperty: Invalid value for property '%s': %s\n", property->string, Com_GetLastParseError());
00790                 return qfalse;
00791             }
00792             ui_global.curadata += bytes;
00793         }
00794         break;
00795 
00796     case V_UI:
00797 
00798         switch (property->type) {
00799         case V_UI_ACTION:
00800             result = UI_ParseEventProperty(object, property, text, token, errhead);
00801             if (!result)
00802                 return qfalse;
00803             break;
00804 
00805         case V_UI_EXCLUDERECT:
00806             result = UI_ParseExcludeRect(object, text, token, errhead);
00807             if (!result)
00808                 return qfalse;
00809             break;
00810 
00811         case V_UI_ICONREF:
00812             {
00813                 uiIcon_t** icon = (uiIcon_t**) valuePtr;
00814                 *token = Com_EParse(text, errhead, objectName);
00815                 if (!*text)
00816                     return qfalse;
00817 
00818                 *icon = UI_GetIconByName(*token);
00819                 if (*icon == NULL) {
00820                     Com_Printf("UI_ParseProperty: icon '%s' not found (object %s)\n", *token, objectName);
00821                 }
00822             }
00823             break;
00824 
00825         case V_UI_IF:
00826             {
00827                 uiAction_t **expression = (uiAction_t **) valuePtr;
00828 
00829                 *token = Com_EParse(text, errhead, objectName);
00830                 if (!*text)
00831                     return qfalse;
00832 
00833                 *expression = UI_AllocStaticStringCondition(*token);
00834                 if (*expression == NULL)
00835                     return qfalse;
00836             }
00837             break;
00838 
00839         case V_UI_DATAID:
00840             {
00841                 int *dataId = (int*) valuePtr;
00842                 *token = Com_EParse(text, errhead, objectName);
00843                 if (!*text)
00844                     return qfalse;
00845 
00846                 *dataId = UI_GetDataIDByName(*token);
00847                 if (*dataId < 0) {
00848                     Com_Printf("UI_ParseProperty: Could not find shared data ID '%s' (%s@%s)\n",
00849                             *token, objectName, property->string);
00850                     return qfalse;
00851                 }
00852             }
00853             break;
00854 
00855         default:
00856             Com_Printf("UI_ParseProperty: unknown property type '%d' (0x%X) (%s@%s)\n",
00857                     property->type, property->type, objectName, property->string);
00858             return qfalse;
00859         }
00860         break;
00861 
00862     default:
00863         Com_Printf("UI_ParseProperties: unknown property type '%d' (0x%X) (%s@%s)\n",
00864                 property->type, property->type, objectName, property->string);
00865         return qfalse;
00866     }
00867 
00868     return qtrue;
00869 }
00870 
00871 static qboolean UI_ParseFunction (uiNode_t * node, const char **text, const char **token)
00872 {
00873     uiAction_t **action;
00874     assert(node->behaviour->isFunction);
00875 
00876     Com_EnableFunctionScriptToken(qtrue);
00877 
00878     action = &node->onClick;
00879     *action = UI_ParseActionList(node, text, token);
00880     if (*action == NULL)
00881         return qfalse;
00882 
00883     Com_EnableFunctionScriptToken(qfalse);
00884 
00885     return (*token)[0] == '}';
00886 }
00887 
00905 static qboolean UI_ParseNodeProperties (uiNode_t * node, const char **text, const char **token)
00906 {
00907     const char *errhead = "UI_ParseNodeProperties: unexpected end of file (node";
00908     qboolean nextTokenAlreadyRead = qfalse;
00909 
00910     if ((*token)[0] != '{')
00911         nextTokenAlreadyRead = qtrue;
00912 
00913     do {
00914         const value_t *val;
00915         int result;
00916 
00917         /* get new token */
00918         if (!nextTokenAlreadyRead) {
00919             *token = Com_EParse(text, errhead, node->name);
00920             if (!*text)
00921                 return qfalse;
00922         } else {
00923             nextTokenAlreadyRead = qfalse;
00924         }
00925 
00926         /* is finished */
00927         if ((*token)[0] == '}')
00928             break;
00929 
00930         /* find the property */
00931         val = UI_GetPropertyFromBehaviour(node->behaviour, *token);
00932         if (!val) {
00933             /* unknown token, print message and continue */
00934             Com_Printf("UI_ParseNodeProperties: unknown property \"%s\", node ignored (node %s)\n",
00935                     *token, UI_GetPath(node));
00936             return qfalse;
00937         }
00938 
00939         /* get parameter values */
00940         result = UI_ParseProperty(node, val, node->name, text, token);
00941         if (!result) {
00942             Com_Printf("UI_ParseNodeProperties: Problem with parsing of node property '%s@%s'. See upper\n",
00943                     UI_GetPath(node), val->string);
00944             return qfalse;
00945         }
00946 
00947     } while (*text);
00948 
00949     return qtrue;
00950 }
00951 
00964 static qboolean UI_ParseNodeBody (uiNode_t * node, const char **text, const char **token, const char *errhead)
00965 {
00966     qboolean result = qtrue;
00967 
00968     if ((*token)[0] != '{') {
00969         /* read the body block start */
00970         *token = Com_EParse(text, errhead, node->name);
00971         if (!*text)
00972             return qfalse;
00973         if ((*token)[0] != '{') {
00974             Com_Printf("UI_ParseNodeBody: node doesn't have body, token '%s' read (node \"%s\")\n", *token, UI_GetPath(node));
00975             ui_global.numNodes--;
00976             return qfalse;
00977         }
00978     }
00979 
00980     /* functions are a special case */
00981     if (node->behaviour->isFunction) {
00982         result = UI_ParseFunction(node, text, token);
00983     } else {
00984 
00985         /* check the content */
00986         *token = Com_EParse(text, errhead, node->name);
00987         if (!*text)
00988             return qfalse;
00989 
00990         if ((*token)[0] == '{') {
00991             /* we have a special block for properties */
00992             result = UI_ParseNodeProperties(node, text, token);
00993             if (!result)
00994                 return qfalse;
00995 
00996             /* move token over the next node behaviour */
00997             *token = Com_EParse(text, errhead, node->name);
00998             if (!*text)
00999                 return qfalse;
01000 
01001             /* and then read all nodes */
01002             while ((*token)[0] != '}') {
01003                 uiNode_t *new = UI_ParseNode(node, text, token, errhead);
01004                 if (!new)
01005                     return qfalse;
01006 
01007                 *token = Com_EParse(text, errhead, node->name);
01008                 if (*text == NULL)
01009                     return qfalse;
01010             }
01011         } else if (UI_GetPropertyFromBehaviour(node->behaviour, *token)) {
01012             /* we should have a block with properties only */
01013             result = UI_ParseNodeProperties(node, text, token);
01014         } else {
01015             /* we should have a block with nodes only */
01016             while ((*token)[0] != '}') {
01017                 uiNode_t *new = UI_ParseNode(node, text, token, errhead);
01018                 if (!new)
01019                     return qfalse;
01020 
01021                 *token = Com_EParse(text, errhead, node->name);
01022                 if (*text == NULL)
01023                     return qfalse;
01024             }
01025         }
01026     }
01027     if (!result) {
01028         Com_Printf("UI_ParseNodeBody: node with bad body ignored (node \"%s\")\n", UI_GetPath(node));
01029         ui_global.numNodes--;
01030         return qfalse;
01031     }
01032 
01033     /* already check on UI_ParseNodeProperties */
01034     assert((*token)[0] == '}');
01035     return qtrue;
01036 }
01037 
01045 static uiNode_t *UI_ParseNode (uiNode_t * parent, const char **text, const char **token, const char *errhead)
01046 {
01047     uiNode_t *node = NULL;
01048     uiBehaviour_t *behaviour;
01049     uiNode_t *component = NULL;
01050     qboolean result;
01051 
01052     /* allow to begin with the identifier "node" before the behaviour name */
01053     if (!Q_strcasecmp(*token, "node")) {
01054         *token = Com_EParse(text, errhead, "");
01055         if (!*text)
01056             return NULL;
01057     }
01058 
01059     /* get the behaviour */
01060     behaviour = UI_GetNodeBehaviour(*token);
01061     if (!behaviour) {
01062         component = UI_GetComponent(*token);
01063     }
01064     if (behaviour == NULL && component == NULL) {
01065         Com_Printf("UI_ParseNode: node behaviour/component '%s' doesn't exists\n", *token);
01066         return NULL;
01067     }
01068 
01069     /* get the name */
01070     *token = Com_EParse(text, errhead, "");
01071     if (!*text)
01072         return NULL;
01073     if (!UI_TokenIsName(*token, Com_ParsedTokenIsQuoted())) {
01074         Com_Printf("UI_ParseNode: \"%s\" is not a well formed node name ([a-zA-Z_][a-zA-Z0-9_]*)\n", *token);
01075         return NULL;
01076     }
01077     if (UI_TokenIsReserved(*token)) {
01078         Com_Printf("UI_ParseNode: \"%s\" is a reserved token, we can't call a node with it\n", *token);
01079         return NULL;
01080     }
01081 
01082     /* test if node already exists */
01083     /* Already existing node should only come from inherited node,we should not have 2 definitions of the same node into the same window. */
01084     if (parent)
01085         node = UI_GetNode(parent, *token);
01086 
01087     /* reuse a node */
01088     if (node) {
01089         if (node->behaviour != behaviour) {
01090             Com_Printf("UI_ParseNode: we can't change node type (node \"%s\")\n", UI_GetPath(node));
01091             return NULL;
01092         }
01093         Com_DPrintf(DEBUG_CLIENT, "... over-riding node %s\n", UI_GetPath(node));
01094 
01095     /* else initialize a component */
01096     } else if (component) {
01097         node = UI_CloneNode(component, NULL, qtrue, *token, qfalse);
01098         if (parent) {
01099             if (parent->root)
01100                 UI_UpdateRoot(node, parent->root);
01101             UI_AppendNode(parent, node);
01102         }
01103 
01104     /* else initialize a new node */
01105     } else {
01106         node = UI_AllocNode(*token, behaviour->name, qfalse);
01107         node->parent = parent;
01108         if (parent)
01109             node->root = parent->root;
01111         if (parent)
01112             UI_AppendNode(parent, node);
01113     }
01114 
01115     /* get body */
01116     result = UI_ParseNodeBody(node, text, token, errhead);
01117     if (!result)
01118         return NULL;
01119 
01120     /* validate properties */
01121     if (node->behaviour->loaded)
01122         node->behaviour->loaded(node);
01123 
01124     return node;
01125 }
01126 
01131 void UI_ParseUIModel (const char *name, const char **text)
01132 {
01133     uiModel_t *model;
01134     const char *token;
01135     int i;
01136     const value_t *v = NULL;
01137     const char *errhead = "UI_ParseUIModel: unexpected end of file (names ";
01138 
01139     /* search for a UI models with same name */
01140     for (i = 0; i < ui_global.numModels; i++)
01141         if (!strcmp(ui_global.models[i].id, name)) {
01142             Com_Printf("UI_ParseUIModel: menu_model \"%s\" with same name found, second ignored\n", name);
01143             return;
01144         }
01145 
01146     if (ui_global.numModels >= UI_MAX_MODELS) {
01147         Com_Printf("UI_ParseUIModel: Max UI models reached\n");
01148         return;
01149     }
01150 
01151     /* initialize the model */
01152     model = &ui_global.models[ui_global.numModels];
01153     memset(model, 0, sizeof(*model));
01154 
01155     Vector4Set(model->color, 1, 1, 1, 1);
01156 
01157     model->id = Mem_PoolStrDup(name, ui_sysPool, 0);
01158     Com_DPrintf(DEBUG_CLIENT, "Found UI model %s (%i)\n", model->id, ui_global.numModels);
01159 
01160     /* get it's body */
01161     token = Com_Parse(text);
01162 
01163     if (!*text || token[0] != '{') {
01164         Com_Printf("UI_ParseUIModel: Model \"%s\" without body ignored\n", model->id);
01165         return;
01166     }
01167 
01168     ui_global.numModels++;
01169 
01170     do {
01171         /* get the name type */
01172         token = Com_EParse(text, errhead, name);
01173         if (!*text)
01174             break;
01175         if (token[0] == '}')
01176             break;
01177 
01178         v = UI_FindPropertyByName(uiModelProperties, token);
01179         if (!v)
01180             Com_Printf("UI_ParseUIModel: unknown token \"%s\" ignored (UI model %s)\n", token, name);
01181 
01182         if (v->type == V_NULL) {
01183             if (!strcmp(v->string, "need")) {
01184                 token = Com_EParse(text, errhead, name);
01185                 if (!*text)
01186                     return;
01187                 model->next = UI_GetUIModel(token);
01188                 if (!model->next)
01189                     Com_Printf("Could not find UI model %s", token);
01190                 model->need = Mem_PoolStrDup(token, ui_sysPool, 0);
01191             }
01192         } else {
01193             token = Com_EParse(text, errhead, name);
01194             if (!*text)
01195                 return;
01196             switch (v->type) {
01197             case V_CLIENT_HUNK_STRING:
01198                 Mem_PoolStrDupTo(token, (char**) ((char*)model + (int)v->ofs), ui_sysPool, 0);
01199                 break;
01200             default:
01201                 Com_EParseValue(model, token, v->type, v->ofs, v->size);
01202             }
01203         }
01204     } while (*text);
01205 }
01206 
01207 void UI_ParseIcon (const char *name, const char **text)
01208 {
01209     uiIcon_t *icon;
01210     const char *token;
01211 
01212     /* search for icons with same name */
01213     icon = UI_AllocStaticIcon(name);
01214 
01215     /* get it's body */
01216     token = Com_Parse(text);
01217     assert(token[0] == '{');
01218 
01219     /* read properties */
01220     while (qtrue) {
01221         const value_t *property;
01222         qboolean result;
01223 
01224         token = Com_Parse(text);
01225         if (*text == NULL)
01226             return;
01227 
01228         if (token[0] == '}')
01229             break;
01230 
01231         property = UI_FindPropertyByName(mn_iconProperties, token);
01232         if (!property) {
01233             Com_Printf("UI_ParseIcon: unknown options property: '%s' - ignore it\n", token);
01234             return;
01235         }
01236 
01237         /* get parameter values */
01238         result = UI_ParseProperty(icon, property, icon->name, text, &token);
01239         if (!result) {
01240             Com_Printf("UI_ParseIcon: Parsing for icon '%s'. See upper\n", icon->name);
01241             return;
01242         }
01243     }
01244 
01245     return;
01246 }
01247 
01256 void UI_ParseComponent (const char *type, const char **text)
01257 {
01258     const char *errhead = "UI_ParseComponent: unexpected end of file (component";
01259     uiNode_t *component;
01260     const char *token;
01261 
01262     if (strcmp(type, "component") != 0) {
01263         Com_Error(ERR_FATAL, "UI_ParseComponent: \"component\" expected but \"%s\" found.\n", type);
01264         return; /* never reached */
01265     }
01266 
01267     /* CL_ParseClientData read the real type as name */
01268     Com_UnParseLastToken();
01269     token = Com_Parse(text);
01270 
01271     component = UI_ParseNode(NULL, text, &token, errhead);
01272     if (component)
01273         UI_InsertComponent(component);
01274 }
01275 
01276 
01285 void UI_ParseWindow (const char *type, const char *name, const char **text)
01286 {
01287     const char *errhead = "UI_ParseWindow: unexpected end of file (window";
01288     uiNode_t *window;
01289     const char *token;
01290     qboolean result;
01291     int i;
01292 
01293     if (strcmp(type, "window") != 0) {
01294         Com_Error(ERR_FATAL, "UI_ParseWindow: '%s %s' is not a window node\n", type, name);
01295         return; /* never reached */
01296     }
01297 
01298     if (!UI_TokenIsName(name, Com_ParsedTokenIsQuoted())) {
01299         Com_Printf("UI_ParseWindow: \"%s\" is not a well formed node name ([a-zA-Z_][a-zA-Z0-9_]*)\n", name);
01300         return;
01301     }
01302     if (UI_TokenIsReserved(name)) {
01303         Com_Printf("UI_ParseWindow: \"%s\" is a reserved token, we can't call a node with it (node \"%s\")\n", name, name);
01304         return;
01305     }
01306 
01307     /* search for windows with same name */
01308     for (i = 0; i < ui_global.numWindows; i++)
01309         if (!strncmp(name, ui_global.windows[i]->name, sizeof(ui_global.windows[i]->name)))
01310             break;
01311 
01312     if (i < ui_global.numWindows) {
01313         Com_Printf("UI_ParseWindow: %s \"%s\" with same name found, second ignored\n", type, name);
01314     }
01315 
01316     if (ui_global.numWindows >= UI_MAX_WINDOWS) {
01317         Com_Error(ERR_FATAL, "UI_ParseWindow: max windows exceeded (%i) - ignore '%s'\n", UI_MAX_WINDOWS, name);
01318         return; /* never reached */
01319     }
01320 
01321     /* get window body */
01322     token = Com_Parse(text);
01323 
01324     /* does this window inherit data from another window? */
01325     if (!strcmp(token, "extends")) {
01326         uiNode_t *superWindow;
01327         token = Com_Parse(text);
01328         superWindow = UI_GetWindow(token);
01329         if (superWindow == NULL)
01330             Sys_Error("Could not get the super window \"%s\"", token);
01331         window = UI_CloneNode(superWindow, NULL, qtrue, name, qfalse);
01332         token = Com_Parse(text);
01333     } else {
01334         window = UI_AllocNode(name, type, qfalse);
01335         window->root = window;
01336     }
01337 
01338     UI_InsertWindow(window);
01339 
01340     /* parse it's body */
01341     result = UI_ParseNodeBody(window, text, &token, errhead);
01342     if (!result) {
01343         Com_Error(ERR_FATAL, "UI_ParseWindow: window \"%s\" has a bad body\n", window->name);
01344         return; /* never reached */
01345     }
01346 
01347     window->behaviour->loaded(window);
01348 }
01349 
01354 const char *UI_GetReferenceString (const uiNode_t* const node, const char *ref)
01355 {
01356     if (!ref)
01357         return NULL;
01358 
01359     /* its a cvar */
01360     if (ref[0] == '*') {
01361         const char *token;
01362 
01363         /* get the reference and the name */
01364         token = Com_MacroExpandString(ref);
01365         if (token)
01366             return token;
01367 
01368         /* skip the star */
01369         token = ref + 1;
01370         if (token[0] == '\0')
01371             return NULL;
01372 
01373         if (!strncmp(token, "binding:", 8)) {
01374             /* skip prefix */
01375             token = token + 8;
01376             return Key_GetBinding(token, (cls.state != ca_active ? KEYSPACE_UI : KEYSPACE_GAME));
01377         } else {
01378             Sys_Error("UI_GetReferenceString: unknown reference");  
01379 #if 0   
01380             uiNode_t *refNode;
01381             const value_t *val;
01382 
01383             token = Com_Parse(&text);
01384             if (!text)
01385                 return NULL;
01386 
01387             /* draw a reference to a node property */
01388             refNode = UI_GetNode(node->root, ident);
01389             if (!refNode)
01390                 return NULL;
01391 
01392             /* get the property */
01393             val = UI_GetPropertyFromBehaviour(refNode->behaviour, token);
01394             if (!val)
01395                 return NULL;
01396 
01397             /* get the string */
01398             return Com_ValueToStr(refNode, val->type & V_BASETYPEMASK, val->ofs);
01399 #endif
01400         }
01401 
01402     /* translatable string */
01403     } else if (ref[0] == '_') {
01404         ref++;
01405         return _(ref);
01406 
01407     /* just a string */
01408     } else {
01409         return ref;
01410     }
01411 }
01412 
01413 float UI_GetReferenceFloat (const uiNode_t* const node, const void *ref)
01414 {
01415     if (!ref)
01416         return 0.0;
01417     if (((const char *) ref)[0] == '*') {
01418         const char *token;
01419         token = (const char *) ref + 1;
01420 
01421         if (token[0] == '\0')
01422             return 0.0;
01423 
01424         if (!strncmp(token, "cvar:", 5)) {
01425             /* get the cvar value */
01426             return Cvar_GetValue(token + 5);
01427         } else {
01429             Sys_Error("UI_GetReferenceFloat: unknown reference '%s' from node '%s'",
01430                     token, node->name);
01431 #if 0   
01432             uiNode_t *refNode;
01433             const value_t *val;
01434 
01435             /* draw a reference to a node property */
01436             refNode = UI_GetNode(node->root, ident);
01437             if (!refNode)
01438                 return 0.0;
01439 
01440             /* get the property */
01441             val = UI_GetPropertyFromBehaviour(refNode->behaviour, token);
01442             if (!val || val->type != V_FLOAT)
01443                 return 0.0;
01444 
01445             /* get the string */
01446             return *(float *) ((byte *) refNode + val->ofs);
01447 #endif
01448         }
01449     } else {
01450         /* just get the data */
01451         return *(const float *) ref;
01452     }
01453 }

Generated by  doxygen 1.6.2