1 /***************************************************************************
2                           datendatei.cpp  -  description
3                              -------------------
4     begin                : Sun Jul 1 2001
5     copyright            : (C) 2001 by Immi
6     email                : cuyo@karimmi.de
7 
8 Modified 2002,2005,2006,2010,2011,2014 by the cuyo developers
9 
10  ***************************************************************************/
11 
12 /***************************************************************************
13  *                                                                         *
14  *   This program is free software; you can redistribute it and/or modify  *
15  *   it under the terms of the GNU General Public License as published by  *
16  *   the Free Software Foundation; either version 2 of the License, or     *
17  *   (at your option) any later version.                                   *
18  *                                                                         *
19  ***************************************************************************/
20 
21 #include "cuyointl.h"
22 
23 #include "datendatei.h"
24 #include "knoten.h"
25 
26 
27 /** In parser.yy definiert. */
28 void parse(const Str & name, DefKnoten * erg);
29 
30 
DatenDatei()31 DatenDatei::DatenDatei():
32   mDaten(new DefKnoten()) /* Leerer Knoten ohne Vater */
33 {
34   /* Das Squirrel sitzt am Anfang ganz oben */
35   initSquirrel();
36 }
37 
~DatenDatei()38 DatenDatei::~DatenDatei() {
39   delete mDaten;
40 }
41 
42 
43 
44 
45 /** Entfernt alles, was bisher geladen wurde. Aufrufen, wenn man alles
46     neu laden m�chte. */
leeren()47 void DatenDatei::leeren() {
48   delete mDaten;
49   mDaten = new DefKnoten();
50 
51   /* Squirrel neu setzen. (Sonst stimmt der Pointer nicht mehr.) */
52   initSquirrel();
53 }
54 
55 
56 
57 /** L�dt die angegebene Datei. (Kann mehrmals aufgerufen werden, um
58     mehrere Dateien gleichzeitig zu laden.) */
laden(const Str & name)59 void DatenDatei::laden(const Str & name) {
60   parse(name, mDaten);
61 }
62 
63 
64 
65 
66 
67 
68 /***** Squirrel-Methoden *****/
69 
70 
71 /** Setzt das Squirrel an die Wurzel des Baums. */
initSquirrel()72 void DatenDatei::initSquirrel() {
73   mSquirrelPosString = "";
74   mSquirrelKnoten = mDaten;
75   mSquirrelCodeKnoten = mDaten;
76 }
77 
78 
79 /** Liefert true, wenn das Squirrel sich an einer Stelle des Baums
80     befindet, die existiert. */
existiertSquirrelKnoten() const81 bool DatenDatei::existiertSquirrelKnoten() const {
82   return mSquirrelKnoten;
83 }
84 
85 
86 /** Liefert die Position des Squirrels als String. */
getSquirrelPosString() const87 Str DatenDatei::getSquirrelPosString() const {
88   return mSquirrelPosString;
89 }
90 
91 
92 /** Das Eichh�rnchen klettert weiter weg von der Wurzel. Wird von
93     DatenDateiPush benutzt. */
kletterWeiter(const Str & na,const Version & version)94 void DatenDatei::kletterWeiter(const Str & na, const Version & version) {
95 
96   /* Neuen Abschnittnamen bauen */
97   if (!mSquirrelPosString.isEmpty())
98     mSquirrelPosString += '/';
99   mSquirrelPosString += na;
100 
101   /* Knoten zum neuen Abschnitt suchen */
102   mSquirrelKnoten = (DefKnoten *) getEintragKnoten(na, version, true,
103 						   type_DefKnoten);
104 
105   /* Wenn dieser Unterabschnitt existiert, dann auch die Codeen
106      dort suchen. */
107   if (mSquirrelKnoten)
108     mSquirrelCodeKnoten = mSquirrelKnoten;
109 }
110 
111 
112 
113 /** Liefert die Squirrel-Position zur�ck (und zwar
114     mSquirrelCodeKnoten; siehe dort). */
getSquirrelPos() const115 DefKnoten * DatenDatei::getSquirrelPos() const {
116   return mSquirrelCodeKnoten;
117 }
118 
119 
120 
121 /***** Eintrag-Methoden *****/
122 
123 
124 
125 
126 /** Liefert den angegebenen Eintrag beim Squirrel.
127     Pr�ft, ob der Typ der gew�nschte ist.
128     Liefert 0, wenn's den Eintrag nicht gibt, aber defaultVorhanden.
129     Throwt bei sonstigem Fehler. */
getEintragKnoten(const Str & schluessel,const Version & version,bool defaultVorhanden,int typ) const130 Knoten * DatenDatei::getEintragKnoten(const Str & schluessel,
131 				      const Version & version,
132 				      bool defaultVorhanden, int typ) const {
133 
134   if (!mSquirrelKnoten) {
135     if (defaultVorhanden)
136       return 0;
137     else throw Fehler("%s required but not defined",schluessel.data());
138   }
139 
140   Knoten * ret = mSquirrelKnoten->getKind(schluessel,version,
141 					  defaultVorhanden);
142 
143   if (ret)
144     if (typ != type_egal && ret->type() != typ)
145       throw Fehler("Wrong type on the righthand side of %s%s=",
146                    schluessel.data(), version.toString().data());
147 
148   return ret;
149 }
150 
151 
152 
153 
154 /** Gibt's den Eintrag? */
hatEintrag(const Str & schluessel) const155 bool DatenDatei::hatEintrag(const Str & schluessel) const {
156   return mSquirrelKnoten->enthaelt(schluessel);
157 }
158 
159 /** Liefert den Eintrag, wenn er existiert, sonst null, wenn
160     defaultVorhanden, sonst wird gethrowt. */
getEintrag(const Str & schluessel,const Version & version,bool defaultVorhanden,int typ) const161 const DatenKnoten * DatenDatei::getEintrag(const Str & schluessel,
162 					   const Version & version,
163 					   bool defaultVorhanden,
164 					   int typ
165 					   /*= type_EgalDatum*/) const {
166   Knoten * e = getEintragKnoten(schluessel, version, defaultVorhanden,
167 				type_ListenKnoten);
168   if (e)
169     return ((ListenKnoten *) e)->getDatum(0)->assert_datatype(typ);
170   else
171     return 0;
172 }
173 
174 /** Dito f�r W�rter. Default f�r def ist "". */
getWortEintragOhneDefault(const Str & schluessel,const Version & version) const175 Str DatenDatei::getWortEintragOhneDefault(const Str & schluessel,
176 					       const Version & version) const {
177   return getEintrag(schluessel,version,false,type_WortDatum)->getWort();
178 }
179 
getWortEintragMitDefault(const Str & schluessel,const Version & version,Str def) const180 Str DatenDatei::getWortEintragMitDefault(const Str & schluessel,
181 					      const Version & version,
182 					      Str def /*= Str()*/) const {
183   const DatenKnoten * e = getEintrag(schluessel,version,true,type_WortDatum);
184   if (e)
185     return e->getWort();
186   else
187     return def;
188 }
189 
190 /** Liefert den Eintrag als Zahl. */
getZahlEintragOhneDefault(const Str & schluessel,const Version & version) const191 int DatenDatei::getZahlEintragOhneDefault(const Str & schluessel,
192 					  const Version & version) const {
193   return getEintrag(schluessel,version,false,type_ZahlDatum)->getZahl(0);
194 }
195 
getZahlEintragMitDefault(const Str & schluessel,const Version & version,int def) const196 int DatenDatei::getZahlEintragMitDefault(const Str & schluessel,
197 					 const Version & version,
198 					 int def /*= 0*/) const {
199   const DatenKnoten * e = getEintrag(schluessel,version,true,type_ZahlDatum);
200   if (e) {
201     return e->getZahl(0);
202   } else
203     return def;
204 }
205 
intZuBool(int i)206 bool intZuBool(int i) {
207   switch (i) {
208   case 0: return false;
209   case 1: return true;
210   default: throw Fehler("0 or 1 expected, got %d.",i);
211   }
212 }
213 
getBoolEintragOhneDefault(const Str & schluessel,const Version & version) const214 bool DatenDatei::getBoolEintragOhneDefault(const Str & schluessel,
215 					   const Version & version) const {
216   return intZuBool(getZahlEintragOhneDefault(schluessel,version));
217 }
218 
219 
getBoolEintragMitDefault(const Str & schluessel,const Version & version,bool def) const220 bool DatenDatei::getBoolEintragMitDefault(const Str & schluessel,
221 					  const Version & version,
222 					  bool def) const {
223   return intZuBool(getZahlEintragMitDefault(schluessel,version,(def ? 1 : 0)));
224 }
225 
226 
227 /** Liefert den Eintrag als Farbe. */
getFarbEintragOhneDefault(const Str & schluessel,const Version & version) const228 Color DatenDatei::getFarbEintragOhneDefault(const Str & schluessel,
229 					    const Version & version) const {
230   ListenKnoten * e = getListenEintrag(schluessel,version,false);
231   if (e->getLaenge() != 3)
232     throw Fehler("%s","Color (r,g,b) expected");
233 
234   return Color(e->getDatum(0)->assert_datatype(type_ZahlDatum)->getZahl(),
235 		e->getDatum(1)->assert_datatype(type_ZahlDatum)->getZahl(),
236 		e->getDatum(2)->assert_datatype(type_ZahlDatum)->getZahl());
237 }
238 
getFarbEintragMitDefault(const Str & schluessel,const Version & version,const Color & def) const239 Color DatenDatei::getFarbEintragMitDefault(const Str & schluessel,
240 				  const Version & version,
241 				  const Color & def /*= black*/) const {
242   ListenKnoten * e = getListenEintrag(schluessel,version,true);
243 
244   if (e == 0) return def;
245 
246   if (e->getLaenge() != 3)
247     throw Fehler("%s","Color (r,g,b) expected");
248 
249   return Color(e->getDatum(0)->assert_datatype(type_ZahlDatum)->getZahl(),
250 		e->getDatum(1)->assert_datatype(type_ZahlDatum)->getZahl(),
251 		e->getDatum(2)->assert_datatype(type_ZahlDatum)->getZahl());
252 }
253 
254 /** Liefert einen Eintrag als Knoten */
getListenEintrag(const Str & schluessel,const Version & version,bool defaultVorhanden) const255 ListenKnoten * DatenDatei::getListenEintrag(const Str & schluessel,
256 					    const Version & version,
257 					    bool defaultVorhanden) const {
258   Knoten * e = getEintragKnoten(schluessel, version, defaultVorhanden,
259 				type_ListenKnoten);
260   if (e) {
261     /* Fr�her freute sich der Aufrufer dar�ber, da� er wusste, da� die
262        Liste nur W�rter enth�lt. Es k�nnten noch Probleme existieren */
263     ListenKnoten * ret = (ListenKnoten*) e;
264     for (int i = 0; i < ret->getLaenge(); i++)
265       if (ret->getKind(i)->type() != type_DatenKnoten)
266         throw Fehler("%s","List of atomic data expected");
267     return ret;
268   } else
269     return 0;
270 }
271 
272 
273 
274 /** Sucht einen Code beim Squirrel oder n�her an der Wurzel.
275     Beh�lt den Besitz am Code/an der VarDefinition.
276     Throwt bei nicht-existenz. */
getCode(const Str & name,const Version & version,bool defaultVorhanden)277 Code * DatenDatei::getCode(const Str & name,
278 			   const Version & version, bool defaultVorhanden) {
279 
280   /* Einen Codeabschnitt sollte es eigentlich immer geben - zumindest
281      wenn die Datei auf ist. Aber die sollte immer auf sein. */
282   CASSERT(mSquirrelCodeKnoten);
283 
284   return (Code *) mSquirrelCodeKnoten->getDefinition(namespace_prozedur,
285 						     name, version,
286 						     defaultVorhanden);
287 }
288 
getVarDef(const Str & name,const Version & version,bool defaultVorhanden)289 VarDefinition * DatenDatei::getVarDef(const Str & name,
290 				      const Version & version,
291 				      bool defaultVorhanden) {
292 
293   /* Einen Codeabschnitt sollte es eigentlich immer geben - zumindest
294      wenn die Datei auf ist. Aber die sollte immer auf sein. */
295   CASSERT(mSquirrelCodeKnoten);
296 
297   return (VarDefinition *) mSquirrelCodeKnoten->getDefinition(
298       namespace_variable, name, version, defaultVorhanden);
299 }
300 
301 
302 
303 
304 
305 /***************************************************************************/
306 
307 
308 
309 
310 
DatenDateiPush(DatenDatei & c,const Str & name,const Version & version,bool verlange)311 DatenDateiPush::DatenDateiPush(DatenDatei & c,
312 			       const Str & name, const Version & version,
313                                bool verlange /*= true*/): mConf(c) {
314   mMerkName = mConf.mSquirrelPosString;
315   mMerkKnoten = mConf.mSquirrelKnoten;
316   mMerkCodeKnoten = mConf.mSquirrelCodeKnoten;
317   mConf.kletterWeiter(name,version);
318   if (verlange && !mConf.existiertSquirrelKnoten())
319     throw Fehler("Section %s does not exist.",
320                  mConf.getSquirrelPosString().data());
321 }
322 
~DatenDateiPush()323 DatenDateiPush::~DatenDateiPush() {
324   mConf.mSquirrelPosString = mMerkName;
325   mConf.mSquirrelKnoten = mMerkKnoten;
326   mConf.mSquirrelCodeKnoten = mMerkCodeKnoten;
327 }
328 
329 
330