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

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