Branch data Line data Source code
1 : : /*
2 : : * check_touchstone.cpp - checker for Touchstone files
3 : : *
4 : : * Copyright (C) 2003, 2004, 2005, 2006 Stefan Jahn <stefan@lkcc.org>
5 : : *
6 : : * This is free software; you can redistribute it and/or modify
7 : : * it under the terms of the GNU General Public License as published by
8 : : * the Free Software Foundation; either version 2, or (at your option)
9 : : * any later version.
10 : : *
11 : : * This software is distributed in the hope that it will be useful,
12 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : : * GNU General Public License for more details.
15 : : *
16 : : * You should have received a copy of the GNU General Public License
17 : : * along with this package; see the file COPYING. If not, write to
18 : : * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
19 : : * Boston, MA 02110-1301, USA.
20 : : *
21 : : * $Id$
22 : : *
23 : : */
24 : :
25 : : #if HAVE_CONFIG_H
26 : : # include <config.h>
27 : : #endif
28 : :
29 : : #include <stdio.h>
30 : : #include <stdlib.h>
31 : : #include <string.h>
32 : : #include <ctype.h>
33 : : #include <cmath>
34 : :
35 : : #include "logging.h"
36 : : #include "complex.h"
37 : : #include "object.h"
38 : : #include "vector.h"
39 : : #include "matrix.h"
40 : : #include "matvec.h"
41 : : #include "dataset.h"
42 : : #include "strlist.h"
43 : : #include "constants.h"
44 : : #include "check_touchstone.h"
45 : :
46 : : #define ZREF 50.0 /* reference impedance */
47 : :
48 : : using namespace qucs;
49 : :
50 : : strlist * touchstone_idents = NULL;
51 : : dataset * touchstone_result = NULL;
52 : : qucs::vector * touchstone_vector = NULL;
53 : :
54 : : /* default touchstone options */
55 : : struct touchstone_t touchstone_options = {
56 : : "GHz", 'S', "MA", 50.0, 1e9, 0, 0, 0 };
57 : :
58 : : /* available touchstone options */
59 : : static const char * touchstone_valid_options[] = {
60 : : "hz", "khz", "mhz", "ghz", "s", "y", "z", "g", "h", "ma", "db", "ri", NULL };
61 : :
62 : : /* This subroutine is going to join vectors on multiple lines. The
63 : : input and output list of vectors of this function is the
64 : : touchstone_vector variable. */
65 : 0 : static void touchstone_join (void) {
66 : 0 : qucs::vector * yroot, * xroot, * next = NULL;
67 : : /* go through each vector */
68 [ # # ]: 0 : for (yroot = touchstone_vector; yroot != NULL; yroot = next) {
69 : : /* go through each trailing vector */
70 : 0 : next = (qucs::vector *) yroot->getNext ();
71 [ # # ]: 0 : for (xroot = next; xroot != NULL; xroot = next) {
72 : 0 : next = (qucs::vector *) xroot->getNext ();
73 : : /* append xroot vector to yroot vector (even no. of values) ? */
74 [ # # ]: 0 : if ((xroot->getSize () & 1) == 0) {
75 : : /* yes, delete the xroot vector and adjust list */
76 : 0 : yroot->add (xroot);
77 : 0 : yroot->setNext (next);
78 [ # # ]: 0 : delete xroot;
79 : : }
80 : : else {
81 : : /* no, handle next vectors */
82 : 0 : next = xroot;
83 : 0 : break;
84 : : }
85 : : }
86 : : }
87 : 0 : }
88 : :
89 : : /* This subroutine checks the size and overall conformance of each
90 : : touchstone matrix at a given frequency derived from the first
91 : : matrix. The function return zero on success and non-zero
92 : : otherwise. */
93 : 0 : static int touchstone_vector_check (void) {
94 : 0 : qucs::vector * root = touchstone_vector, * next;
95 : 0 : int even = 0, errors = 0, size = root->getSize (), noise = 0, lines = 1;
96 : 0 : nr_double_t f = real (root->get (0));
97 : :
98 : : /* check size of first line */
99 [ # # ]: 0 : if ((size & 1) == 0) {
100 : : logprint (LOG_ERROR, "checker error, first data line has %d (even) "
101 : 0 : "values\n", size);
102 : 0 : errors++;
103 : 0 : even = 1;
104 : : }
105 : : /* first line determines the number of expected ports */
106 : 0 : touchstone_options.ports = (int) std::sqrt ((size - 1) / 2.0);
107 : :
108 : : /* check first frequency value */
109 [ # # ]: 0 : if (f < 0.0) {
110 : : logprint (LOG_ERROR, "checker error, negative data frequency "
111 : 0 : "value %g\n", f);
112 : 0 : errors++;
113 : : }
114 : :
115 : : /* go through each vector */
116 [ # # ]: 0 : for (root = (qucs::vector *) root->getNext (); root != NULL; root = next) {
117 : 0 : next = (qucs::vector *) root->getNext ();
118 : 0 : nr_double_t freq = real (root->get (0));
119 : :
120 : : /* check increasing frequency value */
121 [ # # ]: 0 : if (f >= freq) {
122 [ # # ]: 0 : if (!noise) {
123 : : /* determined start of noise parameters */
124 : 0 : noise++;
125 : 0 : size = 5;
126 [ # # ]: 0 : if (freq < 0.0) {
127 : : logprint (LOG_ERROR, "checker error, negative noise frequency "
128 : 0 : "value %g\n", freq);
129 : 0 : errors++;
130 : : }
131 : : }
132 : : else {
133 : : logprint (LOG_ERROR, "checker error, %s line (f = %g) has "
134 : : "decreasing frequency value\n", noise ? "noise" : "data",
135 [ # # ]: 0 : freq);
136 : 0 : errors++;
137 : : }
138 : : }
139 : 0 : f = freq;
140 : :
141 : : /* check size of vector */
142 [ # # ][ # # ]: 0 : if (!even && root->getSize () != size) {
[ # # ]
143 : : logprint (LOG_ERROR, "checker error, %s line (f = %g) has %d values, "
144 : : "%d required\n", noise ? "noise" : "data",
145 [ # # ][ # # ]: 0 : real (root->get (0)), root->getSize (), size);
146 : 0 : errors++;
147 : : }
148 : :
149 : : /* count number of data lines without noise entries */
150 [ # # ]: 0 : if (!noise) lines++;
151 : : }
152 : 0 : touchstone_options.noise = noise;
153 : 0 : touchstone_options.lines = lines;
154 : 0 : return errors;
155 : : }
156 : :
157 : : /* The function evaluates the identifiers in the option line and fills
158 : : the touchstone_options structure with appropriate values. */
159 : 0 : static void touchstone_options_eval (void) {
160 : : /* go through all identifiers */
161 [ # # ]: 0 : for (int i = 0; i < touchstone_idents->length (); i++) {
162 : 0 : char * str = touchstone_idents->get (i);
163 : : /* frequency unit */
164 [ # # ]: 0 : if (!strcmp (str, "hz")) {
165 : 0 : touchstone_options.factor = 1.0;
166 : 0 : touchstone_options.unit = "Hz";
167 : : }
168 [ # # ]: 0 : else if (!strcmp (str, "khz")) {
169 : 0 : touchstone_options.factor = 1e3;
170 : 0 : touchstone_options.unit = "kHz";
171 : : }
172 [ # # ]: 0 : else if (!strcmp (str, "mhz")) {
173 : 0 : touchstone_options.factor = 1e6;
174 : 0 : touchstone_options.unit = "MHz";
175 : : }
176 [ # # ]: 0 : else if (!strcmp (str, "ghz")) {
177 : 0 : touchstone_options.factor = 1e9;
178 : 0 : touchstone_options.unit = "GHz";
179 : : }
180 : : /* parameter type */
181 [ # # ]: 0 : else if (!strcmp (str, "s")) {
182 : 0 : touchstone_options.parameter = 'S';
183 : : }
184 [ # # ]: 0 : else if (!strcmp (str, "y")) {
185 : 0 : touchstone_options.parameter = 'Y';
186 : : }
187 [ # # ]: 0 : else if (!strcmp (str, "z")) {
188 : 0 : touchstone_options.parameter = 'Z';
189 : : }
190 [ # # ]: 0 : else if (!strcmp (str, "g")) {
191 : 0 : touchstone_options.parameter = 'G';
192 : : }
193 [ # # ]: 0 : else if (!strcmp (str, "h")) {
194 : 0 : touchstone_options.parameter = 'H';
195 : : }
196 : : /* value formats */
197 [ # # ]: 0 : else if (!strcmp (str, "ma")) {
198 : 0 : touchstone_options.format = "MA";
199 : : }
200 [ # # ]: 0 : else if (!strcmp (str, "db")) {
201 : 0 : touchstone_options.format = "dB";
202 : : }
203 [ # # ]: 0 : else if (!strcmp (str, "ri")) {
204 : 0 : touchstone_options.format = "RI";
205 : : }
206 : : }
207 : 0 : }
208 : :
209 : : /* This little function returns a static string containing an
210 : : appropriate variable name. */
211 : 0 : static char * touchstone_create_set (int r, int c) {
212 : : char * text;
213 : 0 : text = matvec::createMatrixString (touchstone_options.parameter, r, c);
214 : 0 : return text;
215 : : }
216 : :
217 : : /* The function actually creates the resulting dataset. */
218 : 0 : static void touchstone_create (void) {
219 : 0 : qucs::vector * f, * v, * root, * next, * nf = NULL;
220 : 0 : int ports = touchstone_options.ports, n;
221 : 0 : nr_complex_t val;
222 : : strlist * s;
223 : :
224 : : /* create dataset and frequency vector */
225 [ # # ][ # # ]: 0 : touchstone_result = new dataset ();
226 [ # # ][ # # ]: 0 : f = new qucs::vector ("frequency");
227 [ # # ]: 0 : touchstone_result->appendDependency (f);
228 [ # # ][ # # ]: 0 : s = new strlist ();
229 [ # # ]: 0 : s->add (f->getName ());
230 : : /* create variable vectors for the resulting dataset */
231 [ # # ]: 0 : for (int r = 0; r < ports; r++) {
232 [ # # ]: 0 : for (int c = 0; c < ports; c++) {
233 [ # # ][ # # ]: 0 : v = new qucs::vector ();
234 [ # # ][ # # ]: 0 : v->setName (touchstone_create_set (r, c));
235 [ # # ][ # # ]: 0 : v->setDependencies (new strlist (*s));
[ # # ]
236 [ # # ]: 0 : touchstone_result->appendVariable (v);
237 : : }
238 : : }
239 [ # # ][ # # ]: 0 : delete s;
240 : :
241 : : /* create noise vectors if necessary */
242 [ # # ]: 0 : if (touchstone_options.noise) {
243 [ # # ][ # # ]: 0 : nf = new qucs::vector ("nfreq");
244 [ # # ]: 0 : touchstone_result->appendDependency (nf);
245 [ # # ][ # # ]: 0 : s = new strlist ();
246 [ # # ]: 0 : s->add (nf->getName ());
247 : : /* append noise parameters to dataset */
248 [ # # ][ # # ]: 0 : v = new qucs::vector ("Fmin");
249 [ # # ][ # # ]: 0 : v->setDependencies (new strlist (*s));
[ # # ]
250 [ # # ]: 0 : touchstone_result->appendVariable (v);
251 [ # # ][ # # ]: 0 : v = new qucs::vector ("Sopt");
252 [ # # ][ # # ]: 0 : v->setDependencies (new strlist (*s));
[ # # ]
253 [ # # ]: 0 : touchstone_result->appendVariable (v);
254 [ # # ][ # # ]: 0 : v = new qucs::vector ("Rn");
255 [ # # ][ # # ]: 0 : v->setDependencies (new strlist (*s));
[ # # ]
256 [ # # ]: 0 : touchstone_result->appendVariable (v);
257 [ # # ][ # # ]: 0 : delete s;
258 : : }
259 : :
260 : : /* go through each vector */
261 [ # # ]: 0 : for (n = 0, root = touchstone_vector; root != NULL; root = next, n++) {
262 : 0 : next = (qucs::vector *) root->getNext ();
263 : : // handle data lines
264 [ # # ]: 0 : if (n < touchstone_options.lines) {
265 : : /* fill frequency vector */
266 [ # # ][ # # ]: 0 : f->add (real (root->get (0)) * touchstone_options.factor);
267 : : /* go through each variable vector */
268 : 0 : v = touchstone_result->getVariables ();
269 [ # # ]: 0 : for (int i = 0; i < ports; i++) {
270 [ # # ]: 0 : for (int j = 0; j < ports; j++) {
271 : 0 : int pos = 1 + j * 2 + i * 2 * ports;
272 : : /* handle special case for 2-port touchstone data, '21' data
273 : : precedes the '12' data */
274 [ # # ][ # # ]: 0 : if (ports == 2 && i != j) {
275 : 0 : pos = 1 + i * 2 + j * 2 * ports;
276 : : }
277 : : /* depending on the touchstone data format */
278 [ # # ]: 0 : if (!strcmp (touchstone_options.format, "RI")) {
279 : : val = nr_complex_t (real (root->get (pos + 0)),
280 [ # # ][ # # ]: 0 : real (root->get (pos + 1)));
281 : : }
282 [ # # ]: 0 : else if (!strcmp (touchstone_options.format, "MA")) {
283 : : val = qucs::polar (real (root->get (pos + 0)),
284 [ # # ][ # # ]: 0 : rad (real (root->get (pos + 1))));
[ # # ]
285 : : }
286 [ # # ]: 0 : else if (!strcmp (touchstone_options.format, "dB")) {
287 [ # # ]: 0 : val = qucs::polar (std::pow (10.0, real (root->get (pos + 0)) / 20.0),
288 [ # # ][ # # ]: 0 : rad (real (root->get (pos + 1))));
289 : : }
290 [ # # ]: 0 : v->add (val);
291 : 0 : v = (qucs::vector *) v->getNext ();
292 : : }
293 : : }
294 : : }
295 : : // handle noise lines
296 [ # # ]: 0 : else if (touchstone_options.noise) {
297 : : /* fill frequency vector */
298 [ # # ][ # # ]: 0 : nf->add (real (root->get (0)) * touchstone_options.factor);
299 : : /* fill minimum noise figure vector */
300 [ # # ]: 0 : v = touchstone_result->findVariable ("Fmin");
301 [ # # ]: 0 : val = std::pow (10.0, real (root->get (1)) / 10.0);
302 [ # # ]: 0 : v->add (val);
303 : : /* fill optimal noise reflexion coefficient vector */
304 [ # # ]: 0 : v = touchstone_result->findVariable ("Sopt");
305 [ # # ][ # # ]: 0 : val = qucs::polar (real (root->get (2)), rad (real (root->get (3))));
[ # # ]
306 [ # # ]: 0 : if (ZREF != touchstone_options.resistance) {
307 : : // re-normalize reflexion coefficient if necessary
308 : : nr_double_t r = (ZREF - touchstone_options.resistance) /
309 : 0 : (ZREF + touchstone_options.resistance);
310 [ # # ]: 0 : val = (val - r) / (1.0 - r * val);
311 : : }
312 [ # # ]: 0 : v->add (val);
313 : : /* fill equivalent noise resistance vector */
314 [ # # ]: 0 : v = touchstone_result->findVariable ("Rn");
315 [ # # ]: 0 : val = real (root->get (4)) * touchstone_options.resistance;
316 [ # # ]: 0 : v->add (val);
317 : : }
318 : : }
319 : 0 : }
320 : :
321 : : /* The function re-normalizes S-parameters to the internal reference
322 : : impedance 50 Ohms. */
323 : 0 : static void touchstone_normalize_sp (void) {
324 : 0 : int ports = touchstone_options.ports;
325 : 0 : qucs::vector * v = touchstone_result->getVariables ();
326 [ # # ]: 0 : int i, j, n, len = v->getSize ();
327 [ # # ]: 0 : matrix s = matrix (ports);
328 : :
329 : : // go through each matrix entry
330 [ # # ]: 0 : for (n = 0; n < len; n++) {
331 : 0 : v = touchstone_result->getVariables ();
332 : : // save entries in a temporary matrix
333 [ # # ]: 0 : for (i = 0; i < ports; i++) {
334 [ # # ]: 0 : for (j = 0; j < ports; j++) {
335 [ # # ][ # # ]: 0 : s.set (i, j, v->get (n));
336 : 0 : v = (qucs::vector *) v->getNext ();
337 : : }
338 : : }
339 : : // convert the temporary matrix
340 [ # # ][ # # ]: 0 : s = stos (s, touchstone_options.resistance, ZREF);
[ # # ][ # # ]
[ # # ]
341 : 0 : v = touchstone_result->getVariables ();
342 : : // restore the results in the entries
343 [ # # ]: 0 : for (i = 0; i < ports; i++) {
344 [ # # ]: 0 : for (j = 0; j < ports; j++) {
345 [ # # ][ # # ]: 0 : v->set (s.get (i, j), n);
346 : 0 : v = (qucs::vector *) v->getNext ();
347 : : }
348 : : }
349 [ # # ]: 0 : }
350 : 0 : }
351 : :
352 : : /* The function transforms the reference impedance given in the
353 : : touchstone file to the internal reference impedance 50 Ohms. */
354 : 0 : static void touchstone_normalize (void) {
355 : 0 : qucs::vector * v = touchstone_result->getVariables ();
356 : 0 : int ports = touchstone_options.ports;
357 : :
358 : : // transform S-parameters if necessary
359 [ # # ]: 0 : if (touchstone_options.parameter == 'S') {
360 [ # # ]: 0 : if (touchstone_options.resistance != ZREF)
361 : 0 : touchstone_normalize_sp ();
362 : 0 : return;
363 : : }
364 : : // transform any other X-parameters
365 [ # # ]: 0 : for (int i = 1; i <= ports; i++) {
366 [ # # ]: 0 : for (int j = 1; j <= ports; j++) {
367 [ # # # # : 0 : switch (touchstone_options.parameter) {
# ]
368 : : case 'Y': // Y-parameters
369 : 0 : *v /= touchstone_options.resistance;
370 : 0 : break;
371 : : case 'Z': // Z-parameters
372 : 0 : *v *= touchstone_options.resistance;
373 : 0 : break;
374 : : case 'G': // hybrid G-parameters
375 [ # # ][ # # ]: 0 : if (i == 1 && j == 1)
376 : 0 : *v /= touchstone_options.resistance;
377 [ # # ][ # # ]: 0 : else if (i == 2 && j == 2)
378 : 0 : *v *= touchstone_options.resistance;
379 : 0 : break;
380 : : case 'H': // hybrid H-parameters
381 [ # # ][ # # ]: 0 : if (i == 1 && j == 1)
382 : 0 : *v *= touchstone_options.resistance;
383 [ # # ][ # # ]: 0 : else if (i == 2 && j == 2)
384 : 0 : *v /= touchstone_options.resistance;
385 : 0 : break;
386 : : }
387 : 0 : v = (qucs::vector *) v->getNext ();
388 : : }
389 : : }
390 : : }
391 : :
392 : : /* Removes temporary data items from memory if necessary. */
393 : 0 : static void touchstone_finalize (void) {
394 : : qucs::vector * root, * next;
395 [ # # ]: 0 : for (root = touchstone_vector; root != NULL; root = next) {
396 : 0 : next = (qucs::vector *) root->getNext ();
397 [ # # ]: 0 : delete root;
398 : : }
399 : 0 : touchstone_vector = NULL;
400 [ # # ]: 0 : if (touchstone_idents != NULL) {
401 [ # # ]: 0 : delete touchstone_idents;
402 : 0 : touchstone_idents = NULL;
403 : : }
404 : 0 : touchstone_lex_destroy ();
405 : : /* apply default values again */
406 : 0 : touchstone_options.unit = "GHz";
407 : 0 : touchstone_options.parameter = 'S';
408 : 0 : touchstone_options.format = "MA";
409 : 0 : touchstone_options.resistance = 50.0;
410 : 0 : touchstone_options.factor = 1e9;
411 : 0 : touchstone_options.ports = 0;
412 : 0 : touchstone_options.noise = 0;
413 : 0 : touchstone_options.lines = 0;
414 : 0 : }
415 : :
416 : :
417 : : /* This function is the checker routine for a parsed touchstone. It
418 : : returns zero on success or non-zero if the parsed touchstone
419 : : contained errors. */
420 : 0 : int touchstone_check (void) {
421 : :
422 : 0 : int i, n, errors = 0;
423 : :
424 : : /* first checking the options */
425 [ # # ]: 0 : if (touchstone_idents->length () > 3) {
426 : : logprint (LOG_ERROR, "checker error, found %d options\n",
427 : 0 : touchstone_idents->length ());
428 : 0 : errors++;
429 : : }
430 : : /* touchstone is case insensitive */
431 [ # # ]: 0 : for (i = 0; i < touchstone_idents->length (); i++) {
432 [ # # ]: 0 : for (char * p = touchstone_idents->get (i); *p != '\0'; p++)
433 : 0 : *p = tolower (*p);
434 : : }
435 : : /* check duplicate options */
436 [ # # ]: 0 : for (i = 0; i < touchstone_idents->length (); i++) {
437 : 0 : char * str = touchstone_idents->get (i);
438 [ # # ]: 0 : if ((n = touchstone_idents->contains (str)) != 1) {
439 : : logprint (LOG_ERROR, "checker error, option `%s' occurred %dx\n",
440 : 0 : str, n);
441 : 0 : errors++;
442 : : }
443 : : }
444 : : /* check valid options */
445 [ # # ]: 0 : for (i = 0; i < touchstone_idents->length (); i++) {
446 : 0 : char * str = touchstone_idents->get (i);
447 : 0 : int valid = 0;
448 [ # # ]: 0 : for (int v = 0; touchstone_valid_options[v] != NULL; v++) {
449 [ # # ]: 0 : if (!strcmp (touchstone_valid_options[v], str))
450 : 0 : valid = 1;
451 : : }
452 [ # # ]: 0 : if (!valid) {
453 : 0 : logprint (LOG_ERROR, "checker error, invalid option `%s'\n", str);
454 : 0 : errors++;
455 : : }
456 : : }
457 : :
458 : : /* evaluate the option line and put values into touchstone_options
459 : : structure */
460 : 0 : touchstone_options_eval ();
461 : :
462 [ # # ]: 0 : if (touchstone_vector == NULL) {
463 : 0 : logprint (LOG_ERROR, "checker error, no data in touchstone file\n");
464 : 0 : errors++;
465 : : }
466 : : else {
467 : : /* join vectors on multiple lines */
468 : 0 : touchstone_join ();
469 : :
470 : : /* check each vector */
471 : 0 : errors += touchstone_vector_check ();
472 : :
473 : : /* check validity of ports and parameters */
474 [ # # ][ # # ]: 0 : if ((touchstone_options.parameter == 'G' ||
[ # # ]
475 : : touchstone_options.parameter == 'H') &&
476 : : touchstone_options.ports != 2) {
477 : : logprint (LOG_ERROR, "checker error, %c-parameters for %d-ports not "
478 : : "defined\n", touchstone_options.parameter,
479 : 0 : touchstone_options.ports);
480 : 0 : errors++;
481 : : }
482 : :
483 : : /* check noise parameter compatibility */
484 [ # # ][ # # ]: 0 : if (touchstone_options.noise && touchstone_options.ports != 2) {
485 : : logprint (LOG_ERROR, "checker error, noise parameters for %d-ports not "
486 : 0 : "defined\n", touchstone_options.ports);
487 : 0 : errors++;
488 : : }
489 : : }
490 : :
491 : : /* finally create a dataset */
492 [ # # ]: 0 : if (!errors) {
493 : 0 : touchstone_create ();
494 : 0 : touchstone_normalize ();
495 : : }
496 : :
497 : : #if DEBUG
498 : : /* emit little notify message on successful loading */
499 [ # # ]: 0 : if (!errors) {
500 : : logprint (LOG_STATUS, "NOTIFY: touchstone %d-port %c-data%s loaded\n",
501 : : touchstone_options.ports, touchstone_options.parameter,
502 [ # # ]: 0 : touchstone_options.noise ? " including noise" : "");
503 : : }
504 : : #endif
505 : :
506 : : /* free temporary memory */
507 : 0 : touchstone_finalize ();
508 : :
509 [ # # ]: 0 : return errors ? -1 : 0;
510 : : }
511 : :
512 : : // Destroys data used by the Touchstone file lexer, parser and checker.
513 : 0 : void touchstone_destroy (void) {
514 [ # # ]: 0 : if (touchstone_result != NULL) {
515 : : // delete associated dataset
516 [ # # ]: 0 : delete touchstone_result;
517 : 0 : touchstone_result = NULL;
518 : : }
519 [ # # ]: 0 : if (touchstone_vector != NULL) {
520 : 0 : touchstone_finalize ();
521 : 0 : touchstone_vector = NULL;
522 : : }
523 : 0 : }
524 : :
525 : : // Initializes the Touchstone file checker.
526 : 0 : void touchstone_init (void) {
527 : 0 : touchstone_result = NULL;
528 : 0 : touchstone_vector = NULL;
529 : 0 : touchstone_idents = NULL;
530 : 0 : }
|