added simple 'condition scripts'
[k8-i-v-a-n.git] / src / felib / fesave.cpp
blob49c0a9c26e471da5f0c83ac8b5684c6388ce3b09
1 /*
3 * Iter Vehemens ad Necem (IVAN)
4 * Copyright (C) Timo Kiviluoto
5 * Released under the GNU General
6 * Public License
8 * See LICENSING which should be included
9 * along with this file for more details
12 #ifndef _GNU_SOURCE
13 # define _GNU_SOURCE
14 #endif
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <unistd.h>
22 #include <cctype>
24 #ifdef WIN32
25 # include <windows.h>
26 #endif
28 #include "fesave.h"
29 #include "femath.h"
32 truth inputfile::fileExists (const festring &fname) {
33 #ifndef WIN32
34 struct stat st;
35 if (stat(fname.CStr(), &st)) return false;
36 if (!S_ISREG(st.st_mode)) return false;
37 return access(fname.CStr(), R_OK) == 0;
38 #else
39 FILE *fl = fopen(fname.CStr(), "rb");
40 if (fl) fclose(fl);
41 return fl != 0;
42 #endif
46 festring inputfile::GetMyDir (void) {
47 char myDir[8192];
48 #ifndef WIN32
49 char buf[128];
50 pid_t mypid = getpid();
51 memset(myDir, 0, sizeof(myDir));
52 sprintf(buf, "/proc/%u/exe", (unsigned int)mypid);
53 if (readlink(buf, myDir, sizeof(myDir)-1) < 0) strcpy(myDir, ".");
54 else {
55 char *p = (char *)strrchr(myDir, '/');
56 if (!p) strcpy(myDir, "."); else *p = '\0';
58 if (myDir[strlen(myDir)-1] == '/') myDir[strlen(myDir)-1] = '\0';
59 #else
60 char *p;
61 memset(myDir, 0, sizeof(myDir));
62 GetModuleFileName(GetModuleHandle(NULL), myDir, sizeof(myDir)-1);
63 p = strrchr(myDir, '\\');
64 if (!p) strcpy(myDir, "."); else *p = '\0';
65 #endif
66 return myDir;
70 outputfile::outputfile (cfestring &FileName, truth AbortOnErr) :
71 Buffer(fopen(FileName.CStr(), "wb")),
72 FileName(FileName)
74 if (AbortOnErr && !IsOpen()) ABORT("Can't open %s for output!", FileName.CStr());
78 outputfile::~outputfile () {
79 if (Buffer) fclose(Buffer);
83 void outputfile::ReOpen () {
84 fclose(Buffer);
85 Buffer = fopen(FileName.CStr(), "ab");
89 inputfile::inputfile (cfestring &FileName, const valuemap *ValueMap, truth AbortOnErr) :
90 Buffer(fopen(FileName.CStr(), "rb")),
91 FileName(FileName),
92 ValueMap(ValueMap),
93 lastWordWasString(false)
95 if (AbortOnErr && !IsOpen()) ABORT("File %s not found!", FileName.CStr());
99 inputfile::~inputfile () {
100 if (Buffer) fclose(Buffer);
104 festring inputfile::findVar (cfestring &name, truth *found) const {
105 VarMap::const_iterator i = mVars.find(name);
106 if (i != mVars.end()) {
107 if (found) *found = true;
108 return i->second;
110 if (found) *found = false;
111 return "";
115 festring inputfile::getVar (cfestring &name) {
116 truth found;
117 festring res = findVar(name, &found);
119 if (!found) {
120 if (mGetVar) {
121 res = mGetVar(this, name);
122 } else {
123 festring s = "unknown variable: "+name;
124 die(s);
127 return res;
131 void inputfile::setVar (cfestring &name, cfestring &value) {
132 mVars[name] = value;
136 //TODO: invoke callback
137 truth inputfile::delVar (cfestring &name) {
138 VarMap::iterator i = mVars.find(name);
139 if (i != mVars.end()) {
140 mVars.erase(i);
141 return true;
143 return false;
147 void inputfile::die (cfestring &msg) {
148 ABORT("ERROR in file %s, line %d: %s", GetFileName().CStr(), TellLine(), msg.CStr());
152 // 0: term
153 // 1: unary
154 // 2: comparisons
155 // 3: &&
156 // 4: ||
157 const int maxCPrio = 4;
158 const char *opers[5][7] = {
159 {NULL},
160 {NULL},
161 {"<", ">", "<=", ">=", "==", "!=", NULL},
162 {"&&", NULL},
163 {"||", NULL}
166 festring inputfile::readCondition (festring &token, int prio, truth skipIt) {
167 festring res, op1, opc;
168 //fprintf(stderr, "IN: prio: %d; skip: %s; [%s]\n", prio, skipIt?"t":"o", token.CStr());
169 switch (prio) {
170 case 0: // term
171 if (token == "(") {
172 readWordIntr(token, true);
173 res = readCondition(token, maxCPrio, skipIt);
174 if (token != ")") die("')' expected");
175 } else if (token == "@") {
176 readWordIntr(token, true);
177 if (!skipIt) res = getVar(token);
178 } else {
179 res = token;
181 readWordIntr(token, true);
182 goto done;
183 //return res;
184 case 1:
185 if (token == "!") {
186 readWordIntr(token, true);
187 res = readCondition(token, 1, skipIt);
188 if (!skipIt) {
189 if (res == "") res = "tan"; else res = "";
191 } else {
192 res = readCondition(token, prio-1, skipIt);
194 goto done;
195 //return res;
198 if (prio > 4) return res;
199 res = readCondition(token, prio-1, skipIt);
200 for (;;) {
201 //readWordIntr(token, true);
202 bool myOp = false;
203 if (token == "=") die("no assignments yet!");
204 if (token == ";") {
205 //fprintf(stderr, " RET: [%s]\n", res.CStr());
206 break;
208 if (token == "less") token = "<";
209 else if (token == "great") token = ">";
210 else if (token == "equ") token = "==";
211 else if (token == "neq") token = "!=";
212 else if (token == "lessequ") token = "<=";
213 else if (token == "greatequ") token = ">=";
214 for (int f = 0; opers[prio][f]; f++) {
215 if (!strcmp(opers[prio][f], token.CStr())) { myOp = true; break; }
217 //fprintf(stderr, "tk: [%s]; %s\n", token.CStr(), myOp?"MY":"skip");
218 if (!myOp) break;
219 opc = token;
220 readWordIntr(token, true);
221 op1 = readCondition(token, prio-1, skipIt);
222 //fprintf(stderr, " prio: %d; opc=[%s]; res=[%s]; op1=[%s]\n", prio, opc.CStr(), res.CStr(), op1.CStr());
223 switch (prio) {
224 case 2: // comparisons
225 if (opc == "==") {
226 if (!skipIt) res = res==op1 ? "tan" : "";
227 } else if (opc == "!=") {
228 if (!skipIt) res = res!=op1 ? "tan" : "";
229 } else if (opc == "<") {
230 if (!skipIt) res = res<op1 ? "tan" : "";
231 } else if (opc == ">") {
232 if (!skipIt) res = res>op1 ? "tan" : "";
233 } else if (opc == "<=") {
234 if (!skipIt) res = res<=op1 ? "tan" : "";
235 } else if (opc == ">=") {
236 if (!skipIt) res = res>=op1 ? "tan" : "";
238 break;
239 case 3: // &&
240 if (opc == "&&") {
241 if (!skipIt) {
242 res = res!=""&&op1!="" ? "tan" : "";
243 if (res == "") skipIt = true;
246 break;
247 case 4: // ||
248 if (opc == "||") {
249 if (!skipIt) {
250 res = res!=""||op1!="" ? "tan" : "";
251 if (res != "") skipIt = true;
254 break;
255 default:
256 die("invalid priority");
259 done:
260 //fprintf(stderr, "OUT: prio: %d; skip: %s; [%s]\n", prio, skipIt?"t":"o", token.CStr());
261 return res;
265 // stack top:
266 // 1: processing 'then'
267 // 2: processing 'else'
268 // -1: skiping 'then'
269 // -2: skiping 'else'
270 // -3: skiping whole 'if', 'then' part
271 // -4: skiping whole 'if', 'else' part
272 // -666: skiping '{}'
273 // 666: in '{}', processing
274 void inputfile::ReadWord (festring &str, truth AbortOnEOF, truth skipIt) {
275 int prc;
276 for (;;) {
277 if (!mIfStack.empty()) prc = mIfStack.top(); else prc = 0;
278 readWordIntr(str, AbortOnEOF);
279 if (str == "if") {
280 readWordIntr(str, true);
281 festring res = readCondition(str, maxCPrio, prc<0);
282 if (str != ";") die("';' expected");
283 if (prc < 0) {
284 // skiping
285 mIfStack.push(-3);
286 } else {
287 mIfStack.push(res!="" ? 1 : -1);
289 continue;
291 if (str == "else") {
292 switch (prc) {
293 case 1: // processing 'then'
294 mIfStack.pop();
295 mIfStack.push(-2);
296 break;
297 case -1: // skiping 'then'
298 mIfStack.pop();
299 mIfStack.push(2);
300 break;
301 case -3: // skiping whole, 'then'
302 mIfStack.pop();
303 mIfStack.push(-4);
304 break;
305 default: die("unexpected 'else'");
307 continue;
309 if (str == "endif") {
310 switch (prc) {
311 case 1: // processing 'then'
312 case 2: // processing 'else'
313 case -1: // skiping 'then'
314 case -2: // skiping 'else'
315 case -3: // skiping whole, 'then'
316 case -4: // skiping whole, 'else'
317 mIfStack.pop();
318 break;
319 default: die("unexpected 'endif'");
321 continue;
323 if (str == "{") {
324 mIfStack.push(prc>=0 ? 666 : -666);
325 if (prc >= 0) return;
326 continue;
328 if (str == "}") {
329 if (abs(prc) != 666) die("unexpected '}'");
330 mIfStack.pop();
331 if (prc >= 0) return;
332 continue;
334 if (prc >= 0) return;
339 festring inputfile::ReadWord (truth AbortOnEOF) {
340 festring ToReturn;
341 ReadWord(ToReturn, AbortOnEOF);
342 return ToReturn;
346 void inputfile::SkipSpaces () {
347 while (!feof(Buffer)) {
348 int ch = fgetc(Buffer);
349 if (ch == EOF) break;
350 if ((unsigned char)ch > ' ') {
351 ungetc(ch, Buffer);
352 break;
358 #define MODE_WORD 1
359 #define MODE_NUMBER 2
361 #define PUNCT_RETURN 0
362 #define PUNCT_CONTINUE 1
364 int inputfile::HandlePunct (festring &String, int Char, int Mode) {
365 if (Char == '/') {
366 // comment? (can be nested)
367 if (!feof(Buffer)) {
368 Char = fgetc(Buffer);
369 if (Char == '*') {
370 sLong StartPos = TellPos();
371 int OldChar = 0, CommentLevel = 1;
372 for (;;) {
373 if (feof(Buffer)) ABORT("Unterminated comment in file %s, beginning at line %d!", FileName.CStr(), TellLineOfPos(StartPos));
374 Char = fgetc(Buffer);
375 if (OldChar != '*' || Char != '/') {
376 if (OldChar != '/' || Char != '*') OldChar = Char;
377 else {
378 ++CommentLevel;
379 OldChar = 0;
381 } else {
382 if (!--CommentLevel) break;
383 OldChar = 0;
386 return PUNCT_CONTINUE;
388 if (Char == '/') {
389 // comment (to eol)
390 while (!feof(Buffer)) {
391 int ch = fgetc(Buffer);
392 if (ch == '\n') break;
394 return PUNCT_CONTINUE;
396 ungetc(Char, Buffer);
397 clearerr(Buffer);
399 if (Mode) ungetc('/', Buffer); else String << '/';
400 return PUNCT_RETURN;
403 if (Mode) {
404 ungetc(Char, Buffer);
405 return PUNCT_RETURN;
408 if (Char == '"') {
409 // string
410 lastWordWasString = true;
411 sLong StartPos = TellPos();
412 for (;;) {
413 if (feof(Buffer)) ABORT("Unterminated string in file %s, beginning at line %d!", FileName.CStr(), TellLineOfPos(StartPos));
414 Char = fgetc(Buffer);
415 if (Char == '\\') {
416 Char = fgetc(Buffer);
417 if (Char == EOF) ABORT("Unterminated string in file %s, beginning at line %d!", FileName.CStr(), TellLineOfPos(StartPos));
418 switch (Char) {
419 case 't': String << '\t'; break;
420 case 'n': String << '\n'; break;
421 case 'r': String << '\r'; break;
422 case '"': String << '"'; break;
423 default:
424 ABORT("Invalid escape in string in file %s at line %d!", FileName.CStr(), TellLine());
426 } else if (Char == '"') {
427 return PUNCT_RETURN;
428 } else {
429 String << char(Char);
432 if (Char != '"') {
433 String << char(Char);
434 OldChar = Char;
435 } else if (OldChar == '\\') {
436 String[String.GetSize()-1] = '"';
437 OldChar = 0;
438 } else return PUNCT_RETURN;
442 String << char(Char);
443 if (!feof(Buffer)) {
444 if (Char == '=' || Char == '<' || Char == '>' || Char == '!') {
445 Char = fgetc(Buffer);
446 if (Char == '=') String << char(Char); else ungetc(Char, Buffer);
447 } else if (Char == '&' || Char == '|') {
448 int ch = fgetc(Buffer);
449 if (Char == ch) String << char(ch); else ungetc(ch, Buffer);
452 return PUNCT_RETURN;
456 void inputfile::readWordIntr (festring &String, truth AbortOnEOF) {
457 int Mode = 0;
458 String.Empty();
459 lastWordWasString = false;
460 for (int Char = fgetc(Buffer); !feof(Buffer); Char = fgetc(Buffer)) {
461 if (isalpha(Char) || Char == '_') {
462 if (!Mode) Mode = MODE_WORD;
463 else if (Mode == MODE_NUMBER) {
464 ungetc(Char, Buffer);
465 return;
467 String << char(Char);
468 continue;
470 if (isdigit(Char)) {
471 if (!Mode) Mode = MODE_NUMBER;
472 else if (Mode == MODE_WORD) {
473 ungetc(Char, Buffer);
474 return;
476 String << char(Char);
477 continue;
479 if ((Char == ' ' || Char == '\n' || Char == '\r' || Char == '\t') && Mode) return;
480 if (ispunct(Char) && HandlePunct(String, Char, Mode) == PUNCT_RETURN) return;
482 if (AbortOnEOF) ABORT("Unexpected end of file %s!", FileName.CStr());
483 if (Mode) clearerr(Buffer);
487 char inputfile::ReadLetter (truth AbortOnEOF) {
488 for (int Char = fgetc(Buffer); !feof(Buffer); Char = fgetc(Buffer)) {
489 if (isalpha(Char) || isdigit(Char)) return Char;
490 if (ispunct(Char)) {
491 if (Char == '/') {
492 if (!feof(Buffer)) {
493 Char = fgetc(Buffer);
494 if (Char == '*') {
495 sLong StartPos = TellPos();
496 int OldChar = 0, CommentLevel = 1;
497 for (;;) {
498 if (feof(Buffer)) ABORT("Unterminated comment in file %s, beginning at line %d!", FileName.CStr(), TellLineOfPos(StartPos));
499 Char = fgetc(Buffer);
500 if (OldChar != '*' || Char != '/') {
501 if (OldChar != '/' || Char != '*') OldChar = Char;
502 else {
503 ++CommentLevel;
504 OldChar = 0;
506 } else {
507 if (!--CommentLevel) break;
508 OldChar = 0;
511 continue;
512 } else {
513 ungetc(Char, Buffer);
516 return '/';
518 return Char;
521 if (AbortOnEOF) ABORT("Unexpected end of file %s!", FileName.CStr());
522 return 0;
526 /* Reads a number or a formula from inputfile. Valid values could be for
527 instance "3", "5 * 4+5", "2+Variable%4" etc. */
528 //sLong inputfile::ReadNumber (int CallLevel, truth PreserveTerminator) {
529 festring inputfile::ReadNumberIntr (int CallLevel, sLong *num, truth *isString, truth allowStr, truth PreserveTerminator) {
530 sLong Value = 0;
531 festring Word;
532 truth NumberCorrect = false;
533 truth firstWord = true;
534 *isString = false;
535 *num = 0;
536 festring res;
537 for (;;) {
538 ReadWord(Word);
539 if (Word == "@") {
540 // variable
541 ReadWord(Word, true);
542 //fprintf(stderr, "var: [%s]\n", Word.CStr());
543 Word = getVar(Word);
544 //fprintf(stderr, " value: [%s]\n", Word.CStr());
545 const char *s = Word.CStr();
546 char *e;
547 sLong l = strtoll(s, &e, 10);
548 if (*e == '\0') {
549 //fprintf(stderr, " number: [%d]\n", l);
550 Value = l;
551 NumberCorrect = true;
552 continue;
554 if (firstWord && allowStr) {
555 *isString = true;
556 return Word;
557 } else {
558 ABORT("Number expected in file %s, line %d!", FileName.CStr(), TellLine());
561 if (firstWord) {
562 if (allowStr && lastWordWasString) {
563 *isString = true;
564 ReadWord(res);
565 if (res.GetSize() == 1) {
566 if (res[0] != ';' && res[0] != ',' && res[0] != ':') {
567 ABORT("Invalid terminator in file %s, line %d!", FileName.CStr(), TellLine());
569 if (PreserveTerminator) ungetc(res[0], Buffer);
570 } else {
571 ABORT("Terminator expected in file %s, line %d!", FileName.CStr(), TellLine());
573 return Word;
575 firstWord = false;
577 char First = Word[0];
578 if (isdigit(First)) {
579 Value = atoi(Word.CStr());
580 NumberCorrect = true;
581 continue;
583 if (Word.GetSize() == 1) {
584 if (First == ';' || First == ',' || First == ':') {
585 if (CallLevel != HIGHEST || PreserveTerminator) ungetc(First, Buffer);
586 *num = Value;
587 return res;
589 if (First == ')') {
590 if ((CallLevel != HIGHEST && CallLevel != 4) || PreserveTerminator) ungetc(')', Buffer);
591 *num = Value;
592 return res;
594 if (First == '~') {
595 Value = ~ReadNumber(4);
596 NumberCorrect = true;
597 continue;
599 /* Convert this into an inline function! */
600 #define CHECK_OP(op, cl) \
601 if (First == #op[0]) { \
602 if (cl < CallLevel) {\
603 Value op##= ReadNumber(cl);\
604 NumberCorrect = true;\
605 continue;\
606 } else {\
607 ungetc(#op[0], Buffer);\
608 *num = Value;\
609 return res;\
612 CHECK_OP(&, 1); CHECK_OP(|, 1); CHECK_OP(^, 1);
613 CHECK_OP(*, 2); CHECK_OP(/, 2); CHECK_OP(%, 2);
614 CHECK_OP(+, 3); CHECK_OP(-, 3);
615 if (First == '<') {
616 char Next = Get();
617 if (Next == '<')
618 if (1 < CallLevel) {
619 Value <<= ReadNumber(1);
620 NumberCorrect = true;
621 continue;
622 } else {
623 ungetc('<', Buffer);
624 ungetc('<', Buffer);
625 *num = Value;
626 return res;
627 } else {
628 ungetc(Next, Buffer);
631 if (First == '>') {
632 char Next = Get();
633 if (Next == '>')
634 if (1 < CallLevel) {
635 Value >>= ReadNumber(1);
636 NumberCorrect = true;
637 continue;
638 } else {
639 ungetc('>', Buffer);
640 ungetc('>', Buffer);
641 *num = Value;
642 return res;
643 } else {
644 ungetc(Next, Buffer);
647 if (First == '(') {
648 if (NumberCorrect) {
649 ungetc('(', Buffer);
650 *num = Value;
651 return res;
652 } else {
653 Value = ReadNumber(4);
654 NumberCorrect = false;
655 continue;
658 if (First == '=' && CallLevel == HIGHEST) continue;
659 if (First == '#') {
660 // for #defines
661 ungetc('#', Buffer);
662 *num = Value;
663 return res;
667 if (Word == "enum" || Word == "bitenum") {
668 if (CallLevel != HIGHEST || PreserveTerminator) ungetc(';', Buffer);
669 *num = Value;
670 return res;
673 if (Word == "rgb") {
674 int Bits = ReadNumber();
675 if (Bits == 16) {
676 int Red = ReadNumber();
677 int Green = ReadNumber();
678 int Blue = ReadNumber();
679 Value = MakeRGB16(Red, Green, Blue);
680 } else if (Bits == 24) {
681 int Red = ReadNumber();
682 int Green = ReadNumber();
683 int Blue = ReadNumber();
684 Value = MakeRGB24(Red, Green, Blue);
685 } else {
686 ABORT("Illegal RGB bit size %d in file %s, line %d!", Bits, FileName.CStr(), TellLine());
688 NumberCorrect = true;
689 continue;
691 if (Word == "true" || Word == "tan") {
692 Value = 1;
693 NumberCorrect = true;
694 continue;
696 if (Word == "false" || Word == "ona") {
697 Value = 0;
698 NumberCorrect = true;
699 continue;
701 if (ValueMap) {
702 valuemap::const_iterator Iterator = ValueMap->find(Word);
703 if (Iterator != ValueMap->end()) {
704 Value = Iterator->second;
705 NumberCorrect = true;
706 continue;
709 ABORT("Odd numeric value \"%s\" encountered in file %s, line %d!",
710 Word.CStr(), FileName.CStr(), TellLine());
715 festring inputfile::ReadCode (truth AbortOnEOF) {
716 int sqLevel = 1;
717 char inString = 0;
718 festring res;
720 for (char Char = fgetc(Buffer); !feof(Buffer); Char = fgetc(Buffer)) {
721 //fprintf(stderr, "char: [%c]; inString: %d; sqLevel: %d\n", (Char < 32 || Char > 126 ? '?' : Char), inString, sqLevel);
722 if (inString) {
723 res << Char;
724 if (Char == inString) {
725 inString = 0;
726 } else if (Char == '\\') {
727 if (feof(Buffer)) break;
728 Char = fgetc(Buffer);
729 res << Char;
731 } else {
732 if (Char == '[') {
733 ++sqLevel;
734 res << Char;
735 } else if (Char == ']') {
736 if (--sqLevel == 0) break;
737 res << Char;
738 } else if (Char == '/') {
739 if (feof(Buffer)) { res << Char; break; }
740 switch ((Char = fgetc(Buffer))) {
741 case '/': // eol comment
742 while (!feof(Buffer)) if (fgetc(Buffer) == '\n') break;
743 break;
744 case '*': // c-like comment
745 while (!feof(Buffer)) {
746 if (fgetc(Buffer) == '*') {
747 if (feof(Buffer)) break;
748 if (fgetc(Buffer) == '/') break;
751 break;
752 default:
753 res << '/';
754 res << Char;
755 break;
757 } else if (Char == '"' || Char == '\'') {
758 res << Char;
759 inString = Char;
760 } else {
761 res << Char;
765 if (AbortOnEOF && feof(Buffer)) ABORT("Unexpected end of file %s!", FileName.CStr());
766 return res;
770 sLong inputfile::ReadNumber (int CallLevel, truth PreserveTerminator) {
771 sLong num = 0;
772 truth isString = false;
773 ReadNumberIntr(CallLevel, &num, &isString, false, PreserveTerminator);
774 return num;
778 festring inputfile::ReadStringOrNumber (sLong *num, truth *isString, truth PreserveTerminator) {
779 return ReadNumberIntr(0xFF, num, isString, true, PreserveTerminator);
783 v2 inputfile::ReadVector2d () {
784 v2 Vector;
785 Vector.X = ReadNumber();
786 Vector.Y = ReadNumber();
787 return Vector;
791 rect inputfile::ReadRect () {
792 rect Rect;
793 Rect.X1 = ReadNumber();
794 Rect.Y1 = ReadNumber();
795 Rect.X2 = ReadNumber();
796 Rect.Y2 = ReadNumber();
797 return Rect;
801 outputfile &operator << (outputfile &SaveFile, cfestring &String) {
802 uShort Length = String.GetSize();
803 SaveFile << Length;
804 if (Length) SaveFile.Write(String.CStr(), Length);
805 return SaveFile;
809 inputfile &operator >> (inputfile &SaveFile, festring &String) {
810 char *RealBuffer, StackBuffer[1024];
811 uShort Length;
812 SaveFile >> Length;
813 RealBuffer = Length < 1024 ? StackBuffer : new char[Length+1];
814 String.Empty();
815 if (Length) {
816 SaveFile.Read(RealBuffer, Length);
817 RealBuffer[Length] = 0;
818 String << RealBuffer;
820 if (Length >= 1024) delete [] RealBuffer;
821 return SaveFile;
825 outputfile &operator << (outputfile &SaveFile, cchar *String) {
826 uShort Length = String ? strlen(String) : 0;
827 SaveFile << Length;
828 if (Length) SaveFile.Write(String, Length);
829 return SaveFile;
833 inputfile &operator >> (inputfile &SaveFile, char *&String) {
834 uShort Length;
835 SaveFile >> Length;
836 if (Length) {
837 String = new char[Length+1];
838 SaveFile.Read(String, Length);
839 String[Length] = 0;
840 } else {
841 String = 0;
843 return SaveFile;
847 void ReadData (festring &String, inputfile &SaveFile) {
848 SaveFile.ReadWord(String);
849 if (String == "=") SaveFile.ReadWord(String);
850 SaveFile.ReadWord();
854 void ReadData (fearray<sLong> &Array, inputfile &SaveFile) {
855 Array.Clear();
856 festring Word;
857 SaveFile.ReadWord(Word);
858 //if (Word == "=") SaveFile.ReadWord(Word);
859 if (Word == "==") {
860 Array.Allocate(1);
861 Array.Data[0] = SaveFile.ReadNumber();
862 return;
864 if (Word != "=") ABORT("Array syntax error: '=' or '==' expected in file %s, line %d!", SaveFile.GetFileName().CStr(), SaveFile.TellLine());
865 SaveFile.ReadWord(Word);
866 if (Word != "{") ABORT("Array syntax error \"%s\" found in file %s, line %d!", Word.CStr(), SaveFile.GetFileName().CStr(), SaveFile.TellLine());
867 fearray<sLong>::sizetype Size = SaveFile.ReadNumber();
868 Array.Allocate(Size);
869 for (fearray<sLong>::sizetype c = 0; c < Size; ++c) Array.Data[c] = SaveFile.ReadNumber();
870 if (SaveFile.ReadWord() != "}") ABORT("Illegal array terminator \"%s\" encountered in file %s, line %d!", Word.CStr(), SaveFile.GetFileName().CStr(), SaveFile.TellLine());
874 void ReadData (fearray<festring> &Array, inputfile &SaveFile) {
875 Array.Clear();
876 festring Word;
877 SaveFile.ReadWord(Word);
878 //if (Word == "=") SaveFile.ReadWord(Word);
879 if (Word == "==") {
880 Array.Allocate(1);
881 SaveFile.ReadWord(Array.Data[0]);
882 if (SaveFile.ReadWord() != ";") ABORT("Array syntax error \"%s\" found in file %s, line %d!", Word.CStr(), SaveFile.GetFileName().CStr(), SaveFile.TellLine());
883 return;
885 if (Word != "=") ABORT("Array syntax error: '=' or '==' expected in file %s, line %d!", SaveFile.GetFileName().CStr(), SaveFile.TellLine());
886 SaveFile.ReadWord(Word);
887 if (Word != "{") ABORT("Array syntax error \"%s\" found in file %s, line %d!", Word.CStr(), SaveFile.GetFileName().CStr(), SaveFile.TellLine());
888 fearray<festring>::sizetype Size = SaveFile.ReadNumber();
889 Array.Allocate(Size);
890 for (fearray<festring>::sizetype c = 0; c < Size; ++c) {
891 SaveFile.ReadWord(Array.Data[c]);
892 SaveFile.ReadWord(Word);
893 if (Word != "," && Word != ";") ABORT("Array syntax error \"%s\" found in file %s, line %d!", Word.CStr(), SaveFile.GetFileName().CStr(), SaveFile.TellLine());
895 if (SaveFile.ReadWord() != "}") ABORT("Illegal array terminator \"%s\" encountered in file %s, line %d!", Word.CStr(), SaveFile.GetFileName().CStr(), SaveFile.TellLine());
899 uLong inputfile::TellLineOfPos (sLong Pos) {
900 uLong Line = 1;
901 sLong BackupPos = TellPos();
902 SeekPosBegin(0);
903 while (TellPos() != Pos) { if (fgetc(Buffer) == '\n') ++Line; }
904 if (TellPos() != BackupPos) SeekPosBegin(BackupPos);
905 return Line;
909 meminputfile::meminputfile (cfestring &str, const valuemap *ValueMap) :
910 inputfile("", ValueMap, false)
912 if (Buffer) fclose(Buffer);
913 #ifdef WIN32
914 char nbuf[MAX_PATH+1], tfn[MAX_PATH+1];
915 GetTempPath(MAX_PATH, nbuf);
916 GetTempFileName(nbuf, "ivan", 0, tfn);
917 tfname = tfn;
918 FILE *fl = fopen(tfn, "wb");
919 fwrite(str.CStr(), str.GetSize(), 1, fl);
920 fclose(fl);
921 Buffer = fopen(tfn, "rb");
922 #else
923 bufSize = str.GetSize();
924 buf = malloc(bufSize+1);
925 memmove(buf, str.CStr(), bufSize);
926 Buffer = fmemopen(buf, bufSize, "rb");
927 #endif
928 FileName = "<memory>";
931 meminputfile::~meminputfile () {
932 if (buf) free(buf);
933 #ifdef WIN32
934 if (Buffer) fclose(Buffer);
935 unlink(tfname.CStr());
936 #endif