00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include <assert.h>
00031 #include <ctype.h>
00032 #include <errno.h>
00033 #include <limits.h>
00034 #include <stdio.h>
00035 #include <stdlib.h>
00036 #include <string.h>
00037 #include <unistd.h>
00038 #include <math.h>
00039 #include <stdarg.h>
00040
00041
00042
00043 #include "replace.h"
00044 #include "stage.hh"
00045 #include "worldfile.hh"
00046 using namespace Stg;
00047
00048
00049
00050 #ifndef isblank
00051 #define isblank(a) (a == ' ' || a == '\t')
00052 #endif
00053
00055
00056 #define TOKEN_ERR(z, l) \
00057 PRINT_ERR2("%s:%d : " z, this->filename.c_str(), l)
00058 #define PARSE_ERR(z, l) \
00059 PRINT_ERR2("%s:%d : " z, this->filename.c_str(), l)
00060
00061
00063
00064 Worldfile::Worldfile() :
00065 tokens(),
00066 macros(),
00067 entities(),
00068 properties(),
00069 filename(),
00070 unit_length( 1.0 ),
00071 unit_angle( M_PI / 180.0 )
00072 {
00073 }
00074
00075
00077
00078 Worldfile::~Worldfile()
00079 {
00080 ClearProperties();
00081 ClearMacros();
00082 ClearEntities();
00083 ClearTokens();
00084 }
00085
00086 FILE *Worldfile::FileOpen(const std::string& filename, const char* method)
00087 {
00088 FILE *fp = fopen(filename.c_str(), method);
00089
00090 if (fp) {
00091 PRINT_DEBUG1( "Loading: %s", filename.c_str());
00092 return fp;
00093 }
00094
00095
00096 char *stagepath = getenv("STAGEPATH");
00097 char *token = strtok(stagepath, ":");
00098 char* fullpath = new char[PATH_MAX];
00099 char *tmp = strdup(filename.c_str());
00100 const char *base = basename(tmp);
00101 while (token != NULL) {
00102
00103 memset( fullpath, 0, PATH_MAX);
00104 strcat( fullpath, token);
00105 strcat( fullpath, "/" );
00106 strcat( fullpath, base);
00107 assert(strlen(fullpath) + 1 < PATH_MAX);
00108 fp = fopen(fullpath, method);
00109 if (fp) {
00110 this->filename = std::string(fullpath);
00111 PRINT_DEBUG1( "Loading: %s", filename.c_str());
00112 free(tmp);
00113 return fp;
00114 }
00115 token = strtok(NULL, ":");
00116 }
00117 if( tmp ) free(tmp);
00118 if( fullpath ) delete[] fullpath;
00119 return NULL;
00120 }
00121
00122
00124
00125 bool Worldfile::Load(const std::string& filename )
00126 {
00127 this->filename = filename;
00128
00129
00130
00131 FILE *file = FileOpen(this->filename.c_str(), "r");
00132 if (!file)
00133 {
00134 PRINT_ERR2("unable to open world file %s : %s",
00135 this->filename.c_str(), strerror(errno));
00136 return false;
00137 }
00138
00139 ClearTokens();
00140
00141
00142 if (!LoadTokens(file, 0))
00143 {
00144
00145 fclose(file);
00146 return false;
00147 }
00148
00149 fclose(file);
00150
00151
00152 if (!ParseTokens())
00153 {
00154
00155 return false;
00156 }
00157
00158
00159 if (ReadInt(0, "test", 0) != 0)
00160 {
00161 PRINT_ERR("this is a test file; quitting");
00162 DumpTokens();
00163 DumpMacros();
00164 DumpEntities();
00165 DumpProperties();
00166 return false;
00167 }
00168
00169
00170 const std::string& unitl = ReadString(0, "unit_length", "m");
00171 if( unitl == "m")
00172 this->unit_length = 1.0;
00173 else if( unitl == "cm")
00174 this->unit_length = 0.01;
00175 else if( unitl == "mm")
00176 this->unit_length = 0.001;
00177
00178
00179 const std::string& unita = ReadString(0, "unit_angle", "degrees");
00180 if( unita == "degrees")
00181 this->unit_angle = M_PI / 180;
00182 else if( unita == "radians")
00183 this->unit_angle = 1;
00184
00185
00186
00187 return true;
00188 }
00189
00190
00192
00193 bool Worldfile::Save(const std::string& filename )
00194 {
00195
00196
00197
00198
00199 FILE *file = fopen(filename.c_str(), "w+");
00200
00201 if (!file)
00202 {
00203 PRINT_ERR2("unable to open world file %s : %s",
00204 filename.c_str(), strerror(errno));
00205 return false;
00206 }
00207
00208
00209
00210
00211 if (!SaveTokens(file))
00212 {
00213 fclose(file);
00214 return false;
00215 }
00216
00217 fclose(file);
00218 return true;
00219 }
00220
00221
00223
00224 bool Worldfile::WarnUnused()
00225 {
00226 bool unused = false;
00227
00228 FOR_EACH( it, properties )
00229 {
00230 if( ! it->second->used )
00231 {
00232 PRINT_WARN3("worldfile %s:%d : property [%s] is defined but not used",
00233 this->filename.c_str(), it->second->line, it->second->name.c_str());
00234 unused = true;
00235 }
00236 }
00237
00238 return unused;
00239 }
00240
00241
00243
00244 bool Worldfile::LoadTokens(FILE *file, int include)
00245 {
00246 int ch;
00247 int line;
00248 char token[256];
00249
00250 line = 1;
00251
00252 while (true)
00253 {
00254 ch = fgetc(file);
00255 if (ch == EOF)
00256 break;
00257
00258 if ((char) ch == '#')
00259 {
00260 ungetc(ch, file);
00261 if (!LoadTokenComment(file, &line, include))
00262 return false;
00263 }
00264 else if (isalpha(ch))
00265 {
00266 ungetc(ch, file);
00267 if (!LoadTokenWord(file, &line, include))
00268 return false;
00269 }
00270 else if (strchr("+-.0123456789", ch))
00271 {
00272 ungetc(ch, file);
00273 if (!LoadTokenNum(file, &line, include))
00274 return false;
00275 }
00276 else if (isblank(ch))
00277 {
00278 ungetc(ch, file);
00279 if (!LoadTokenSpace(file, &line, include))
00280 return false;
00281 }
00282 else if (ch == '"')
00283 {
00284 ungetc(ch, file);
00285 if (!LoadTokenString(file, &line, include))
00286 return false;
00287 }
00288 else if (strchr("(", ch))
00289 {
00290 token[0] = ch;
00291 token[1] = 0;
00292 AddToken(TokenOpenEntity, token, include);
00293 }
00294 else if (strchr(")", ch))
00295 {
00296 token[0] = ch;
00297 token[1] = 0;
00298 AddToken(TokenCloseEntity, token, include);
00299 }
00300 else if (strchr("[", ch))
00301 {
00302 token[0] = ch;
00303 token[1] = 0;
00304 AddToken(TokenOpenTuple, token, include);
00305 }
00306 else if (strchr("]", ch))
00307 {
00308 token[0] = ch;
00309 token[1] = 0;
00310 AddToken(TokenCloseTuple, token, include);
00311 }
00312 else if ( 0x0d == ch )
00313 {
00314 ch = fgetc(file);
00315 if ( 0x0a != ch )
00316 ungetc(ch, file);
00317 line++;
00318 AddToken(TokenEOL, "\n", include);
00319 }
00320 else if ( 0x0a == ch )
00321 {
00322 ch = fgetc(file);
00323 if ( 0x0d != ch )
00324 ungetc(ch, file);
00325 line++;
00326 AddToken(TokenEOL, "\n", include);
00327 }
00328 else
00329 {
00330 TOKEN_ERR("syntax error", line);
00331 return false;
00332 }
00333 }
00334
00335 return true;
00336 }
00337
00338
00340
00341 bool Worldfile::LoadTokenComment(FILE *file, int *line, int include)
00342 {
00343 char token[256];
00344 int len;
00345 int ch;
00346
00347 len = 0;
00348 memset(token, 0, sizeof(token));
00349
00350 while (true)
00351 {
00352 ch = fgetc(file);
00353
00354 if (ch == EOF)
00355 {
00356 AddToken(TokenComment, token, include);
00357 return true;
00358 }
00359 else if ( 0x0a == ch || 0x0d == ch )
00360 {
00361 ungetc(ch, file);
00362 AddToken(TokenComment, token, include);
00363 return true;
00364 }
00365 else
00366 token[len++] = ch;
00367 }
00368 return true;
00369 }
00370
00371
00373
00374 bool Worldfile::LoadTokenWord(FILE *file, int *line, int include)
00375 {
00376 char token[256];
00377 int len;
00378 int ch;
00379
00380 len = 0;
00381 memset(token, 0, sizeof(token));
00382
00383 while (true)
00384 {
00385 ch = fgetc(file);
00386
00387 if (ch == EOF)
00388 {
00389 AddToken(TokenWord, token, include);
00390 return true;
00391 }
00392 else if (isalpha(ch) || isdigit(ch) || strchr(".-_[]", ch))
00393 {
00394 token[len++] = ch;
00395 }
00396 else
00397 {
00398 if (strcmp(token, "include") == 0)
00399 {
00400 ungetc(ch, file);
00401 AddToken(TokenWord, token, include);
00402 if (!LoadTokenInclude(file, line, include))
00403 return false;
00404 }
00405 else
00406 {
00407 ungetc(ch, file);
00408 AddToken(TokenWord, token, include);
00409 }
00410 return true;
00411 }
00412 }
00413 assert(false);
00414 return false;
00415 }
00416
00417
00419
00420 bool Worldfile::LoadTokenInclude(FILE *file, int *line, int include)
00421 {
00422 int ch;
00423 const char *filename;
00424 char *fullpath;
00425
00426 ch = fgetc(file);
00427
00428 if (ch == EOF)
00429 {
00430 TOKEN_ERR("incomplete include statement", *line);
00431 return false;
00432 }
00433 else if (!isblank(ch))
00434 {
00435 TOKEN_ERR("syntax error in include statement", *line);
00436 return false;
00437 }
00438
00439 ungetc(ch, file);
00440 if (!LoadTokenSpace(file, line, include))
00441 return false;
00442
00443 ch = fgetc(file);
00444
00445 if (ch == EOF)
00446 {
00447 TOKEN_ERR("incomplete include statement", *line);
00448 return false;
00449 }
00450 else if (ch != '"')
00451 {
00452 TOKEN_ERR("syntax error in include statement", *line);
00453 return false;
00454 }
00455
00456 ungetc(ch, file);
00457 if (!LoadTokenString(file, line, include))
00458 return false;
00459
00460
00461 filename = GetTokenValue(this->tokens.size() - 1);
00462
00463
00464
00465 if (filename[0] == '/' || filename[0] == '~')
00466 {
00467 fullpath = strdup(filename);
00468 }
00469 else if (this->filename[0] == '/' || this->filename[0] == '~')
00470 {
00471
00472
00473
00474 char *tmp = strdup(this->filename.c_str());
00475 fullpath = new char[PATH_MAX];
00476 memset(fullpath, 0, PATH_MAX);
00477 strcat( fullpath, dirname(tmp));
00478 strcat( fullpath, "/" );
00479 strcat( fullpath, filename );
00480 assert(strlen(fullpath) + 1 < PATH_MAX);
00481 free(tmp);
00482 }
00483 else
00484 {
00485
00486
00487
00488 char *tmp = strdup(this->filename.c_str());
00489 fullpath = new char[PATH_MAX];
00490 char* dummy = getcwd(fullpath, PATH_MAX);
00491 if (!dummy)
00492 {
00493 PRINT_ERR2("unable to get cwd %d: %s", errno, strerror(errno));
00494 if(tmp) free(tmp);
00495 delete[] fullpath;
00496 return false;
00497 }
00498 strcat( fullpath, "/" );
00499 strcat( fullpath, dirname(tmp));
00500 strcat( fullpath, "/" );
00501 strcat( fullpath, filename );
00502 assert(strlen(fullpath) + 1 < PATH_MAX);
00503 free(tmp);
00504 }
00505
00506 printf( "[Include %s]", filename );
00507 fflush( stdout );
00508
00509
00510 FILE *infile = FileOpen(fullpath, "r");
00511 if (!infile)
00512 {
00513 PRINT_ERR2("unable to open include file %s : %s",
00514 fullpath, strerror(errno));
00515
00516 delete[] fullpath;
00517 return false;
00518 }
00519
00520
00521 AddToken(TokenEOL, "\n", include);
00522
00523
00524
00525
00526 if (!LoadTokens(infile, include + 1))
00527 {
00528 fclose( infile );
00529
00530
00531 delete[] fullpath;
00532 return false;
00533 }
00534
00535
00536 fclose( infile );
00537
00538
00539
00540 while ( ch != '\n' )
00541 ch = fgetc(file);
00542
00543 delete[] fullpath;
00544 return true;
00545 }
00546
00547
00549
00550 bool Worldfile::LoadTokenNum(FILE *file, int *line, int include)
00551 {
00552 char token[256];
00553 int len;
00554 int ch;
00555
00556 len = 0;
00557 memset(token, 0, sizeof(token));
00558
00559 while (true)
00560 {
00561 ch = fgetc(file);
00562
00563 if (ch == EOF)
00564 {
00565 AddToken(TokenNum, token, include);
00566 return true;
00567 }
00568 else if (strchr("+-.0123456789", ch))
00569 {
00570 token[len++] = ch;
00571 }
00572 else
00573 {
00574 AddToken(TokenNum, token, include);
00575 ungetc(ch, file);
00576 return true;
00577 }
00578 }
00579 assert(false);
00580 return false;
00581 }
00582
00583
00585
00586 bool Worldfile::LoadTokenString(FILE *file, int *line, int include)
00587 {
00588 int ch;
00589 int len;
00590 char token[256];
00591
00592 len = 0;
00593 memset(token, 0, sizeof(token));
00594
00595 ch = fgetc(file);
00596
00597 while (true)
00598 {
00599 ch = fgetc(file);
00600
00601 if ( EOF == ch || 0x0a == ch || 0x0d == ch )
00602 {
00603 TOKEN_ERR("unterminated string constant", *line);
00604 return false;
00605 }
00606 else if (ch == '"')
00607 {
00608 AddToken(TokenString, token, include);
00609 return true;
00610 }
00611 else
00612 {
00613 token[len++] = ch;
00614 }
00615 }
00616 assert(false);
00617 return false;
00618 }
00619
00620
00622
00623 bool Worldfile::LoadTokenSpace(FILE *file, int *line, int include)
00624 {
00625 int ch;
00626 int len;
00627 char token[256];
00628
00629 len = 0;
00630 memset(token, 0, sizeof(token));
00631
00632 while (true)
00633 {
00634 ch = fgetc(file);
00635
00636 if (ch == EOF)
00637 {
00638 AddToken(TokenSpace, token, include);
00639 return true;
00640 }
00641 else if (isblank(ch))
00642 {
00643 token[len++] = ch;
00644 }
00645 else
00646 {
00647 AddToken(TokenSpace, token, include);
00648 ungetc(ch, file);
00649 return true;
00650 }
00651 }
00652 assert(false);
00653 return false;
00654 }
00655
00656
00658
00659 bool Worldfile::SaveTokens(FILE *file)
00660 {
00661 unsigned int i;
00662 CToken *token;
00663
00664 for (i = 0; i < this->tokens.size(); i++)
00665 {
00666 token = &this->tokens[i];
00667
00668 if (token->include > 0)
00669 continue;
00670 if (token->type == TokenString)
00671 fprintf(file, "\"%s\"", token->value.c_str());
00672 else
00673 fprintf(file, "%s", token->value.c_str());
00674 }
00675 return true;
00676 }
00677
00678
00680
00681 void Worldfile::ClearTokens()
00682 {
00683 tokens.clear();
00684 }
00685
00686
00688
00689 bool Worldfile::AddToken(int type, const char *value, int include)
00690 {
00691 tokens.push_back( CToken( include, type, value ));
00692 return true;
00693 }
00694
00695
00697
00698 bool Worldfile::SetTokenValue(int index, const char *value)
00699 {
00700 assert(index >= 0 && index < (int)this->tokens.size() );
00701 tokens[index].value = value;
00702 return true;
00703 }
00704
00705
00707
00708 const char *Worldfile::GetTokenValue(int index)
00709 {
00710 assert(index >= 0 && index < (int)this->tokens.size());
00711 return this->tokens[index].value.c_str();
00712 }
00713
00714
00716
00717 void Worldfile::DumpTokens()
00718 {
00719 int line;
00720
00721 line = 1;
00722 printf("\n## begin tokens\n");
00723 printf("## %4d : ", line);
00724
00725 FOR_EACH( it, tokens )
00726
00727 {
00728 if ( it->value[0] == '\n')
00729 printf("[\\n]\n## %4d : %02d ", ++line, it->include);
00730 else
00731 printf("[%s] ", it->value.c_str());
00732 }
00733 printf("\n");
00734 printf("## end tokens\n");
00735 }
00736
00737
00739
00740 bool Worldfile::ParseTokens()
00741 {
00742 int i;
00743 int entity;
00744 int line;
00745 CToken *token;
00746
00747 ClearEntities();
00748 ClearProperties();
00749
00750
00751 entity = AddEntity(-1, "");
00752 line = 1;
00753
00754 for (i = 0; i < (int)this->tokens.size(); i++)
00755 {
00756 token = &this->tokens[0] + i;
00757
00758 switch (token->type)
00759 {
00760 case TokenWord:
00761 if ( token->value == "include")
00762 {
00763 if (!ParseTokenInclude(&i, &line))
00764 return false;
00765 }
00766 else if ( token->value == "define" )
00767 {
00768 if (!ParseTokenDefine(&i, &line))
00769 return false;
00770 }
00771 else
00772 {
00773 if (!ParseTokenWord(entity, &i, &line))
00774 return false;
00775 }
00776 break;
00777 case TokenComment:
00778 break;
00779 case TokenSpace:
00780 break;
00781 case TokenEOL:
00782 line++;
00783 break;
00784 default:
00785 PARSE_ERR("syntax error 1", line);
00786 return false;
00787 }
00788 }
00789 return true;
00790 }
00791
00792
00794
00795 bool Worldfile::ParseTokenInclude(int *index, int *line)
00796 {
00797 int i;
00798 CToken *token;
00799
00800 for (i = *index + 1; i < (int)this->tokens.size(); i++)
00801 {
00802 token = &this->tokens[i];
00803
00804 switch (token->type)
00805 {
00806 case TokenString:
00807 break;
00808 case TokenSpace:
00809 break;
00810 case TokenEOL:
00811 *index = i;
00812 (*line)++;
00813 return true;
00814 default:
00815 PARSE_ERR("syntax error in include statement", *line);
00816 return false;
00817 }
00818 }
00819 PARSE_ERR("incomplete include statement", *line);
00820 return false;
00821 }
00822
00823
00825
00826 bool Worldfile::ParseTokenDefine(int *index, int *line)
00827 {
00828 int i;
00829 int count;
00830 const char *macroname, *entityname;
00831 int starttoken;
00832 CToken *token;
00833
00834 count = 0;
00835 macroname = NULL;
00836 entityname = NULL;
00837 starttoken = -1;
00838
00839 for (i = *index + 1; i < (int)this->tokens.size(); i++)
00840 {
00841 token = &this->tokens[i];
00842
00843 switch (token->type)
00844 {
00845 case TokenWord:
00846 if (count == 0)
00847 {
00848 if (macroname == NULL)
00849 macroname = GetTokenValue(i);
00850 else if (entityname == NULL)
00851 {
00852 entityname = GetTokenValue(i);
00853 starttoken = i;
00854 }
00855 else
00856 {
00857 PARSE_ERR("extra tokens in macro definition", *line);
00858 return false;
00859 }
00860 }
00861 else
00862 {
00863 if (macroname == NULL)
00864 {
00865 PARSE_ERR("missing name in macro definition", *line);
00866 return false;
00867 }
00868 if (entityname == NULL)
00869 {
00870 PARSE_ERR("missing name in macro definition", *line);
00871 return false;
00872 }
00873 }
00874 break;
00875 case TokenOpenEntity:
00876 count++;
00877 break;
00878 case TokenCloseEntity:
00879 count--;
00880 if (count == 0)
00881 {
00882 AddMacro(macroname, entityname, *line, starttoken, i);
00883 *index = i;
00884 return true;
00885 }
00886 if (count < 0)
00887 {
00888 PARSE_ERR("misplaced ')'", *line);
00889 return false;
00890 }
00891 break;
00892 default:
00893 break;
00894 }
00895 }
00896 PARSE_ERR("missing ')'", *line);
00897 return false;
00898 }
00899
00900
00902
00903 bool Worldfile::ParseTokenWord(int entity, int *index, int *line)
00904 {
00905 int i;
00906 CToken *token;
00907
00908 for (i = *index + 1; i < (int)this->tokens.size(); i++)
00909 {
00910 token = &this->tokens[i];
00911
00912 switch (token->type)
00913 {
00914 case TokenComment:
00915 break;
00916 case TokenSpace:
00917 break;
00918 case TokenEOL:
00919 (*line)++;
00920 break;
00921 case TokenOpenEntity:
00922 return ParseTokenEntity(entity, index, line);
00923 case TokenNum:
00924 case TokenString:
00925 case TokenOpenTuple:
00926 return ParseTokenProperty(entity, index, line);
00927 default:
00928 PARSE_ERR("syntax error 2", *line);
00929 return false;
00930 }
00931 }
00932
00933 return false;
00934 }
00935
00936
00938
00939 bool Worldfile::ParseTokenEntity(int entity, int *index, int *line)
00940 {
00941 int i;
00942
00943 int name;
00944 CToken *token;
00945
00946 name = *index;
00947 CMacro* macro = LookupMacro(GetTokenValue(name));
00948
00949
00950 if (macro )
00951 {
00952 int nentity = this->entities.size();
00953 int mindex = macro->starttoken;
00954 int mline = macro->line;
00955 if (!ParseTokenEntity(entity, &mindex, &mline))
00956 return false;
00957 entity = nentity;
00958
00959 for (i = *index + 1; i < (int)this->tokens.size(); i++)
00960 {
00961 token = &this->tokens[i];
00962
00963 switch (token->type)
00964 {
00965 case TokenOpenEntity:
00966 break;
00967 case TokenWord:
00968 if (!ParseTokenWord(entity, &i, line))
00969 return false;
00970 break;
00971 case TokenCloseEntity:
00972 *index = i;
00973 return true;
00974 case TokenComment:
00975 break;
00976 case TokenSpace:
00977 break;
00978 case TokenEOL:
00979 (*line)++;
00980 break;
00981 default:
00982 PARSE_ERR("syntax error 3", *line);
00983 return false;
00984 }
00985 }
00986 PARSE_ERR("missing ')'", *line);
00987 }
00988
00989
00990 else
00991 {
00992 for (i = *index + 1; i < (int)this->tokens.size(); i++)
00993 {
00994 token = &this->tokens[i];
00995
00996 switch (token->type)
00997 {
00998 case TokenOpenEntity:
00999 entity = AddEntity(entity, GetTokenValue(name));
01000 break;
01001 case TokenWord:
01002 if (!ParseTokenWord(entity, &i, line))
01003 return false;
01004 break;
01005 case TokenCloseEntity:
01006 *index = i;
01007 return true;
01008 case TokenComment:
01009 break;
01010 case TokenSpace:
01011 break;
01012 case TokenEOL:
01013 (*line)++;
01014 break;
01015 default:
01016 PARSE_ERR("syntax error 3", *line);
01017 return false;
01018 }
01019 }
01020 PARSE_ERR("missing ')'", *line);
01021 }
01022 return false;
01023 }
01024
01025
01027
01028 bool Worldfile::ParseTokenProperty(int entity, int *index, int *line)
01029 {
01030 CProperty* property(NULL);
01031 int name( *index );
01032 CToken *token(NULL);
01033
01034 for(int i = *index + 1; i < (int)this->tokens.size(); i++)
01035 {
01036 token = &this->tokens[i];
01037
01038 switch (token->type)
01039 {
01040 case TokenNum:
01041 property = AddProperty(entity, GetTokenValue(name), *line);
01042 AddPropertyValue(property, 0, i);
01043 *index = i;
01044 return true;
01045 case TokenString:
01046 property = AddProperty(entity, GetTokenValue(name), *line);
01047 AddPropertyValue(property, 0, i);
01048 *index = i;
01049 return true;
01050 case TokenOpenTuple:
01051 property = AddProperty(entity, GetTokenValue(name), *line);
01052 if (!ParseTokenTuple( property, &i, line))
01053 return false;
01054 *index = i;
01055 return true;
01056 case TokenSpace:
01057 break;
01058 default:
01059 PARSE_ERR("syntax error 4", *line);
01060 return false;
01061 }
01062 }
01063 return true;
01064 }
01065
01066
01068
01069 bool Worldfile::ParseTokenTuple( CProperty* property, int *index, int *line)
01070 {
01071 unsigned int i, count;
01072 CToken *token;
01073
01074 count = 0;
01075
01076 for (i = *index + 1; i < this->tokens.size(); i++)
01077 {
01078 token = &this->tokens[i];
01079
01080 switch (token->type)
01081 {
01082 case TokenNum:
01083 AddPropertyValue(property, count++, i);
01084 *index = i;
01085 break;
01086 case TokenString:
01087 AddPropertyValue(property, count++, i);
01088 *index = i;
01089 break;
01090 case TokenCloseTuple:
01091 *index = i;
01092 return true;
01093 case TokenSpace:
01094 break;
01095 default:
01096 PARSE_ERR("syntax error 5", *line);
01097 return false;
01098 }
01099 }
01100 return true;
01101 }
01102
01103
01105
01106 void Worldfile::ClearMacros()
01107 {
01108 macros.clear();
01109 }
01110
01111
01113
01114 void Worldfile::AddMacro(const char *macroname, const char *entityname,
01115 int line, int starttoken, int endtoken)
01116 {
01117 macros.insert( std::pair<std::string,CMacro>( macroname, CMacro( macroname, entityname, line, starttoken, endtoken )));
01118 }
01119
01120
01122
01123
01124 Worldfile::CMacro* Worldfile::LookupMacro(const char *macroname)
01125 {
01126 std::map<std::string,CMacro>::iterator it = macros.find( macroname );
01127
01128 if( it == macros.end() )
01129 return NULL;
01130 else
01131 return &it->second;
01132 }
01133
01134
01136
01137 void Worldfile::DumpMacros()
01138 {
01139 printf("\n## begin macros\n");
01140
01141 FOR_EACH( it, macros )
01142
01143 {
01144 CMacro *macro = &(it->second);
01145
01146 printf("## [%s][%s]", macro->macroname.c_str(), macro->entityname.c_str());
01147 for (int j = macro->starttoken; j <= macro->endtoken; j++)
01148 {
01149 if (this->tokens[j].type == TokenEOL)
01150 printf("[\\n]");
01151 else
01152 printf("[%s]", GetTokenValue(j));
01153 }
01154 printf("\n");
01155 }
01156 printf("## end macros\n");
01157 }
01158
01159
01161
01162 void Worldfile::ClearEntities()
01163 {
01164
01165
01166
01167
01168
01169 this->entities.clear();
01170 }
01171
01172
01174
01175 int Worldfile::AddEntity(int parent, const char *type)
01176 {
01177
01178
01179
01180
01181
01182
01183
01184
01185
01186
01187
01188
01189 this->entities.push_back( CEntity( parent, type ));
01190 return( entities.size()-1);
01191 }
01192
01193
01195
01196 int Worldfile::GetEntityCount()
01197 {
01198 return this->entities.size();
01199 }
01200
01201
01203
01204 int Worldfile::GetEntityParent(int entity)
01205 {
01206 if (entity < 0 || entity >= (int)this->entities.size())
01207 return -1;
01208 return this->entities[entity].parent;
01209 }
01210
01211
01213
01214 const char *Worldfile::GetEntityType(int entity)
01215 {
01216 if (entity < 0 || entity >= (int)this->entities.size())
01217 return NULL;
01218 return this->entities[entity].type.c_str();
01219 }
01220
01221
01223
01224
01225 int Worldfile::LookupEntity(const char *type)
01226 {
01227 for (int entity = 0; entity < GetEntityCount(); entity++)
01228 {
01229 if (strcmp(GetEntityType(entity), type) == 0)
01230 return entity;
01231 }
01232 return -1;
01233 }
01234
01235
01236 void PrintProp( const char* key, CProperty* prop )
01237 {
01238 if( prop )
01239 printf( "Print key %s prop ent %d name %s\n", key, prop->entity, prop->name.c_str() );
01240 }
01241
01243
01244 void Worldfile::DumpEntities()
01245 {
01246 printf("\n## begin entities\n");
01247
01248 FOR_EACH( it, properties )
01249 PrintProp( it->first.c_str(), it->second );
01250
01251 printf("## end entities\n");
01252 }
01253
01254
01256
01257 void Worldfile::ClearProperties()
01258 {
01259 FOR_EACH( it, properties )
01260 delete it->second;
01261 properties.clear();
01262 }
01263
01264
01266
01267 CProperty* Worldfile::AddProperty(int entity, const char *name, int line)
01268 {
01269 char key[128];
01270 snprintf( key, 127, "%d%s", entity, name );
01271
01272 CProperty *property = new CProperty( entity, name, line );
01273
01274 properties[ key ] = property;
01275
01276 return property;
01277 }
01278
01279
01281
01282 void Worldfile::AddPropertyValue( CProperty* property, int index, int value_token)
01283 {
01284 assert(property);
01285
01286
01287
01288 if( index >= (int)property->values.size() )
01289 property->values.resize( index+1 );
01290
01291 property->values[index] = value_token;
01292 }
01293
01294
01295
01297
01298 CProperty* Worldfile::GetProperty(int entity, const char *name)
01299 {
01300 char key[128];
01301 snprintf( key, 127, "%d%s", entity, name );
01302
01303
01304
01305 static char cache_key[128] = { 0 };
01306 static CProperty* cache_property = NULL;
01307
01308 if( strncmp( key, cache_key, 128 ) != 0 )
01309 {
01310 strncpy( cache_key, key, 128 );
01311
01312 std::map<std::string,CProperty*>::iterator it = properties.find( key );
01313 if( it == properties.end() )
01314 cache_property = NULL;
01315 else
01316 cache_property = it->second;
01317 }
01318
01319
01320
01321 return cache_property;
01322 }
01323
01324 bool Worldfile::PropertyExists( int section, const char* token )
01325 {
01326 return (bool)GetProperty( section, token );
01327 }
01328
01329
01331
01332 void Worldfile::SetPropertyValue( CProperty* property, int index, const char *value)
01333 {
01334 assert( property );
01335
01336
01337
01338 assert(index >= 0 && index < (int)property->values.size() );
01339
01340 SetTokenValue( property->values[index], value);
01341 }
01342
01344
01345 const char *Worldfile::GetPropertyValue(CProperty* property, int index)
01346 {
01347 assert(property);
01348 property->used = true;
01349 return GetTokenValue(property->values[index]);
01350 }
01351
01352
01354
01355 void Worldfile::DumpProperties()
01356 {
01357 printf("\n## begin properties\n");
01358
01359
01360
01361
01362
01363
01364
01365
01366
01367
01368
01369
01370 printf("## end properties\n");
01371 }
01372
01373
01375
01376 const std::string Worldfile::ReadString(int entity, const char *name, const std::string& value)
01377 {
01378 CProperty* property = GetProperty(entity, name);
01379 if (property == NULL )
01380 return value;
01381 return GetPropertyValue(property, 0);
01382 }
01383
01384
01386
01387 void Worldfile::WriteString(int entity, const char *name, const std::string &value)
01388 {
01389 CProperty* property = GetProperty(entity, name);
01390 if( property == NULL )
01391 return;
01392 SetPropertyValue(property, 0, value.c_str());
01393 }
01394
01395
01397
01398 int Worldfile::ReadInt(int entity, const char *name, int value)
01399 {
01400 CProperty* property = GetProperty(entity, name);
01401 if (property == NULL )
01402 return value;
01403 return atoi(GetPropertyValue(property, 0));
01404 }
01405
01406
01408
01409 void Worldfile::WriteInt(int entity, const char *name, int value)
01410 {
01411 char default_str[64];
01412 snprintf(default_str, sizeof(default_str), "%d", value);
01413 WriteString(entity, name, default_str);
01414 }
01415
01417
01418 void Worldfile::WriteFloat(int entity, const char *name, double value)
01419 {
01420
01421 if( fabs(value) < 0.001 )
01422 WriteString(entity, name, "0" );
01423 else
01424 {
01425 char default_str[64];
01426 snprintf(default_str, sizeof(default_str), "%.3f", value);
01427 WriteString(entity, name, default_str);
01428 }
01429 }
01430
01431
01433
01434 double Worldfile::ReadFloat(int entity, const char *name, double value)
01435 {
01436 CProperty* property = GetProperty(entity, name);
01437 if (property == NULL )
01438 return value;
01439 return atof(GetPropertyValue(property, 0));
01440 }
01441
01442
01444
01445
01446
01447
01448
01449
01450 const char *Worldfile::ReadFilename(int entity, const char *name, const char *value)
01451 {
01452 CProperty* property = GetProperty(entity, name);
01453 if (property == NULL )
01454 return value;
01455 const char *filename = GetPropertyValue(property, 0);
01456
01457 if( filename[0] == '/' || filename[0] == '~' )
01458 return filename;
01459
01460 else if (this->filename[0] == '/' || this->filename[0] == '~')
01461 {
01462
01463
01464
01465 char *tmp = strdup(this->filename.c_str());
01466 char* fullpath = new char[PATH_MAX];
01467 memset(fullpath, 0, PATH_MAX);
01468 strcat( fullpath, dirname(tmp));
01469 strcat( fullpath, "/" );
01470 strcat( fullpath, filename );
01471 assert(strlen(fullpath) + 1 < PATH_MAX);
01472 if(tmp) free(tmp);
01473 return fullpath;
01474 }
01475 else
01476 {
01477
01478
01479
01480
01481 char *tmp = strdup(this->filename.c_str());
01482 char* fullpath = new char[PATH_MAX];
01483 char* dummy = getcwd(fullpath, PATH_MAX);
01484 if (!dummy)
01485 {
01486 PRINT_ERR2("unable to get cwd %d: %s", errno, strerror(errno));
01487 if( fullpath ) delete[] fullpath;
01488 if( tmp ) free(tmp);
01489 return value;
01490 }
01491
01492 strcat( fullpath, "/" );
01493 strcat( fullpath, dirname(tmp));
01494 strcat( fullpath, "/" );
01495 strcat( fullpath, filename );
01496 assert(strlen(fullpath) + 1 < PATH_MAX);
01497 free(tmp);
01498
01499 return fullpath;
01500 }
01501 }
01502
01503
01505
01506 int Worldfile::ReadTuple( const int entity, const char *name,
01507 const unsigned int first, const unsigned int count, const char* format, ... )
01508 {
01509 CProperty* property = GetProperty(entity, name);
01510 if (property == NULL )
01511 return 0;
01512
01513 if( property->values.size() < first+count )
01514 {
01515 PRINT_ERR4( "Worldfile: reading tuple \"%s\" index %u to %u - tuple has length %u\n",
01516 name, first, first+count-1, (unsigned int)property->values.size() );
01517 exit(-1);
01518 }
01519
01520 if( strlen(format) != count )
01521 {
01522 PRINT_ERR2( "format string length %u does not match argument count %u",
01523 (unsigned int)strlen(format), count );
01524 exit(-1);
01525 }
01526
01527 va_list args;
01528 va_start( args, format );
01529
01530 for( unsigned int i=0; i<count; i++ )
01531 {
01532 const char* val = GetPropertyValue(property, first+i);
01533
01534 switch( format[i] )
01535 {
01536 case 'i':
01537 *va_arg( args, int* ) = atoi(val);
01538 break;
01539
01540 case 'u':
01541 *va_arg( args, unsigned int* ) = (unsigned int)atoi(val);
01542 break;
01543
01544 case 'f':
01545 *va_arg( args, double* ) = atof(val);
01546 break;
01547
01548 case 'l':
01549 *va_arg( args, double* ) = atof(val) * unit_length;
01550 break;
01551
01552 case 'a':
01553 *va_arg( args, double* ) = atof(val) * unit_angle;
01554 break;
01555
01556 case 's':
01557 *va_arg( args, char** ) = strdup(val);
01558 break;
01559
01560 default:
01561 PRINT_ERR3( "Unknown format character %c in string %s loading %s",
01562 format[i], format, name );
01563 }
01564 }
01565
01566 va_end( args );
01567
01568 return count;
01569 }
01570
01572
01573 void Worldfile::WriteTuple( const int entity, const char *name,
01574 const unsigned int first, const unsigned int count, const char* format, ... )
01575 {
01576 CProperty* property = GetProperty(entity, name);
01577 if (property == NULL )
01578 return;
01579
01580 if( property->values.size() < first+count )
01581 {
01582 PRINT_ERR4( "Worldfile: reading tuple \"%s\" index %d to %d - tuple has length %d\n",
01583 name, first, first+count-1, (int)property->values.size() );
01584 exit(-1);
01585 }
01586
01587 if( strlen(format) != count )
01588 {
01589 PRINT_ERR2( "format string length %u does not match argument count %u",
01590 (unsigned int)strlen(format), count );
01591 exit(-1);
01592 }
01593
01594 char buf[2048];
01595 buf[0] = 0;
01596
01597 va_list args;
01598 va_start( args, format );
01599
01600 for( unsigned int i=0; i<count; i++ )
01601 {
01602 switch( format[i] )
01603 {
01604 case 'i':
01605 snprintf( buf, sizeof(buf), "%d", va_arg( args, int ) );
01606 break;
01607
01608 case 'u':
01609 snprintf( buf, sizeof(buf), "%u", va_arg( args, unsigned int ) );
01610 break;
01611
01612 case 'f':
01613 snprintf( buf, sizeof(buf), "%.3f", va_arg( args, double ) );
01614 break;
01615
01616 case 'l':
01617 snprintf( buf, sizeof(buf), "%.3f", va_arg( args, double ) / unit_length );
01618 break;
01619
01620 case 'a':
01621 snprintf( buf, sizeof(buf), "%.3f", va_arg( args, double ) / unit_angle );
01622 break;
01623
01624 case 's':
01625 strncpy( buf, va_arg( args, char* ), sizeof(buf) );
01626 buf[sizeof(buf)-1] = 0;
01627 break;
01628
01629 default:
01630 PRINT_ERR3( "Unknown format character %c in string %s loading %s",
01631 format[i], format, name );
01632 exit(-1);
01633 }
01634
01635
01636 SetPropertyValue(property, first+i, buf );
01637 }
01638
01639 va_end( args );
01640 }
01641