Qucs-core  0.0.19
check_mdl.cpp
Go to the documentation of this file.
00001 /*
00002  * check_mdl.cpp - iterate an IC-CAP MDL file
00003  *
00004  * Copyright (C) 2006, 2007 Stefan Jahn <stefan@lkcc.org>
00005  *
00006  * This is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2, or (at your option)
00009  * any later version.
00010  *
00011  * This software is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this package; see the file COPYING.  If not, write to
00018  * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
00019  * Boston, MA 02110-1301, USA.
00020  *
00021  * $Id$
00022  *
00023  */
00024 
00025 #if HAVE_CONFIG_H
00026 # include <config.h>
00027 #endif
00028 
00029 #include <stdio.h>
00030 #include <stdlib.h>
00031 #include <string.h>
00032 #include <cmath>
00033 #include <assert.h>
00034 #include <float.h>
00035 #include <ctype.h>
00036 
00037 #include "logging.h"
00038 #include "strlist.h"
00039 #include "object.h"
00040 #include "complex.h"
00041 #include "vector.h"
00042 #include "dataset.h"
00043 #include "sweep.h"
00044 #include "valuelist.h"
00045 #include "constants.h"
00046 #include "check_mdl.h"
00047 #include "tokens_mdl.h"
00048 
00049 using namespace qucs;
00050 
00051 // Global variables.
00052 dataset * mdl_result = NULL;
00053 struct mdl_link_t * mdl_root = NULL;
00054 struct mdl_sync_t * mdl_sync_root = NULL;
00055 
00056 // Creates an independent data vector.
00057 static void mdl_create_depdataset (sweep * data, char * name) {
00058   vector v (name);
00059   for (int i = 0; i < data->getSize (); i++) v.add (data->get (i));
00060   mdl_result->appendDependency (new vector (v));
00061 }
00062 
00063 // Creates an independent data vector with a single element.
00064 static void mdl_create_condataset (double val, char * name) {
00065   vector v (name);
00066   v.add (val);
00067   mdl_result->appendDependency (new vector (v));
00068 }
00069 
00070 // The functions creates dependent data vector(s).
00071 static void mdl_create_vardataset (struct mdl_point_t * point,
00072                                    struct mdl_datasize_t * dsize,
00073                                    const char * name, const char * type,
00074                                    strlist * deps) {
00075   vector * v = new vector[dsize->x * dsize->y] ();
00076   // adjust type
00077   if (!strcmp (type, "MEAS"))
00078     type = ".M";
00079   else if (!strcmp (type, "SIMU"))
00080     type = ".S";
00081   else if (!strcmp (type, "COMMON"))
00082     type = "";
00083   // create vectors
00084   for (struct mdl_point_t * p = point; p != NULL; p = p->next) {
00085     int n = (p->y - 1) * 2 + p->x - 1;
00086     v[n].add (nr_complex_t (p->r, p->i));
00087   }
00088   // go through indices
00089   for (int x = 1; x < dsize->x + 1; x++) {
00090     for (int y = 1; y < dsize->y + 1; y++) {
00091       // create vector description
00092       int n = (y - 1) * 2 + x - 1;
00093       char * txt = (char *) malloc (strlen (name) + strlen (type) + 4 + 2 * 3);
00094       if (dsize->x > 1 || dsize->y > 1)
00095         sprintf (txt, "%s%s[%d,%d]", name, type, x, y);
00096       else
00097         sprintf (txt, "%s%s", name, type);
00098       v[n].setName (txt);
00099       free (txt);
00100       // put vector into dataset
00101       if (v[n].getSize () > 1) {
00102         v[n].setDependencies (new strlist (*deps));
00103         mdl_result->appendVariable (new vector (v[n]));
00104       } else {
00105         v[n].setDependencies (new strlist ());
00106         mdl_result->appendDependency (new vector (v[n]));
00107       }
00108     }
00109   }
00110   delete[] v;
00111 }
00112 
00113 // Look through hypertable elements for a name and return value.
00114 static char * mdl_find_helement (struct mdl_element_t * root,
00115                                  const char * name) {
00116   for (; root != NULL; root = root->next) {
00117     if (!strcmp (root->name, name)) return root->value;
00118   }
00119   return NULL;
00120 }
00121 
00122 // Look through table elements for a name and return value.
00123 static char * mdl_find_telement (struct mdl_element_t * root,
00124                                  const char * name) {
00125   for (; root != NULL; root = root->next) {
00126     if (!strcmp (root->name, "Name") && !strcmp (root->value, name)) {
00127       if (root->next && !strcmp (root->next->name, "Value")) {
00128         return root->next->value;
00129       }
00130     }
00131   }
00132   return NULL;
00133 }
00134 
00135 // Convert number suffix into a multiplication factor.
00136 static double mdl_convert_factor (char * end) {
00137   double f = 1.0;
00138   if (end) {
00139     switch (*end) {
00140     case 'K': f = 1e+03; break;
00141     case 'M': f = 1e+06; break;
00142     case 'G': f = 1e+09; break;
00143     case 'T': f = 1e+12; break;
00144     case 'm': f = 1e-03; break;
00145     case 'u': f = 1e-06; break;
00146     case 'n': f = 1e-09; break;
00147     case 'p': f = 1e-12; break;
00148     case 'f': f = 1e-15; break;
00149     case 'a': f = 1e-18; break;
00150     }
00151   }
00152   return f;
00153 }
00154 
00155 // Forward declaration.
00156 static double mdl_telement_dvalue (struct mdl_link_t *, struct mdl_element_t *,
00157                                    const char *);
00158 
00159 // The function resolves the given variable trying upscope resolving.
00160 static int mdl_resolve_variable (struct mdl_link_t * link, char * name,
00161                                  double &val) {
00162   int done = 0;
00163   val = 0.0;
00164   struct mdl_lcontent_t * root;
00165   // try finding variable in current link
00166   for (root = link->content; !done && root != NULL; root = root->next) {
00167     if (root->type == t_TABLE) {
00168       struct mdl_element_t * eroot = root->table->data;
00169       if (mdl_find_telement (eroot, name)) {
00170         val = mdl_telement_dvalue (link, eroot, name);
00171         done++;
00172       }
00173     }
00174   }
00175   // resolve variable in upper scope recursively
00176   if (!done && link->parent) {
00177     done = mdl_resolve_variable (link->parent, name, val);
00178   }
00179   return done;
00180 }
00181 
00182 // Converts a string into a valid value.  Uses variable substitutions.
00183 static double mdl_variable_value (struct mdl_link_t * link, char * txt) {
00184   double val = 0.0;
00185   char * end = NULL;
00186   if (txt != NULL) {
00187     // remove whitespaces
00188     char * t, * p = txt;
00189     while (*p) {
00190       if (isspace (*p)) {
00191         t = p;
00192         while (*t) { *t = *(t + 1); t++; }
00193         p--;
00194       }
00195       p++;
00196     }
00197     // extract value if possible
00198     val = strtod (txt, &end);
00199     // not a value, a variable
00200     if (end == txt) {
00201       double f = 1.0;
00202       if      (*txt == '-') { f = -1.0; txt++; }
00203       else if (*txt == '+') { f = +1.0; txt++; }
00204       if (!mdl_resolve_variable (link, txt, val)) {
00205         // special variables
00206         if (!strcmp (txt, "PI")) {
00207           val = pi;
00208         }
00209         // no resolvable (probably equation)
00210         else {
00211           logprint (LOG_ERROR,
00212                     "checker error, unable to resolve `%s' variable in '%s'\n",
00213                     txt, link->name);
00214           val = 0.0;
00215         }
00216       }
00217       val = f * val;
00218     }
00219     // normal value with probably a suffix
00220     else {
00221       val *= mdl_convert_factor (end);
00222     }
00223   }
00224   return val;
00225 }
00226 
00227 // Returns a double variable value stored in a hypertable.
00228 static double mdl_helement_dvalue (struct mdl_link_t * link,
00229                                    struct mdl_element_t * eroot,
00230                                    const char * name) {
00231   char * txt = mdl_find_helement (eroot, name);
00232   return mdl_variable_value (link, txt);
00233 }
00234 
00235 // Returns a double variable value stored in a table.
00236 static double mdl_telement_dvalue (struct mdl_link_t * link,
00237                                    struct mdl_element_t * eroot,
00238                                    const char * name) {
00239   char * txt = mdl_find_telement (eroot, name);
00240   return mdl_variable_value (link, txt);
00241 }
00242 
00243 // Returns a integer variable value stored in a hypertable.
00244 static int mdl_helement_ivalue (struct mdl_link_t * link,
00245                                 struct mdl_element_t  * eroot,
00246                                 const char * name) {
00247   return (int) mdl_helement_dvalue (link, eroot, name);
00248 }
00249 
00250 // Looks for dependent data vectors and creates them.
00251 static void mdl_find_vardataset (struct mdl_dcontent_t * droot, char * name,
00252                                  strlist * deps) {
00253   struct mdl_dcontent_t * root;
00254   // go through dataset content
00255   for (root = droot; root != NULL; root = root->next) {
00256     if (root->type == t_DATASET) {
00257       // create possibly both - MEAS and SIMU - data vectors
00258       struct mdl_dataset_t * dset = root->data;
00259       if (dset->data1)
00260         mdl_create_vardataset (dset->data1, dset->dsize, name, dset->type1,
00261                                deps);
00262       if (dset->data2)
00263         mdl_create_vardataset (dset->data2, dset->dsize, name, dset->type2,
00264                                deps);
00265     }
00266   }
00267 }
00268 
00269 // Looks for independent data vectors and creates them.
00270 valuelist<int> * mdl_find_depdataset (struct mdl_link_t * link,
00271                                       struct mdl_dcontent_t * droot,
00272                                       char * name) {
00273   char * stype = NULL;
00274   double val, start, stop, step;
00275   int nof = 0, order = 0;
00276   valuelist<int> * deps = new valuelist<int> ();
00277   struct mdl_dcontent_t * root;
00278 
00279   // go through dataset content
00280   for (root = droot; root != NULL; root = root->next) {
00281     if (root->type == t_HYPTABLE) {
00282       struct mdl_hyptable_t * hyptab = root->hyptable;
00283       // found a sweep definition?
00284       if (!strcmp (hyptab->name, "Edit Sweep Def")) {
00285         if (!strcmp (stype, "LIN")) {
00286           // linear sweep
00287           order = mdl_helement_ivalue (link, hyptab->data, "Sweep Order");
00288           start = mdl_helement_dvalue (link, hyptab->data, "Start");
00289           stop = mdl_helement_dvalue (link, hyptab->data, "Stop");
00290           nof = mdl_helement_ivalue (link, hyptab->data, "# of Points");
00291           step = mdl_helement_dvalue (link, hyptab->data, "Step Size");
00292           if (nof <= 0) nof = (int) fabs ((stop - start) / step) + 1;
00293           deps->insert({{name,order}});
00294           linsweep * sw = new linsweep ();
00295           sw->create (start, stop, nof);
00296           mdl_create_depdataset (sw, name);
00297           delete sw;
00298         }
00299         else if (!strcmp (stype, "CON")) {
00300           // constant sweep
00301           val = mdl_helement_dvalue (link, hyptab->data, "Value");
00302           mdl_create_condataset (val, name);
00303         }
00304         else if (!strcmp (stype, "LOG")) {
00305           // logarithmic sweep
00306           order = mdl_helement_ivalue (link, hyptab->data, "Sweep Order");
00307           start = mdl_helement_dvalue (link, hyptab->data, "Start");
00308           stop = mdl_helement_dvalue (link, hyptab->data, "Stop");
00309           nof = mdl_helement_ivalue (link, hyptab->data, "Total Pts");
00310           if (nof <= 0)
00311             nof = mdl_helement_ivalue (link, hyptab->data, "# of Points");
00312           if (start * stop == 0.0) {
00313             if (start == 0.0) start = 1.0;
00314             if (stop  == 0.0) stop  = 1.0;
00315           }
00316           deps->insert({{name,order}});
00317           logsweep * sw = new logsweep ();
00318           sw->create (start, stop, nof);
00319           mdl_create_depdataset (sw, name);
00320           delete sw;
00321         }
00322         else if (!strcmp (stype, "LIST")) {
00323           // list sweep
00324           order = mdl_helement_ivalue (link, hyptab->data, "Sweep Order");
00325           nof = mdl_helement_ivalue (link, hyptab->data, "# of Values");
00326           deps->insert({{name,order}});
00327         }
00328         else if (!strcmp (stype, "SYNC")) {
00329           // sync sweep
00330           struct mdl_sync_t * sync = (struct mdl_sync_t *)
00331             calloc (sizeof (struct mdl_sync_t), 1);
00332           sync->ratio = mdl_helement_dvalue (link, hyptab->data, "Ratio");
00333           sync->offset = mdl_helement_dvalue (link, hyptab->data, "Offset");
00334           sync->master = mdl_find_helement (hyptab->data, "Master Sweep");
00335           sync->master = strdup (sync->master);
00336           sync->name = strdup (name);
00337           sync->next = mdl_sync_root;
00338           mdl_sync_root = sync;
00339         }
00340       }
00341       // found a sweep information?
00342       else if (!strcmp (hyptab->name, "Edit Sweep Info")) {
00343         stype = mdl_find_helement (hyptab->data, "Sweep Type");
00344       }
00345       // found a list table?
00346       else if (!strcmp (hyptab->name, "List Table")) {
00347         lstsweep * sw = new lstsweep ();
00348         sw->create (nof);
00349         char txt[16];
00350         for (int i = 0; i < nof; i++) {
00351           sprintf (txt, "Value %d", i + 1);
00352           val = mdl_helement_dvalue (link, hyptab->data, txt);
00353           sw->set (i, val);
00354         }
00355         mdl_create_depdataset (sw, name);
00356         delete sw;
00357       }
00358     }
00359   }
00360   return deps;
00361 }
00362 
00363 // Composes a link name.
00364 static char * mdl_create_linkname (char * base, char * name) {
00365   char * txt = (char *) malloc (strlen (base) + 2 + strlen (name));
00366   sprintf (txt, "%s.%s", base, name);
00367   return txt;
00368 }
00369 
00370 // Collects dependency links.
00371 static void mdl_find_deplink (struct mdl_link_t * link, char * name,
00372                               valuelist<int> * deps) {
00373   struct mdl_lcontent_t * root;
00374   const valuelist<int> * d;
00375   // go through link content
00376   for (root = link->content; root != NULL; root = root->next) {
00377     // independent data vector
00378     if (root->type == t_DATA) {
00379       d = mdl_find_depdataset (link, root->data->content, name);
00380       if (d != NULL) {
00381         valuelist<int> copy = *d;
00382         delete d;
00383         copy.insert(deps->begin(),deps->end());
00384         *deps=copy;
00385       }
00386     }
00387     // link to independent data vector
00388     else if (root->type == t_LINK && !strcmp (root->link->type, "SWEEP")) {
00389       char * txt = mdl_create_linkname (name, root->link->name);
00390       root->link->parent = link;
00391       mdl_find_deplink (root->link, txt, deps);
00392       free (txt);
00393     }
00394   }
00395 }
00396 
00397 // Collects variable links.
00398 static void mdl_find_varlink (struct mdl_link_t * link, char * name,
00399                               strlist * deps) {
00400   struct mdl_lcontent_t * root;
00401   // go through link content
00402   for (root = link->content; root != NULL; root = root->next) {
00403     // dependent data vector
00404     if (root->type == t_DATA) {
00405       mdl_find_vardataset (root->data->content, name, deps);
00406     }
00407     // link to dependent data vector
00408     else if (root->type == t_LINK && (!strcmp (root->link->type, "OUT") ||
00409                                       !strcmp (root->link->type, "XFORM"))) {
00410       char * txt = mdl_create_linkname (name, root->link->name);
00411       root->link->parent = link;
00412       mdl_find_varlink (root->link, txt, deps);
00413       free (txt);
00414     }
00415   }
00416 }
00417 
00418 // Sorts a dependency list according to their sweep order.
00419 static strlist * mdl_sort_deps (valuelist<int> * d) {
00420   strlist * deps = new strlist ();
00421   for (int i = 0; i < d->size(); i++) {
00422     for (auto &val: *d) {
00423       if (val.second == i + 1) {
00424         deps->append (val.first.c_str());
00425       }
00426     }
00427   }
00428   return deps;
00429 }
00430 
00431 // Iterates the MDL file recursively.
00432 static void mdl_find_link (struct mdl_link_t * link, char * name) {
00433   struct mdl_lcontent_t * root;
00434 
00435   // collect independent data
00436   valuelist<int> * vdeps = new valuelist<int> ();
00437   mdl_find_deplink (link, name, vdeps);
00438   strlist * deps = mdl_sort_deps (vdeps);
00439   delete vdeps;
00440 
00441   // collect dependent data
00442   mdl_find_varlink (link, name, deps);
00443   delete deps;
00444 
00445   // go through link content
00446   for (root = link->content; root != NULL; root = root->next) {
00447     if (root->type == t_LINK &&
00448         strcmp (root->link->type, "OUT") &&
00449         strcmp (root->link->type, "SWEEP") &&
00450         strcmp (root->link->type, "XFORM")) {
00451       char * txt = mdl_create_linkname (name, root->link->name);
00452       root->link->parent = link;
00453       mdl_find_link (root->link, txt);
00454       free (txt);
00455     }
00456   }
00457 }
00458 
00459 // Creates an synchronized independent data vector.
00460 static void mdl_create_syndataset (vector * v, char * name) {
00461   v->setName (name);
00462   mdl_result->appendDependency (v);
00463 }
00464 
00465 // Goes through list of sync sweeps and creates them if possible.
00466 void mdl_find_syncdatasets (struct mdl_sync_t * root) {
00467   struct mdl_sync_t * sync;
00468   for (sync = root; sync != NULL; sync = sync->next) {
00469     // determine master sweep link
00470     char * link = sync->name;
00471     int i = strlen (link) - 1;
00472     while (i > 0 && link[i] != '.') i--;
00473     if (link[i] == '.') {
00474       link[i] = '\0';
00475       char * txt = (char *) malloc (i + 2 + strlen (sync->master));
00476       sprintf (txt, "%s.%s", link, sync->master);
00477       link[i] = '.';
00478       free (sync->master);
00479       sync->master = txt;
00480     }
00481     // create synchronize independent data vector
00482     vector * v = mdl_result->findDependency (sync->master);
00483     if (v != NULL) {
00484       vector * s = new vector ((*v) * sync->ratio + sync->offset);
00485       mdl_create_syndataset (s, sync->name);
00486     }
00487   }
00488 }
00489 
00490 // Destroys an element structure.
00491 static void mdl_free_element (struct mdl_element_t * e) {
00492   free (e->name);
00493   free (e->value);
00494   free (e->attr);
00495   free (e);
00496 }
00497 
00498 // Destroys a datasize structure.
00499 static void mdl_free_datasize (struct mdl_datasize_t * d) {
00500   free (d->type);
00501   free (d);
00502 }
00503 
00504 // Destroys a hypertable structure.
00505 static void mdl_free_hyptable (struct mdl_hyptable_t * h) {
00506   free (h->name);
00507   struct mdl_element_t * e, * next;
00508   for (e = h->data; e != NULL; e = next) {
00509     next = e->next;
00510     mdl_free_element (e);
00511   }
00512   free (h);
00513 }
00514 
00515 // Destroys a table structure.
00516 static void mdl_free_table (struct mdl_table_t * t) {
00517   free (t->name);
00518   struct mdl_element_t * e, * next;
00519   for (e = t->data; e != NULL; e = next) {
00520     next = e->next;
00521     mdl_free_element (e);
00522   }
00523   free (t);
00524 }
00525 
00526 // Destroys a dataset structure.
00527 static void mdl_free_dataset (struct mdl_dataset_t * d) {
00528   free (d->type1);
00529   struct mdl_point_t * p, * next;
00530   for (p = d->data1; p != NULL; p = next) {
00531     next = p->next;
00532     free (p);
00533   }
00534   free (d->type2);
00535   for (p = d->data2; p != NULL; p = next) {
00536     next = p->next;
00537     free (p);
00538   }
00539   if (d->dsize) mdl_free_datasize (d->dsize);
00540 }
00541 
00542 // Destroys a data content structure.
00543 static void mdl_free_dcontent (struct mdl_dcontent_t * c) {
00544   switch (c->type) {
00545   case t_DATASET: mdl_free_dataset (c->data); break;
00546   case t_HYPTABLE: mdl_free_hyptable (c->hyptable); break;
00547   }
00548 }
00549 
00550 // Destroys a data structure.
00551 static void mdl_free_data (struct mdl_data_t * d) {
00552   struct mdl_dcontent_t * c, * next;
00553   for (c = d->content; c != NULL; c = next) {
00554     next = c->next;
00555     mdl_free_dcontent (c);
00556   }
00557 }
00558 
00559 // Forward declaration.
00560 static void mdl_free_link (struct mdl_link_t *);
00561 
00562 // Destroys a link content structure.
00563 static void mdl_free_lcontent (struct mdl_lcontent_t * c) {
00564   switch (c->type) {
00565   case t_LINK: mdl_free_link (c->link); break;
00566   case t_DATA: mdl_free_data (c->data); break;
00567   case t_TABLE: mdl_free_table (c->table); break;
00568   }
00569   free (c);
00570 }
00571 
00572 // Destroys a link structure.
00573 static void mdl_free_link (struct mdl_link_t * l) {
00574   free (l->name);
00575   free (l->type);
00576   struct mdl_lcontent_t * c, * next;
00577   for (c = l->content; c != NULL; c = next) {
00578     next = c->next;
00579     mdl_free_lcontent (c);
00580   }
00581 }
00582 
00583 // Destroys a sync structure.
00584 static void mdl_free_sync (struct mdl_sync_t * s) {
00585   struct mdl_sync_t * next;
00586   for (; s != NULL; s = next) {
00587     next = s->next;
00588     free (s->name);
00589     free (s->master);
00590     free (s);
00591   }
00592 }
00593 
00594 // Computes the dependent vector length for the given dependency list.
00595 static int mdl_get_depsize (strlist * deps) {
00596   char * n;
00597   vector * v;
00598   int res = 1;
00599   for (int i = 0; i < deps->length (); i++) {
00600     if ((n = deps->get (i)) != NULL)
00601       if ((v = mdl_result->findDependency (n)) != NULL)
00602         res *= v->getSize ();
00603   }
00604   return res;
00605 }
00606 
00607 // Checks the variable vector dependencies.  Makes them independent if
00608 // necessary.
00609 static void mdl_check_xform_deplen (void) {
00610   vector * v, * next;
00611   for (v = mdl_result->getVariables (); v; v = next) {
00612     next = (vector *) v->getNext ();
00613     strlist * deps = v->getDependencies ();
00614     if (deps->length () <= 0) {
00615       vector * d = new vector (*v);
00616       mdl_result->delVariable (v);
00617       mdl_result->addDependency (d);
00618     }
00619   }
00620 }
00621 
00622 // Checks the variable vector dependencies and reduces them if necessary.
00623 static void mdl_check_xform_dep (void) {
00624   vector * v, * d;
00625   strlist * deps;
00626   for (v = mdl_result->getVariables (); v; v = (vector *) v->getNext ()) {
00627     deps = v->getDependencies ();
00628     int s = mdl_get_depsize (deps);
00629     // dependencies differ from actual vector length
00630     if (v->getSize () != s) {
00631       int found = 0;
00632       for (int i = 0; i < deps->length (); i++) {
00633         // find out a single dependency with the appropriate length
00634         char * n = deps->get (i);
00635         if (n != NULL) {
00636           d = mdl_result->findDependency (n);
00637           if (d != NULL && v->getSize () == d->getSize ()) {
00638             strlist * dep = new strlist ();
00639             dep->add (n);
00640             v->setDependencies (dep);
00641             found++;
00642             break;
00643           }
00644         }
00645       }
00646       // if not found, then no dependency vector
00647       if (!found) v->setDependencies (new strlist ());
00648     }
00649   }
00650 }
00651 
00652 // Checks the XFORM's in the model file
00653 static void mdl_check_xforms (void) {
00654   mdl_check_xform_dep ();
00655   mdl_check_xform_deplen ();
00656 }
00657 
00658 /* This function is the overall MDL data checker.  It returns zero on
00659    success, non-zero otherwise. */
00660 int mdl_check (void) {
00661   int errors = 0;
00662   mdl_result = new dataset ();
00663   struct mdl_link_t * root;
00664   for (root = mdl_root; root; root = root->next) {
00665     char * name = root->name;
00666     mdl_find_link (root, name);
00667   }
00668   mdl_find_syncdatasets (mdl_sync_root);
00669   mdl_check_xforms ();
00670   return errors ? -1 : 0;
00671 }
00672 
00673 // Destroys data used by the MDL checker.
00674 void mdl_destroy (void) {
00675   if (mdl_result != NULL) {
00676     // delete associated dataset
00677     delete mdl_result;
00678     mdl_result = NULL;
00679   }
00680   if (mdl_root != NULL) {
00681     // release internal data structures
00682     struct mdl_link_t * root, * next;
00683     for (root = mdl_root; root; root = next) {
00684       next = root->next;
00685       mdl_free_link (root);
00686     }
00687     mdl_root = NULL;
00688   }
00689   if (mdl_sync_root != NULL) {
00690     // release internal sync structures
00691     mdl_free_sync (mdl_sync_root);
00692     mdl_sync_root = NULL;
00693   }
00694 }
00695 
00696 // Initializes the MDL checker.
00697 void mdl_init (void) {
00698   mdl_root = NULL;
00699   mdl_result = NULL;
00700   mdl_sync_root = NULL;
00701 }