/[ascend]/trunk/base/generic/compiler/module.c
ViewVC logotype

Contents of /trunk/base/generic/compiler/module.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 692 - (show annotations) (download) (as text)
Thu Jun 22 02:45:47 2006 UTC (18 years ago) by johnpye
File MIME type: text/x-csrc
File size: 51240 byte(s)
Fixed up behaviour of default ASCENDLIBRARY in python interface (for the case
where you're using ascpy without using the PyGTK GUI).
Removed some debug output when loading external libraries.
Fixed up the 'extfntest' example & SConscript file.
1 /* ASCEND modelling environment
2 Copyright (C) 1990, 1993, 1994 Thomas Guthrie Epperly
3 Copyright (C) 2006 Carnegie Mellon University
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
8 any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19 *//** @file
20 Ascend Module Control
21 *//*
22 by Tom Epperly
23 Created: 1/11/90
24 Last in CVS: $Revision: 1.25 $ $Date: 1998/03/17 22:09:12 $ $Author: ballan $
25 */
26
27 #include <errno.h>
28 #include <stdarg.h>
29 #include <time.h>
30 #include <ctype.h>
31 #include <sys/stat.h>
32 #include <utilities/ascConfig.h>
33 #include <utilities/ascMalloc.h>
34 #include <utilities/ascEnvVar.h>
35 #include <utilities/ascPanic.h>
36 #include <general/list.h>
37 #include "scanner.h"
38 #include "compiler.h"
39 #include "instance_enum.h"
40 #include "cmpfunc.h"
41 #include "symtab.h"
42 #include "module.h"
43 #include "library.h"
44 #include <general/ospath.h>
45
46 #ifndef lint
47 static CONST char ModuleRCSid[] = "$Id: module.c,v 1.25 1998/03/17 22:09:12 ballan Exp $";
48 #endif /* RCS ID keyword */
49
50
51 #ifdef __WIN32__
52 #define SLASH '\\'
53 #define PATHDIV ';'
54 #else /* ! __WIN32__ */
55 #define SLASH '/'
56 #define PATHDIV ':'
57 #endif
58
59
60 struct module_t {
61 symchar *name; /* module's name, including extension
62 * and version number, no path information.
63 * This is how clients access and find
64 * modules.
65 */
66 symchar *filename; /* module's "full" path name---i.e., what
67 * we need to feed to fopen() to open the
68 * file. NULL implies a string module.
69 */
70 symchar *base_name; /* module's name including extension
71 * and WITHOUT version number. Clients
72 * should never see this.
73 */
74 FILE *f; /* module's FILE pointer. Non null when
75 * reading file, NULL otherwise---the result
76 * of calling fopen() on filename.
77 */
78 CONST char *s; /* module's string pointer. Never NULL
79 * except in creation process, destruction
80 * process or if module wraps a file instead
81 * of a string. NULL implies a file.
82 * Not a symchar pointer.
83 */
84 struct module_t *required_by; /* A pointer to the module that issued
85 * the REQUIRE statement that caused this
86 * module to be loaded.
87 * Always NULL for string modules.
88 */
89 CONST struct module_t *provided_by;
90 /* A pointer to the module that issued
91 * the PROVIDE statement that caused this
92 * module-alias to be created.
93 */
94 time_t time_last_modified; /* when filename was last modified */
95 unsigned long linenum; /* used to store line number when parsing */
96 unsigned long open_count; /* the number of times this has been opened */
97 unsigned long version; /* the module's version. Initially zero; is
98 * incremented when a module with the same
99 * name is loaded.
100 */
101 struct gl_list_t *stats; /* A pointer to a list of
102 * struct StatementList maintained at
103 * NULL or length 1. It's a gl_list
104 * so interfaces using module don't
105 * have to see all the compiler headers.
106 */
107 void *scanbuffer; /* A YY_BUFFER_STATE while the string
108 * is being parsed or in the stack.
109 * NULL otherwise.
110 */
111 };
112
113
114
115 CONST char *g_alt_ending[MOD_FILE_EXTS] = {
116 MOD_OLD_CODE,
117 MOD_OLD_LIBRARY,
118 MOD_NEW_CODE,
119 MOD_NEW_LIBRARY,
120 MOD_NEW_UNITS,
121 MOD_CATCHALL
122 };
123
124
125 /* extern */
126 struct module_t *g_current_module = NULL;
127 /**<
128 * The current module. Even though this variable is "extern",
129 * do NOT use this variable directly. Instead, use a call to
130 * Asc_CurrentModule() to get the current module.
131 */
132
133 static int g_string_modules_processed = 0;
134 /**<
135 * This is a counter, to be incremented each time it is used to
136 * create a string module name. Should not be reset to 0
137 * unless all modules have been destroyed.
138 */
139
140 static struct gl_list_t *g_module_list = NULL;
141 #define G_MODULE_LIST_INIT_SIZE 20L
142
143 /*----------
144 forward declarations
145 */
146
147 static int CmpModulesNameVers(CONST struct module_t*, CONST struct module_t*);
148 static struct module_t *FindModuleFile(CONST char *, int * CONST, int);
149 static struct module_t *CreateStringModule(CONST char *, int * CONST, CONST char *);
150 /* jds20041214 - winbase.h defines FreeModule(), so changed here to DeleteModule(). */
151 #define DeleteModule(m) ascfree(m)
152 static unsigned long ModuleNameToInternalNameVers(CONST char *, char * CONST);
153 static int ModuleSearchPath(CONST char*, char*, struct module_t*, int * CONST);
154 static struct module_t *NewModule(CONST char *);
155 static struct module_t *OpenModuleInternal(CONST char *, int * CONST,
156 int, CONST char *);
157 static void RemoveModule(CONST struct module_t *);
158 static struct module_t *SearchForModule(CONST struct module_t *);
159 static int StoreModule(CONST struct module_t *);
160 static void WriteWhyNotFound(symchar *, int);
161
162 /*------------------------------------------------------------------------------
163 MODULE HANDLING
164 */
165
166 /* see module.h for details of functions not documented here */
167
168 int Asc_InitModules(unsigned long init_size){
169 if( g_module_list != NULL ) {
170 return 0;
171 }
172 g_module_list = gl_create(init_size);
173 if( g_module_list == NULL ) {
174 FPRINTF(ASCERR,"FAILED TO CREATE MODULE LIST\n");
175 return 1;
176 }
177 return 0;
178 }
179
180
181 static DestroyFunc g_sldestroy;
182
183 static void DestroyModule(struct module_t *m){
184 if (m == NULL) return;
185 if (m->s != NULL) {
186 ascfree((char *)m->s);
187 m->s = NULL;
188 if (m->stats != NULL) {
189 gl_iterate(m->stats,g_sldestroy);
190 gl_destroy(m->stats);
191 m->stats = NULL;
192 }
193 }
194 if (m->scanbuffer!= NULL) {
195 FPRINTF(ASCERR, "Module %s being destroyed while opened by lexer\n",
196 SCP(m->name));
197 }
198 DeleteModule(m);
199 }
200
201
202 void Asc_DestroyModules(DestroyFunc f){
203 g_sldestroy = f;
204 if (g_module_list != NULL) {
205 gl_iterate(g_module_list,(DestroyFunc)DestroyModule);
206 gl_destroy( g_module_list );
207 g_module_list = NULL;
208 }
209 }
210
211
212 extern struct module_t *Asc_OpenStringModule(CONST char *inputstring,
213 int *status,
214 CONST char *prefix
215 ){
216 char *name = NULL;
217 char *keep_string;
218 int dummy;
219 int input_len;
220 struct module_t *result;
221
222 if (inputstring != NULL) {
223 /* copy and configure to string we keep for flex processing */
224 input_len = strlen(inputstring);
225 keep_string = (char *)ascmalloc(input_len+3);
226 if (keep_string != NULL) {
227 strcpy(keep_string,inputstring);
228 keep_string[++input_len] = '\0';
229 keep_string[++input_len] = '\0';
230 /* create name only if we successfully copied inputstring */
231 name = (char *)ascmalloc(strlen((prefix != NULL)? prefix : "")+35);
232 if (name != NULL) {
233 sprintf(name, "%s_global_%d", ((prefix != NULL) ? prefix : ""),
234 ++g_string_modules_processed);
235 }
236 }
237 }else{
238 keep_string = NULL;
239 }
240
241 if( status != NULL ) {
242 result = OpenModuleInternal(name, status, FALSE, keep_string);
243 } else {
244 result = OpenModuleInternal(name, &dummy, FALSE, keep_string);
245 }
246 ascfree(name);
247 return result;
248 }
249
250
251 extern struct module_t *Asc_OpenModule(CONST char *name, int *status){
252 if( status != NULL ) {
253 return OpenModuleInternal(name, status, FALSE, NULL);
254 } else {
255 int dummy;
256 return OpenModuleInternal(name, &dummy, FALSE, NULL);
257 }
258 }
259
260
261 extern struct module_t *Asc_RequireModule(CONST char *name, int *status){
262 if( status != NULL ) {
263 return OpenModuleInternal(name, status, TRUE, NULL);
264 } else {
265 int dummy;
266 return OpenModuleInternal(name, &dummy, TRUE, NULL);
267 }
268 }
269
270
271 /**
272 This function is the glue between the user callable Asc_OpenModule()
273 and Asc_RequireModule() functions and FindModuleFile(). Consult
274 those functions' documentation for more information. The
275 `do_not_overwrite' flag tells if we were called from
276 Asc_OpenModule() (==FALSE) or Asc_RequireModule() (==TRUE).
277
278 @param name filename of the module to find
279 @param status status to return to caller
280 @param do_not_overwrite Should we keep existing modules?
281 @param keep_string String we keep and parse if not NULL.
282
283 When str is NULL:
284 This function calls FindModuleFile() to find the module named `name'.
285 The status of FindModuleFile is returned to the caller in `status'.
286 If the call to FindModuleFile is successful and do_not_overwrite is
287 FALSE, we make the returned module the current module and inform
288 the scanner of the change.
289 When str is NOT NULL:
290 Calls FindModuleFile to guard against duplication, then sets up
291 module and scanner for string scanning.
292 */
293 static
294 struct module_t *OpenModuleInternal(CONST char *name,
295 int * CONST status,
296 int do_not_overwrite,
297 CONST char *keep_string)
298 {
299 struct module_t *new_module;
300
301 /*
302 * Make sure the user gave us valid data.
303 * This is valid for both string and file modules.
304 * String modules do this if user gives bad input or if
305 * malloc failed in copying string.
306 */
307 if(( name == NULL ) || ( *name == '\0' )) {
308 *status = -4;
309 return NULL;
310 }
311
312 /*
313 * Find the file and create the struct module_t
314 * or create module from string.
315 */
316 if (keep_string == NULL) {
317 new_module = FindModuleFile(name, status, do_not_overwrite);
318 if( new_module == NULL ) {
319 /* FindModuleFile set *status */
320 return NULL;
321 }
322 }else{
323 new_module = CreateStringModule(name, status, keep_string);
324 if( new_module == NULL ) {
325 /* CreateStringModule set *status */
326 return NULL;
327 }
328 }
329
330 /*
331 * Check the return status of FindModuleFile() to determine
332 * if we should tell the scanner about the module
333 */
334 if( *status == 5 ) {
335 /* We were requiring the module and it already exists, do
336 * not change the file in the scanner
337 */
338 return new_module;
339 }
340 if( *status == 4 ) {
341 /* Recursive require, do not change the files in the scanner */
342 return new_module;
343 }
344
345 /*
346 * Store the scanner's position in the current module
347 */
348 if( g_current_module != NULL ) {
349 g_current_module->linenum = LineNum();
350 }
351
352 /*
353 * Wire up the modules: push existing module onto the new
354 * module's required_by pointer
355 */
356 new_module->required_by = g_current_module;
357 g_current_module = new_module;
358
359 /*
360 * Tell the scanner to parse the new module
361 */
362 if (keep_string == NULL) {
363 Asc_ScannerAssignFile(new_module->f,1);
364 } else {
365 assert(new_module->scanbuffer != NULL);
366 Asc_ScannerAssignString(new_module->scanbuffer,1,1);
367 }
368
369 /*
370 * Return the new module
371 */
372 return new_module;
373 }
374
375
376 /**
377 Find or create a module named `name'. Return the module and put
378 an exit code in `status'. If `do_not_overwrite' is TRUE, an existing
379 module named `name' will be returned; otherwise, a new module will
380 be created, overwriting any existing module having that name.
381
382 The value put into `status' is one of:
383 -3 a memory error occurred: not enough memory to create module;
384 returning NULL
385 -2 a potential file matching module name was found but the
386 file could not be opened for reading; returning NULL
387 -1 could not find a file for the module `name'; returning NULL
388 0 a new module was successfully created and is being returned
389 1 a module with `name' already existed; the file it points to
390 does NOT match the file just found for module `name'; the old
391 module was overwritten and the new module is being returned
392 2 a module with `name' already exited; the file it points to
393 matches the file just found for module `name'; the existing
394 module is being returned
395 3 a module with `name' already existed; it was an alias for
396 for another module; the old module was overwritten and the
397 new module is being returned
398 4 a module with `name' already existed; it was being read when
399 we tried to open it again for reading (recursive require).
400 The existing module is being returned.
401 5 The argument `do_not_overwrite' is TRUE and a module named
402 `name' was found, returning it
403 */
404 static
405 struct module_t *FindModuleFile(CONST char *name,
406 int * CONST status,
407 int do_not_overwrite)
408 {
409 struct module_t *new_module; /* the newly created module */
410 struct module_t *dup = NULL; /* an existing module with the same name */
411 char filename[PATH_MAX]; /* work area to find module's filename */
412 int result; /* return value when searching for module */
413 int error; /* error number returned by fopen() or stat() */
414
415 assert(name != NULL);
416 assert(status != NULL);
417
418 /*
419 Create space for the module and set its base_name to a "proper"
420 name---i.e,, to the first character after the rightmost slash in
421 the name the user passed to us.
422 */
423 new_module = NewModule( name );
424 if( new_module == NULL ) {
425 /*FPRINTF(ASCERR,"NEW MODULE RETURNED NULL\n");*/
426 *status = -3;
427 return NULL;
428 }
429 /*FPRINTF(ASCERR,"NEW MODULE RETURNED NON-NULL\n");*/
430
431
432 /*
433 Check to see if a module having the same base_name exists.
434 If so, fetch it.
435 */
436 dup = SearchForModule( new_module );
437
438 /*
439 If were we called from RequireModule, return if a module
440 having this name already exists
441 */
442 if(( do_not_overwrite == TRUE ) && ( dup != NULL )) {
443 DeleteModule( new_module );
444 *status = 5;
445 return dup;
446 }
447
448 /*
449 Search for the module in ASCENDLIBRARY and, if found, set its
450 `f', `time_last_modified', and `line_number' fields.
451 */
452 result = ModuleSearchPath( name, filename, new_module, &error );
453
454 /*
455 Check for a memory error in ModuleSearchPath.
456 */
457 if( result == -3 ) {
458 DeleteModule( new_module );
459 *status = -4;
460 return NULL;
461 }/* else{
462 CONSOLE_DEBUG("FOUND MODULE FILE, result=%d\n",result);
463 }*/
464
465 /*
466 If we couldn't find the module or a fopen error occurred, print
467 a message and exit the function
468 */
469 if( result == -1 ) {
470 WriteWhyNotFound( new_module->filename, error );
471 DeleteModule(new_module);
472 *status = -2;
473 return NULL;
474 }
475 if( result == 1 ) {
476 ERROR_REPORTER_HERE(ASC_USER_ERROR,"Unable to locate file for module '%s'", name);
477 DeleteModule(new_module);
478 *status = -1;
479 return NULL;
480 }
481
482 /*
483 Create a symbol for the filename. We created a symbol for the
484 base_name when we created the module.
485 */
486 new_module->filename = AddSymbol(filename);
487
488 assert(new_module->f != NULL);
489
490 /*
491 If a module having the same base_name does not exist,
492 set the version number to zero, insert the new module into
493 the module list and return it.
494 */
495 if( dup == NULL ) {
496 /* no module with name 'name' exists. Save it and return */
497 new_module->open_count = 1;
498 new_module->version = 0;
499 sprintf(filename,"%s<%lu>",SCP(new_module->base_name),new_module->version);
500 /*FPRINTF(ASCERR,"SYMBOL FOR FILE IS %s\n",filename);*/
501 new_module->name = AddSymbol(filename);
502
503
504 if( StoreModule( new_module ) != 0 ) {
505 DeleteModule( new_module );
506 ERROR_REPORTER_HERE(ASC_PROG_ERROR,"COULDN'T STORE MODULE %s",new_module->filename);
507 *status = -3;
508 return NULL;
509 }
510 *status = 0;
511 return new_module;
512 }
513
514 /*
515 If the existing module's (dup) provided_by pointer is not null,
516 we are overwriting a module-alias.
517 */
518 if( dup->provided_by != NULL ) {
519 /* remove the module-alias from the module list and destroy it */
520 RemoveModule( dup );
521 DeleteModule( dup );
522 /* add the new_module to the list and return */
523 new_module->open_count = 1;
524 new_module->version = 0;
525 sprintf(filename,"%s<%lu>",SCP(new_module->base_name),new_module->version);
526 new_module->name = AddSymbol(filename);
527 if( StoreModule( new_module ) != 0 ) {
528 DeleteModule( new_module );
529 *status = -3;
530 return NULL;
531 }
532 *status = 3;
533 return new_module;
534 }
535
536 /*
537 If the existing module's (dup) file pointer `f' is not null,
538 we have some bizarre situation. Either return or PANIC.
539 */
540 if( dup->f != NULL ) {
541 if( CmpSymchar( dup->filename, new_module->filename ) != 0 ) {
542 /*
543 we were reading `dup' as if it were module `mod_name' when we
544 were told to treat `new_module' as if it were module `mod_name'.
545 PANIC!
546 */
547 fclose(dup->f);
548 fclose(new_module->f);
549 Asc_Panic(2, "FindModuleFile", "While reading file \"%s\" for module %s,"
550 "\n\treceived a request to read \"%s\" as module %s",
551 SCP(dup->filename), SCP(dup->base_name),
552 SCP(new_module->filename), SCP(new_module->base_name));
553 }
554 if( dup->time_last_modified != new_module->time_last_modified ) {
555 /* timestamp changed while reading the file. PANIC! */
556 fclose(dup->f);
557 fclose(new_module->f);
558 Asc_Panic(2, "FindModuleFile", "Timestamp on file \"%s\" changed\n"
559 "while file was open for reading", SCP(dup->filename));
560 }
561 /* recursive require! */
562 ERROR_REPORTER_HERE(ASC_USER_WARNING
563 ,"Module '%s' includes itself either directly or indirectly (ignoring)"
564 , SCP(new_module->base_name)
565 );
566 DeleteModule( new_module );
567 *status = 4;
568 return dup;
569 }
570
571 if(( CmpSymchar(dup->filename, new_module->filename) == 0 )
572 && ( dup->time_last_modified == new_module->time_last_modified ))
573 {
574 /*
575 The same module. Copy the file pointer (f) from `new_module'
576 to `dup', increment dup's open count, free `new_module', and
577 return `dup'
578 */
579 dup->f = new_module->f;
580 dup->linenum = new_module->linenum;
581 dup->open_count++;
582 DeleteModule(new_module);
583 *status = 2;
584 return dup;
585 }
586
587 /*
588 Either two different files both want to be called module `nmae',
589 or the timestamp on the file has changed. In either case, treat
590 `new_module' as a new version of `dup'.
591 */
592 new_module->open_count = 1;
593 new_module->version = 1 + dup->version;
594 sprintf(filename,"%s<%lu>",SCP(new_module->base_name),new_module->version);
595 new_module->name = AddSymbol(filename);
596 if( StoreModule( new_module ) != 0 ) {
597 DeleteModule( new_module );
598 *status = -3;
599 return NULL;
600 }
601 *status = 1;
602 return new_module;
603 }
604
605 /** Create a module named `name'. Return the module and put
606 * an exit code in `status'.
607 * Name is expected to be unique for all time (or at least until we
608 * reinit the compiler).
609 *
610 * The value put into `status' is one of (following FindModuleFile):
611 * -3 a memory error occurred: not enough memory to create module;
612 * returning NULL.
613 * -2 a potential file matching module name was found but the
614 * file could not be opened for reading; returning NULL.
615 * (never occurs).
616 * -1 could not find a file for the module `name'; returning NULL
617 * (never occurs).
618 * 0 a new module was successfully created and is being returned
619 * 1 a module with `name' already existed; the file it points to
620 * does NOT match the file just found for module `name'; the old
621 * module was overwritten and the new module is being returned
622 * (never occurs).
623 * 2 a module with `name' already exited; the file it points to
624 * matches the file just found for module `name'; the existing
625 * module is being returned
626 * (never occurs).
627 * 3 a module with `name' already existed; it was an alias for
628 * for another module; the old module was overwritten and the
629 * new module is being returned
630 * (never occurs).
631 * 4 a module with `name' already existed; it was being read when
632 * we tried to open it again for reading (recursive require).
633 * The existing module is being returned.
634 * (never occurs).
635 * 5 The argument `do_not_overwrite' is TRUE and a module named
636 * `name' was found, returning it
637 * (never occurs).
638 *
639 * In summary, only -3 and 0 are expected returns. If we decide to
640 * have some less fascist string module naming scheme, we may reinstate
641 * some of these returns.
642 */
643 static
644 struct module_t *CreateStringModule(CONST char *name,
645 int * CONST status,
646 CONST char *keep_string)
647 {
648 /* if this is 1, lots of inappropriate for string buffers code is
649 * uncommented
650 */
651 #define USE_FOR_STRINGS 0
652
653 struct module_t *new_module; /* the newly created module */
654 struct module_t *dup = NULL; /* an existing module with the same name */
655 char filename[PATH_MAX]; /* work area to find module's filename */
656 #if USE_FOR_STRINGS
657 int error; /* errno returned by fopen() or stat() */
658 int result; /* return value when searching for module */
659 #endif /* use for strings */
660
661 assert(name != NULL);
662 assert(keep_string != NULL);
663 assert(status != NULL);
664
665 /*
666 * Create space for the module and set its base_name to a "proper"
667 * name---i.e,, to the first character after the rightmost slash in
668 * the name the user passed to us.
669 */
670 new_module = NewModule( name );
671 if( new_module == NULL ) {
672 *status = -3;
673 return NULL;
674 }
675
676 /*
677 * Check to see if a module having the same base_name exists.
678 * If so, fetch it.
679 */
680 dup = SearchForModule( new_module );
681 assert(dup == NULL); /* string modules are to be unique */
682 /* probably should be ascpanic to avoid mystery messages */
683
684 #if USE_FOR_STRINGS
685 /*
686 * If were we called from RequireModule, return if a module
687 * having this name already exists
688 */
689 if(( do_not_overwrite == TRUE ) && ( dup != NULL )) {
690 DeleteModule( new_module );
691 *status = 5;
692 return dup;
693 }
694 #endif /* use for strings */
695
696
697 #if USE_FOR_STRINGS
698 /*
699 * Search for the module in ASCENDLIBRARY and, if found, set its
700 * `f', `time_last_modified', and `line_number' fields.
701 */
702 result = ModuleSearchPath( name, filename, new_module, &error );
703
704 /*
705 * Check for a memory error in ModuleSearchPath.
706 */
707 if( result == -3 ) {
708 DeleteModule( new_module );
709 *status = -3;
710 return NULL;
711 }
712
713 /*
714 * If we couldn't find the module or a fopen error occurred, print
715 * a message and exit the function
716 */
717 if( result == -1 ) {
718 WriteWhyNotFound( new_module->filename, error );
719 DeleteModule(new_module);
720 *status = -2;
721 return NULL;
722 }
723 if( result == 1 ) {
724 ERROR_REPORTER_HERE(ASC_USER_ERROR,"Unable to locate file for module '%s'", name);
725 DeleteModule(new_module);
726 *status = -1;
727 return NULL;
728 }
729
730 #else
731 new_module->s = keep_string;
732 new_module->f = NULL;
733 new_module->linenum = 1;
734 /* The following is really dumb, but should keep everyone happy.
735 * I'll be damned if I can find a function call that returns
736 * time since the epoch without some other input pointer I don't have
737 * just by looking at the man pages.
738 */
739 new_module->time_last_modified = (time_t)g_string_modules_processed;
740 #endif /* use for strings */
741
742 /*
743 * Create a symbol for the filename. We created a symbol for the
744 * base_name when we created the module.
745 */
746 #if USE_FOR_STRINGS
747 new_module->filename = AddSymbol(filename);
748 #else
749 new_module->filename = NULL;
750 #endif /* use for strings */
751
752 /*
753 * If a module having the same base_name does not exist,
754 * set the version number to zero, insert the new module into
755 * the module list and return it.
756 */
757 if( dup == NULL ) { /* always TRUE */
758 /* no module with name 'name' exists. Save it and return */
759 new_module->open_count = 1;
760 new_module->version = 0;
761 sprintf(filename,"%s<%lu>",SCP(new_module->base_name),new_module->version);
762 new_module->name = AddSymbol(filename);
763 if( StoreModule( new_module ) != 0 ) {
764 DeleteModule( new_module );
765 *status = -3;
766 return NULL;
767 }
768 new_module->scanbuffer =
769 Asc_ScannerCreateStringBuffer(keep_string,strlen(keep_string));
770 *status = 0;
771 return new_module;
772 }
773
774 #if USE_FOR_STRINGS
775 /*
776 * If the existing module's (dup) provided_by pointer is not null,
777 * we are overwriting a module-alias.
778 */
779 if( dup->provided_by != NULL ) {
780 /* remove the module-alias from the module list and destroy it */
781 RemoveModule( dup );
782 DeleteModule( dup );
783 /* add the new_module to the list and return */
784 new_module->open_count = 1;
785 new_module->version = 0;
786 sprintf(filename,"%s<%lu>",SCP(new_module->base_name),new_module->version);
787 new_module->name = AddSymbol(filename);
788 if( StoreModule( new_module ) != 0 ) {
789 DeleteModule( new_module );
790 *status = -3;
791 return NULL;
792 }
793 *status = 3;
794 return new_module;
795 }
796
797 /*
798 * If the existing module's (dup) file pointer `f' is not null,
799 * we have some bizarre situation. Either return or PANIC.
800 */
801 if( dup->f != NULL ) {
802 if( CmpSymchar( dup->filename, new_module->filename ) != 0 ) {
803 /* we were reading `dup' as if it were module `mod_name' when we
804 * were told to treat `new_module' as if it were module `mod_name'.
805 * PANIC!
806 */
807 fclose(dup->f);
808 fclose(new_module->f);
809 Asc_Panic(2, "FindModuleFile", "While reading file \"%s\" for module %s,"
810 "\n\treceived a request to read \"%s\" as module %s",
811 SCP(dup->filename), SCP(dup->base_name),
812 SCP(new_module->filename), SCP(new_module->base_name));
813 }
814 if( dup->time_last_modified != new_module->time_last_modified ) {
815 /* timestamp changed while reading the file. PANIC!
816 */
817 fclose(dup->f);
818 fclose(new_module->f);
819 Asc_Panic(2, "FindModuleFile", "Timestamp on file \"%s\" changed\n"
820 "while file was open for reading", SCP(dup->filename));
821 }
822 /* recursive require! */
823 ERROR_REPORTER_HERE(ASC_USER_WARNING
824 ,"Module %s includes itself either directly or indirectly (ignoring)"
825 , SCP(new_module->base_name)
826 );
827 DeleteModule( new_module );
828 *status = 4;
829 return dup;
830 }
831
832 if(( CmpSymchar(dup->filename, new_module->filename) == 0 )
833 && ( dup->time_last_modified == new_module->time_last_modified ))
834 {
835 /*
836 * The same module. Copy the file pointer (f) from `new_module'
837 * to `dup', increment dup's open count, free `new_module', and
838 * return `dup'
839 */
840 dup->f = new_module->f;
841 dup->linenum = new_module->linenum;
842 dup->open_count++;
843 DeleteModule(new_module);
844 *status = 2;
845 return dup;
846 }
847
848 /*
849 * Either two different files both want to be called module `nmae',
850 * or the timestamp on the file has changed. In either case, treat
851 * `new_module' as a new version of `dup'.
852 */
853 new_module->open_count = 1;
854 new_module->version = 1 + dup->version;
855 sprintf(filename,"%s<%lu>",SCP(new_module->base_name),new_module->version);
856 new_module->name = AddSymbol(filename);
857 if( StoreModule( new_module ) != 0 ) {
858 DeleteModule( new_module );
859 *status = -3;
860 return NULL;
861 }
862 *status = 1;
863 return new_module;
864 #endif /* use for strings */
865 Asc_Panic(2, "CreateStringModule", "String buffer \"%s\" misunderstood"
866 "while opening for reading", new_module->name);
867 exit(2); /* Needed to keep gcc from whining */
868 }
869
870
871 /*------------------------------------------------------------------------------
872 OPENING A MODULE FROM THE SEARCHPATH
873 */
874
875 struct ModuleSearchData{
876 struct FilePath *fp; /**< the relative path we're searching for */
877 int error; /**< error code (in case stat or fopen failed) */
878 time_t mtime; /**< mtime (from the stat command) */
879 FILE *f; /**< return the open file pointer */
880 struct stat buf;
881 struct FilePath *fp_found; /**< the full path we found */
882 };
883
884 FilePathTestFn module_searchpath_test;
885
886 /**
887 @return 1 on success
888 */
889 int module_searchpath_test(struct FilePath *path,void *searchdata){
890 struct FilePath *fp, *fp1, *fp2;
891 struct ModuleSearchData *sd;
892 FILE *f;
893 char *tmp;
894
895 sd = (struct ModuleSearchData *)searchdata;
896 assert(sd!=NULL);
897 assert(sd->fp!=NULL);
898
899 tmp = ospath_str(sd->fp);
900 /* CONSOLE_DEBUG("About to concat path '%s'...",tmp); */
901 ospath_free_str(tmp);
902
903 fp1 = ospath_concat(path,sd->fp);
904
905 tmp = ospath_str(sd->fp);
906 /* CONSOLE_DEBUG("Checking for path '%s'...",tmp); */
907 ospath_free_str(tmp);
908
909 if(ospath_stat(fp1,&sd->buf)){
910 sd->error = errno;
911 /* CONSOLE_DEBUG("Stat failed");*/
912 ospath_free(fp1);
913 return 0;
914 }
915
916 f = ospath_fopen(fp1, "r");
917 if(f==NULL){
918 sd->error = errno;
919 /* CONSOLE_DEBUG("Fopen failed"); */
920 ospath_free(fp1);
921 return 0;
922 }
923
924 sd->mtime = sd->buf.st_mtime;
925 sd->f = f;
926 sd->fp_found = fp1;
927
928 /* CONSOLE_DEBUG("File found"); */
929 return 1;
930 };
931
932
933 /**
934 This function tries to find a file corresponding to the argument
935 "name" by sending "name" to the function ModuleStatFile() which
936 will attempt to open "name" as a file. If that fails, this
937 function then prepends each entry in the search path
938 PATHENVIRONMENTVAR to "name" and attempts to open the resulting
939 file (by once again calling ModuleStatFile()).
940
941 On success, the argument "filename" will be set to the path to the
942 file, and the `f', `time_last_modified', and `linenum' members of
943 the module `m' will be set.
944
945 If ModuleStatFile() encounters an error opening the file, the
946 value of errno will be passed back to the caller in the `error'
947 argument.
948
949 @return
950 -4 Invalid partial path in parameter 'filename'.
951 -3 Memory error occurred when trying to get PATHENVIRONMENTVAR
952 -1 Error encountered in ModuleStatFile, check `error' argument
953 0 Success
954 1 Could not find a file named "name"
955 */
956 static
957 int ModuleSearchPath(CONST char *name,
958 char *filename,
959 struct module_t *m,
960 int * CONST error
961 ){
962 register size_t length;
963 int result;
964 int path_entries;
965 int j;
966 register CONST char *t;
967 struct FilePath *fp1, *fp2;
968 char *tmp;
969 struct FilePath **sp1 = NULL;
970 struct ModuleSearchData sd;
971
972 assert( name != NULL );
973 assert( filename != NULL );
974 assert( m != NULL );
975 assert( error != NULL );
976
977 /* CONSOLE_DEBUG("Launching ModuleSearchPath with '%s'",name); */
978
979 fp1 = ospath_new_noclean(name);
980 if(fp1==NULL){
981 ERROR_REPORTER_HERE(ASC_USER_ERROR,"Invalid partial path '%s'",name);
982 ospath_free(fp1);
983 return -4;
984 }
985
986 tmp = ospath_str(fp1);
987 /* CONSOLE_DEBUG("Searching for '%s'",tmp); */
988 ospath_free_str(tmp);
989
990 /* attempt to open "name" directly */
991 if(0==ospath_stat(fp1,&sd.buf) && NULL!=(sd.f = ospath_fopen(fp1,"r")) ){
992
993 CONSOLE_DEBUG("File '%s' opened directly, without path search",name);
994 sd.fp_found = fp1;
995
996 }else{
997
998 /* CONSOLE_DEBUG("ENV var name is '%s'",PATHENVIRONMENTVAR); */
999
1000 tmp = Asc_GetEnv(PATHENVIRONMENTVAR);
1001 if(tmp==NULL){
1002 ERROR_REPORTER_HERE(ASC_PROG_ERROR,"No paths to search (is env var '%s' set?)",PATHENVIRONMENTVAR);
1003 return 1;
1004 }
1005
1006 /* CONSOLE_DEBUG("ENV var value is '%s'",tmp); */
1007
1008 sp1 = ospath_searchpath_new(tmp);
1009 if(sp1==NULL){
1010 ERROR_REPORTER_HERE(ASC_PROG_ERROR,"Unable to process %s value '%s'",PATHENVIRONMENTVAR,tmp);
1011 /* memory error */
1012 ascfree(tmp);
1013 return -3;
1014 }
1015 ascfree(tmp);
1016
1017 /* CONSOLE_DEBUG("Created SP with %d elements",ospath_searchpath_length(sp1)); */
1018
1019 sd.fp = fp1;
1020
1021 fp2 = ospath_searchpath_iterate(sp1, &module_searchpath_test, &sd);
1022
1023 if(fp2==NULL){
1024 *error = sd.error;
1025 ospath_searchpath_free(sp1);
1026 CONSOLE_DEBUG("File '%s' not found in search path",name);
1027 return -1;
1028 }
1029
1030 tmp = ospath_str(fp2);
1031 ospath_searchpath_free(sp1);
1032 assert(tmp!=NULL);
1033 /* CONSOLE_DEBUG("Found file in '%s' in search path",tmp); */
1034 ospath_free_str(tmp);
1035 }
1036
1037 m->f = sd.f;
1038 m->time_last_modified = sd.mtime;
1039 m->linenum = 1;
1040 ospath_strcpy(sd.fp_found,filename,PATH_MAX);
1041 if(fp1!=sd.fp_found){
1042 ospath_free(fp1);
1043 }
1044 ospath_free(sd.fp_found);
1045 return 0; /* success */
1046 }
1047
1048
1049 /**
1050 Print an error (based on the errno `error') explaining why we could
1051 not open/stat the file named `filename'.
1052 */
1053 static
1054 void WriteWhyNotFound(symchar *filename, int error)
1055 {
1056 switch( error ) {
1057 case EACCES:
1058 ERROR_REPORTER_HERE(ASC_USER_ERROR,
1059 "File or directory permissions don't allow you to access '%s'.",
1060 SCP(filename)
1061 );
1062 break;
1063 case EFAULT:
1064 ERROR_REPORTER_HERE(ASC_USER_ERROR
1065 ,"Filename pointer or buffer pointer was bad."
1066 );
1067 break;
1068 case EIO:
1069 ERROR_REPORTER_HERE(ASC_USER_ERROR
1070 ,"I/O error in reading '%s'.",SCP(filename)
1071 );
1072 break;
1073 case ENAMETOOLONG:
1074 ERROR_REPORTER_HERE(ASC_USER_ERROR
1075 ,"The path for '%s' is too long.",SCP(filename)
1076 );
1077 break;
1078 case ENOENT:
1079 ERROR_REPORTER_HERE(ASC_USER_ERROR
1080 ,"File '%s' doesn't exist.",SCP(filename)
1081 );
1082 break;
1083 case ENOTDIR:
1084 ERROR_REPORTER_HERE(ASC_USER_ERROR
1085 ,"A component of the path name '%s' is not a directory.",SCP(filename)
1086 );
1087 break;
1088 #ifndef __WIN32__
1089 case ELOOP:
1090 /* no symlinks in windows land */
1091 ERROR_REPORTER_HERE(ASC_USER_ERROR
1092 ,"There are too many symbolic links in '%s'.",SCP(filename)
1093 );
1094 break;
1095 #endif /* __WIN32__ */
1096 default:
1097 ERROR_REPORTER_HERE(ASC_USER_ERROR
1098 ,"File not available for unknown reasons (error %d)"
1099 ,error
1100 );
1101 break;
1102 }
1103 }
1104
1105
1106 /** See the header file for this function's documentation
1107 **/
1108 extern int Asc_ModuleCreateAlias(CONST struct module_t *m, CONST char *name)
1109 {
1110 struct module_t *new_module;
1111 struct module_t *dup;
1112 char mod_name[PATH_MAX];
1113
1114 assert( m != NULL );
1115
1116 /*
1117 * Make sure the user gave us good data
1118 */
1119 if(( name == NULL ) || ( *name == '\0' )) {
1120 return -4;
1121 }
1122
1123 /*
1124 * Make sure m is not a module-alias. This shouldn't happen since
1125 * the user should not be able to get his hands on module-aliases.
1126 */
1127 if( m->provided_by != NULL ) {
1128 ERROR_REPORTER_HERE(ASC_USER_ERROR
1129 ,"Module '%s' is a module-alias. Module to alias must not be a module-alias\n"
1130 ,SCP(m->name)
1131 );
1132 return -4;
1133 }
1134
1135 /*
1136 * Create a new module or return -3 if we could not
1137 */
1138 new_module = NewModule( name );
1139 if( new_module == NULL ) {
1140 return -3;
1141 }
1142
1143 dup = SearchForModule( new_module );
1144
1145 if( dup == NULL ) {
1146 /* no module with this name exists. Set up the module-alias
1147 * and store it
1148 */
1149 new_module->provided_by = m;
1150 /* next line probably redundant */
1151 new_module->base_name = AddSymbol(SCP(new_module->base_name));
1152 new_module->version = 0;
1153 sprintf(mod_name,"%s<%lu>",SCP(new_module->base_name),new_module->version);
1154 new_module->name = AddSymbol(mod_name);
1155 if( StoreModule( new_module ) != 0 ) {
1156 DeleteModule( new_module );
1157 return -3;
1158 }
1159 return 0;
1160 }
1161
1162 /*
1163 * Check to see if a module-alias with this name already exists
1164 * that points to this module. If so, destroy the new one
1165 * silently and return.
1166 */
1167 if( dup->provided_by == m ) {
1168 DeleteModule( new_module );
1169 return 2;
1170 }
1171
1172 /*
1173 * Check to see if a module-alias with this name already exists
1174 * that points to different module. If so, check to see if the
1175 * filenames are the same. If the filename not the same, overwrite
1176 * the existing module noisly; else, overwrite it silently.
1177 */
1178 if( dup->provided_by != NULL ) {
1179 if( CmpSymchar( dup->provided_by->filename, m->filename ) != 0 ) {
1180 ERROR_REPORTER_HERE(ASC_USER_WARNING,
1181 "PROVIDE \"%s\" in file '%s' overwrites PROVIDE \"%s\" in file '%s'"
1182 ,SCP(new_module->base_name), SCP(m->filename)
1183 ,SCP(dup->base_name), SCP(dup->provided_by->filename)
1184 );
1185 }
1186 RemoveModule( dup );
1187 DeleteModule( dup );
1188 new_module->provided_by = m;
1189 /* probably redundant addsymbol next line */
1190 new_module->base_name = AddSymbol(SCP(new_module->base_name));
1191 new_module->version = 0;
1192 sprintf(mod_name,"%s<%lu>",SCP(new_module->base_name),new_module->version);
1193 new_module->name = AddSymbol(mod_name);
1194 if( StoreModule( new_module ) != 0 ) {
1195 DeleteModule( new_module );
1196 return -3;
1197 }
1198 return 3;
1199 }
1200
1201 /*
1202 * Check to see if the duplicate module is actually the current
1203 * module---i.e., module ``foo.a4c'' contains the statement
1204 * ``PROVIDE "foo.a4c";'' If so, destroy the new_module silently.
1205 */
1206 if( dup == g_current_module ) {
1207 DeleteModule( new_module );
1208 return 1;
1209 }
1210
1211 /*
1212 * If we made it here, we attempting to PROVIDE a real module that
1213 * already exists. Issue an error, destroy the new_module, and
1214 * return.
1215 */
1216 ERROR_REPORTER_HERE(ASC_USER_ERROR,
1217 "File \"%s\" cannot PROVIDE '%s' because a module with that name already exists (%s)."
1218 , SCP(m->filename), SCP(new_module->base_name), SCP(dup->name)
1219 );
1220 DeleteModule( new_module );
1221 return -2;
1222 }
1223
1224 /**
1225 Allocate space for a new module and set its fields to some
1226 reasonable defaults. If `name' is not NULL, set the module's
1227 base_name to point to the first character after the rightmost
1228 slash (`/' on UNIX, `/' on Windows) in `name', or to `name' if
1229 it contains no slashes. Note that this function will create
1230 a symbol for base_name. Return NULL if malloc fails.
1231 */
1232 static
1233 struct module_t *NewModule(CONST char *name){
1234 struct module_t *newmodule; /* the new module */
1235 char *tmp; /* result of strrchr(); used to get base_name */
1236 struct FilePath *fp1;
1237
1238 newmodule = (struct module_t *)ascmalloc(sizeof(struct module_t));
1239 if( newmodule == NULL ) {
1240 ERROR_REPORTER_HERE(ASC_PROG_ERR,"UNABLE TO MALLOC FOR NEW MODULE");
1241 return NULL;
1242 }
1243 newmodule->name = NULL;
1244 newmodule->filename = NULL;
1245 newmodule->f = NULL;
1246 newmodule->s = NULL;
1247 newmodule->stats = NULL;
1248 newmodule->scanbuffer = NULL;
1249 newmodule->required_by = NULL;
1250 newmodule->provided_by = NULL;
1251 newmodule->time_last_modified = (time_t)0;
1252 newmodule->linenum = 0;
1253 newmodule->open_count = 0;
1254 newmodule->version = ULONG_MAX;
1255
1256 /* CONSOLE_DEBUG("New path: %s",name); */
1257 fp1 = ospath_new(name);
1258 tmp = ospath_getbasefilename(fp1);
1259 if(tmp!=NULL && strlen(tmp)!=0){
1260 newmodule->base_name = AddSymbol(tmp);
1261 }
1262 ospath_free(fp1);
1263
1264 /* CONSOLE_DEBUG("Module base-name: %s",newmodule->base_name); */
1265 return newmodule;
1266 }
1267
1268 /*------------------------------------------------------------------------------
1269 GLOBAL MODULE LIST MANAGEMENT
1270
1271 * The following four functions are used to store, remove, and search
1272 * for modules in the global module list, the gl_list `g_module_list'.
1273 * We do this (instead of inlining the calls to gl_*()) to provide a
1274 * bit of data abstraction, though I'm sure there are some implicit
1275 * assumptions in the code as to how modules are stored on the gl_list.
1276 *
1277 * These functions handle a NULL g_module_list gracefully.
1278 *
1279 * Modules are appended to the g_module_list in the order they are
1280 * OPENED, so later versions of the same file appear toward the end of
1281 * the list. Note that a module in the back of the list may define
1282 * types needed by module at the front of the list, due to the magic of
1283 * the REQUIRE statement.
1284 *
1285 * Since the modules are in the order opened, implementing a
1286 * Re-Read-All-Files function wouldn't be too difficult, but the
1287 * REQUIRE statements in each file would still have to be followed.
1288 *
1289 * Since module-aliases are implemented as modules and are stored on
1290 * the g_module_list, they must sometimes be replaced by actual
1291 * modules or new module-aliases. When this occurs, a module-alias
1292 * must be removed from the g_module_list.
1293 *
1294 * When searching for a module, we start at the end of the list and
1295 * move towards the front. The comparison function looks for the
1296 * base-names to be equal and for the version number of the found
1297 * module being less than or equal to the version number of the module
1298 * passed into the SearchForModule() function. The comparison
1299 * function uses less than or equal for the version number because one
1300 * doesn't know the version number of the most recently read version.
1301 * By setting the version number in the module passed to
1302 * SearchForModule() to be ULONG_MAX, you will get the first module
1303 * where the base-names match, which should be the most recently read
1304 * version of that module.
1305 *-------------------------------------------------
1306 */
1307
1308
1309 /** Store `m' in the global module gl_list `g_module_list', creating
1310 * the g_module_list if needed. Return 0 for success or 1 if the
1311 * g_module_list could not be created.
1312 *
1313 * Storing `m' in g_module_list simply appends it to the list.
1314 */
1315 static
1316 int StoreModule(CONST struct module_t *m)
1317 {
1318 /* initialize the global module list if required */
1319 if((g_module_list==NULL) && (Asc_InitModules(G_MODULE_LIST_INIT_SIZE)!=0)) {
1320 ERROR_REPORTER_HERE(ASC_PROG_ERR,"FAILED TO ASC_INITMODULES");
1321 return 1;
1322 }
1323 gl_append_ptr( g_module_list, (VOIDPTR)m );
1324 return 0;
1325 }
1326
1327
1328 /** Remove `m' from the global module gl_list `g_module_list'.
1329 *
1330 * This function searches backwards through g_module_list and uses
1331 * CmpModulesNameVers() to determine which module to remove.
1332 */
1333 static
1334 void RemoveModule(CONST struct module_t *m)
1335 {
1336 unsigned long place;
1337
1338 if( g_module_list == NULL ) {
1339 return;
1340 }
1341 place = gl_search_reverse( g_module_list, m, (CmpFunc)CmpModulesNameVers );
1342 if( place == 0 ) {
1343 return;
1344 }
1345 gl_delete( g_module_list, place, 0 );
1346 return;
1347 }
1348
1349
1350 /** Search for `m' in the global module gl_list `g_module_list'
1351 * and return it. Return the matching module or NULL if no matching
1352 * module exists or if the g_module_list is empty.
1353 *
1354 * This function searches backwards through g_module_list and uses
1355 * CmpModulesNameVers() to determine which module return.
1356 */
1357 static
1358 struct module_t *SearchForModule(CONST struct module_t *m)
1359 {
1360 unsigned long place;
1361
1362 assert(m != NULL);
1363
1364 if( g_module_list == NULL ) {
1365 return NULL;
1366 }
1367
1368 place = gl_search_reverse( g_module_list, m, (CmpFunc)CmpModulesNameVers );
1369 if( place == 0 ) {
1370 return NULL;
1371 }
1372 return gl_fetch( g_module_list, place );
1373 }
1374
1375
1376 /** Compare the base_names and version numbers of the modules
1377 * `m1' and `m2'.
1378 * Return:
1379 * >0 m1->base_name > m2->base_name
1380 * || (m1->base_name == m2->base_name
1381 * && m1->version > m2->version)
1382 * <0 m1->base_name < m2->base_name
1383 * 0 m1->base_name == m2->base_name
1384 * && m1->version <= m2->version
1385 */
1386 static
1387 int CmpModulesNameVers(CONST struct module_t *m1, CONST struct module_t *m2)
1388 {
1389 int result;
1390
1391 if( (result = CmpSymchar(m1->base_name, m2->base_name)) != 0 ) {
1392 return result;
1393 }
1394 if( m1->version > m2->version ) {
1395 return 1;
1396 }
1397 return 0;
1398 }
1399
1400
1401
1402 extern int Asc_CloseCurrentModule(void){
1403 struct module_t *prev;
1404
1405 /*
1406 * If no current module, return TRUE
1407 */
1408 if (g_current_module == NULL) {
1409 return TRUE;
1410 }
1411
1412 /*
1413 * Store the scanner's position in the current module
1414 */
1415 g_current_module->linenum = LineNum();
1416
1417 /*
1418 * Close the current module's file or buffer.
1419 */
1420 if (g_current_module->f != NULL) {
1421 fclose(g_current_module->f);
1422 g_current_module->f = NULL;
1423 } else {
1424 assert(g_current_module->s != NULL);
1425 Asc_ScannerReleaseStringBuffer(g_current_module->scanbuffer);
1426 g_current_module->scanbuffer = NULL;
1427 }
1428
1429 /*
1430 * Pop the module that REQUIRED the current module so
1431 * it becomes the current module
1432 */
1433 prev = g_current_module->required_by;
1434 g_current_module->required_by = NULL; /* unlink it */
1435 g_current_module = prev;
1436
1437 /*
1438 * No more modules
1439 */
1440 if (g_current_module == NULL) {
1441 return TRUE;
1442 }
1443
1444 /*
1445 * Inform the scanner after pop
1446 */
1447 if (g_current_module->s == NULL) {
1448 Asc_ScannerAssignFile(g_current_module->f,g_current_module->linenum);
1449 } else {
1450 assert(g_current_module->scanbuffer != NULL);
1451 Asc_ScannerAssignString(g_current_module->scanbuffer,
1452 g_current_module->linenum,0);
1453 }
1454 return FALSE;
1455 }
1456
1457
1458 int Asc_ModuleAddStatements(struct module_t *m, struct gl_list_t *l)
1459 {
1460 if (l == NULL || gl_length(l) == 0 ||
1461 m == NULL || m->s == NULL || m->f != NULL) {
1462 return -1;
1463 /* list is empty or module is not a string module.
1464 * caller should dump l and contents.
1465 */
1466 }
1467 if (m->stats == NULL) {
1468 m->stats = l;
1469 /* we're keeping list and contents. */
1470 return 0;
1471 } else {
1472 gl_append_list(m->stats,l);
1473 /* we're keeping contents but not list. caller should destroy l. */
1474 return 1;
1475 }
1476 }
1477
1478
1479 extern CONST struct module_t *Asc_GetModuleByName(CONST char *module_name){
1480 char name[PATH_MAX];
1481 unsigned long vers;
1482 struct module_t *mod;
1483 struct module_t *result;
1484
1485 if( g_module_list == NULL ) {
1486 return NULL;
1487 }
1488
1489 /*
1490 * Convert the given name to an base name and version
1491 */
1492 vers = ModuleNameToInternalNameVers(module_name, name);
1493 if( vers == ULONG_MAX ) {
1494 ERROR_REPORTER_HERE(ASC_PROG_ERR
1495 ,"Bad format for module name %s, no version number found."
1496 ,name
1497 );
1498 return NULL;
1499 }
1500
1501 /*
1502 * Create a new module with this name and version---needed to
1503 * call SearchForModule()
1504 */
1505 mod = NewModule( name );
1506 if( mod == NULL ) {
1507 return NULL;
1508 }
1509 mod->version = vers;
1510
1511 /*
1512 * Search for the module and free the module we used for searching.
1513 */
1514 result = SearchForModule( mod );
1515 DeleteModule( mod );
1516
1517 /*
1518 * If result is a module-alias, return the module that PROVIDED it
1519 */
1520 if(( result != NULL ) && ( result->provided_by != NULL )) {
1521 return result->provided_by;
1522 }
1523 return result;
1524 }
1525
1526
1527 /**
1528 * Parse the module name given in `module_name' (e.g., "foo.a4c<0>")
1529 * into an base name and a version number. Copy the base_name
1530 * into the string `name' and use the version number as the return
1531 * value. Leading and trailing whitespace on `module_name' is removed.
1532 *
1533 * If `module_name' does not contain a valid module name, return
1534 * ULONG_MAX.
1535 */
1536 static
1537 unsigned long ModuleNameToInternalNameVers(CONST char *module_name,
1538 char * CONST name)
1539 {
1540 unsigned int t;
1541 unsigned long vers = ULONG_MAX;
1542
1543 assert( name != NULL );
1544
1545 /*
1546 * Make sure we got good data
1547 */
1548 if(( module_name == NULL ) || ( *module_name == '\0' )) {
1549 return vers;
1550 }
1551
1552 /*
1553 * Ignore leading whitespace
1554 */
1555 while( isspace(*module_name) ) {
1556 module_name++;
1557 }
1558
1559 /*
1560 * Copy all of module_name into name
1561 */
1562 for( t = 0 ; ((name[t] = module_name[t]) != '\0') ; t++ );
1563
1564 /*
1565 * Remove trailing whitespace
1566 * Use t>1 in the while since we decrement t twice before we
1567 * check it again and we don't want to fall off the front of
1568 * the string.
1569 */
1570 while(( t > 1 ) && ( isspace(name[--t]) ));
1571
1572 /*
1573 * Check for '>' preceded by a number
1574 */
1575 if(( name[t] != '>' ) || ( ! isdigit(name[--t]) )) {
1576 return vers;
1577 }
1578
1579 /*
1580 * Back up over all the digits that make up the version number
1581 * Use t>1 in while since a valid base name has to have
1582 * at least one character.
1583 */
1584 while(( t > 1 ) && ( isdigit(name[--t]) ));
1585
1586 /*
1587 * Make sure we have a '<'
1588 */
1589 if( name[t] != '<' ) {
1590 return vers;
1591 }
1592
1593 /*
1594 * Convert the '<' to '\0' since this is where the name ends
1595 */
1596 name[t] = '\0';
1597
1598 /*
1599 * Covert the number to an unsigned long in base 10
1600 */
1601 vers = strtoul( (name + t + 1), NULL, 10 );
1602 if( vers == ULONG_MAX ) {
1603 return vers;
1604 }
1605
1606 return vers;
1607 }
1608
1609 CONST char *Asc_ModuleString(CONST struct module_t *m)
1610 {
1611 if (m==NULL) return NULL;
1612 return m->s;
1613 }
1614
1615 struct gl_list_t *Asc_ModuleStatementLists(CONST struct module_t *m)
1616 {
1617 if (m==NULL) return NULL;
1618 return m->stats;
1619 }
1620
1621
1622
1623 extern struct gl_list_t *Asc_ModuleList(int module_type){
1624 struct gl_list_t *new = NULL;
1625 struct module_t *m;
1626 struct gl_list_t *types = NULL;
1627 unsigned long c;
1628 unsigned long length;
1629
1630 if( g_module_list == NULL ) {
1631 return NULL;
1632 }
1633 length = gl_length(g_module_list);
1634 new = gl_create(length);
1635 if( new == NULL ) {
1636 return NULL;
1637 }
1638 for( c = length; c > 0; c-- ) {
1639 m = (struct module_t *)gl_fetch(g_module_list, c);
1640 switch (module_type) {
1641 case 0:
1642 types = Asc_TypeByModule(m);
1643 if( types != NULL ) {
1644 if( gl_length(types) > 0L ) {
1645 gl_append_ptr(new, (VOIDPTR)(m->name));
1646 }
1647 gl_destroy(types);
1648 types = NULL;
1649 }
1650 break;
1651 case 1:
1652 if (m != NULL && m->s != NULL) {
1653 gl_append_ptr(new, (VOIDPTR)(m->name));
1654 }
1655 break;
1656 case 2:
1657 if (m != NULL && m->stats != NULL) {
1658 gl_append_ptr(new, (VOIDPTR)(m->name));
1659 }
1660 break;
1661 default:
1662 break;
1663 }
1664 }
1665 return new;
1666 }
1667
1668
1669 extern void Asc_ModuleWrite(FILE *f, CONST struct module_t *m){
1670 assert(m!=NULL);
1671 FPRINTF(f,"MODULE: %s\nFILENAME: %s\n",SCP(m->name),SCP(m->filename));
1672 FPRINTF(f,(m->f!=NULL)?"OPEN\n":"CLOSED\n");
1673 FPRINTF(f,"FILE DATE: %s",asctime(localtime( &(m->time_last_modified) )));
1674 }
1675
1676
1677 extern struct module_t *Asc_CurrentModuleF(void){
1678 return g_current_module;
1679 }
1680
1681
1682 extern CONST char *Asc_ModuleName(CONST struct module_t *m){
1683 return (( m != NULL ) ? SCP(m->name) : "");
1684 }
1685
1686
1687 extern CONST char *Asc_ModuleFileName(CONST struct module_t *m){
1688 return ((m != NULL) ? SCP(m->filename) : "");
1689 }
1690
1691 extern CONST char *Asc_ModuleBestName(CONST struct module_t *m){
1692 static char unk[] = "<UNKNOWN>";
1693 if (m == NULL) return "";
1694 if (SCP(m->filename) != NULL) return SCP(m->filename);
1695 if (SCP(m->name)!=NULL) return SCP(m->name);
1696 return unk;
1697 }
1698
1699
1700 extern unsigned long Asc_ModuleTimesOpened(CONST struct module_t *m){
1701 return ((m != NULL) ? (m->open_count) : 0);
1702 }
1703
1704
1705 extern struct tm *Asc_ModuleTimeModified(CONST struct module_t *m){
1706 return ((m != NULL) ? localtime(&(m->time_last_modified)) : NULL);
1707 }
1708
1709 extern int Asc_ModuleStringIndex(CONST struct module_t *m){
1710 return ((m != NULL) ? (int)(m->time_last_modified) : -1);
1711 }

john.pye@anu.edu.au
ViewVC Help
Powered by ViewVC 1.1.22