/[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 1051 - (show annotations) (download) (as text)
Sat Jan 6 04:08:29 2007 UTC (15 years, 11 months ago) by johnpye
File MIME type: text/x-csrc
File size: 51683 byte(s)
Changing to asc_assert in module.c
Changing WriteWhyNotFound to use char* instead of symchar*.
Fixing paths in models/steam/* to be relative to models/
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(char *, 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 asc_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 asc_assert(name != NULL);
402 asc_assert(status != NULL);
403 asc_assert(strcmp(name,"")!=0);
404
405 /*
406 Create space for the module and set its base_name to a "proper"
407 name---i.e,, to the first character after the rightmost slash in
408 the name the user passed to us.
409 */
410 new_module = NewModule( name );
411 if( new_module == NULL ) {
412 /*FPRINTF(ASCERR,"NEW MODULE RETURNED NULL\n");*/
413 *status = -3;
414 return NULL;
415 }
416 /*FPRINTF(ASCERR,"NEW MODULE RETURNED NON-NULL\n");*/
417
418
419 /*
420 Check to see if a module having the same base_name exists.
421 If so, fetch it.
422 */
423 dup = SearchForModule(new_module);
424
425 if(dup){
426 CONSOLE_DEBUG("Duplicate module named '%s' was found"
427 ,SCP(new_module->base_name)
428 );
429 }
430
431 /*
432 If we were called from RequireModule, return if a module
433 having this name already exists
434 */
435 if(( do_not_overwrite == TRUE ) && ( dup != NULL )) {
436 DeleteModule( new_module );
437 *status = 5;
438 return dup;
439 }
440
441 /*
442 Search for the module in ASCENDLIBRARY and, if found, set its
443 `f', `time_last_modified', and `line_number' fields.
444 */
445 result = ModuleSearchPath( name, filename, new_module, &error );
446
447 /*
448 Check for a memory error in ModuleSearchPath.
449 */
450 if( result == -3 ) {
451 DeleteModule( new_module );
452 *status = -4;
453 return NULL;
454 }/* else{
455 CONSOLE_DEBUG("FOUND MODULE FILE, result=%d\n",result);
456 }*/
457
458 /*
459 If we couldn't find the module or a fopen error occurred, print
460 a message and exit the function
461 */
462 if( result == -1 ) {
463 CONSOLE_DEBUG("ModuleSearchPath returned -1, name=%s, filename=%s",name,filename);
464 WriteWhyNotFound(name, error);
465 DeleteModule(new_module);
466 *status = -2;
467 return NULL;
468 }
469 if( result == 1 ) {
470 ERROR_REPORTER_HERE(ASC_USER_ERROR,"Unable to locate file for module '%s'", name);
471 DeleteModule(new_module);
472 *status = -1;
473 return NULL;
474 }
475
476 /*
477 Create a symbol for the filename. We created a symbol for the
478 base_name when we created the module.
479 */
480 new_module->filename = AddSymbol(filename);
481
482 asc_assert(new_module->f != NULL);
483
484 /*
485 If a module having the same base_name does not exist,
486 set the version number to zero, insert the new module into
487 the module list and return it.
488 */
489 if( dup == NULL ) {
490 /* no module with name 'name' exists. Save it and return */
491 new_module->open_count = 1;
492 new_module->version = 0;
493 sprintf(filename,"%s<%lu>",SCP(new_module->base_name),new_module->version);
494 /*FPRINTF(ASCERR,"SYMBOL FOR FILE IS %s\n",filename);*/
495 new_module->name = AddSymbol(filename);
496
497
498 if( StoreModule( new_module ) != 0 ) {
499 DeleteModule( new_module );
500 ERROR_REPORTER_HERE(ASC_PROG_ERROR,"COULDN'T STORE MODULE %s",new_module->filename);
501 *status = -3;
502 return NULL;
503 }
504 *status = 0;
505 return new_module;
506 }
507
508 /*
509 If the existing module's (dup) provided_by pointer is not null,
510 we are overwriting a module-alias.
511 */
512 if( dup->provided_by != NULL ) {
513 /* remove the module-alias from the module list and destroy it */
514 RemoveModule( dup );
515 DeleteModule( dup );
516 /* add the new_module to the list and return */
517 new_module->open_count = 1;
518 new_module->version = 0;
519 sprintf(filename,"%s<%lu>",SCP(new_module->base_name),new_module->version);
520 new_module->name = AddSymbol(filename);
521 if( StoreModule( new_module ) != 0 ) {
522 DeleteModule( new_module );
523 *status = -3;
524 return NULL;
525 }
526 *status = 3;
527 return new_module;
528 }
529
530 /*
531 If the existing module's (dup) file pointer `f' is not null,
532 we have some bizarre situation. Either return or PANIC.
533 */
534 if( dup->f != NULL ) {
535 if( CmpSymchar( dup->filename, new_module->filename ) != 0 ) {
536 /*
537 we were reading `dup' as if it were module `mod_name' when we
538 were told to treat `new_module' as if it were module `mod_name'.
539 PANIC!
540 */
541 fclose(dup->f);
542 fclose(new_module->f);
543 Asc_Panic(2, "FindModuleFile", "While reading file \"%s\" for module %s,"
544 "\n\treceived a request to read \"%s\" as module %s",
545 SCP(dup->filename), SCP(dup->base_name),
546 SCP(new_module->filename), SCP(new_module->base_name));
547 }
548 if( dup->time_last_modified != new_module->time_last_modified ) {
549 /* timestamp changed while reading the file. PANIC! */
550 fclose(dup->f);
551 fclose(new_module->f);
552 Asc_Panic(2, "FindModuleFile", "Timestamp on file \"%s\" changed\n"
553 "while file was open for reading", SCP(dup->filename));
554 }
555 /* recursive require! */
556 ERROR_REPORTER_HERE(ASC_USER_WARNING
557 ,"Module '%s' includes itself either directly or indirectly (ignoring)"
558 , SCP(new_module->base_name)
559 );
560 DeleteModule( new_module );
561 *status = 4;
562 return dup;
563 }
564
565 if(( CmpSymchar(dup->filename, new_module->filename) == 0 )
566 && ( dup->time_last_modified == new_module->time_last_modified ))
567 {
568 /*
569 The same module. Copy the file pointer (f) from `new_module'
570 to `dup', increment dup's open count, free `new_module', and
571 return `dup'
572 */
573 dup->f = new_module->f;
574 dup->linenum = new_module->linenum;
575 dup->open_count++;
576 DeleteModule(new_module);
577 *status = 2;
578 return dup;
579 }
580
581 /*
582 Either two different files both want to be called module `nmae',
583 or the timestamp on the file has changed. In either case, treat
584 `new_module' as a new version of `dup'.
585 */
586 new_module->open_count = 1;
587 new_module->version = 1 + dup->version;
588 sprintf(filename,"%s<%lu>",SCP(new_module->base_name),new_module->version);
589 new_module->name = AddSymbol(filename);
590 if( StoreModule( new_module ) != 0 ) {
591 DeleteModule( new_module );
592 *status = -3;
593 return NULL;
594 }
595 *status = 1;
596 return new_module;
597 }
598
599 /** Create a module named `name'. Return the module and put
600 * an exit code in `status'.
601 * Name is expected to be unique for all time (or at least until we
602 * reinit the compiler).
603 *
604 * The value put into `status' is one of (following FindModuleFile):
605 * -3 a memory error occurred: not enough memory to create module;
606 * returning NULL.
607 * -2 a potential file matching module name was found but the
608 * file could not be opened for reading; returning NULL.
609 * (never occurs).
610 * -1 could not find a file for the module `name'; returning NULL
611 * (never occurs).
612 * 0 a new module was successfully created and is being returned
613 * 1 a module with `name' already existed; the file it points to
614 * does NOT match the file just found for module `name'; the old
615 * module was overwritten and the new module is being returned
616 * (never occurs).
617 * 2 a module with `name' already exited; the file it points to
618 * matches the file just found for module `name'; the existing
619 * module is being returned
620 * (never occurs).
621 * 3 a module with `name' already existed; it was an alias for
622 * for another module; the old module was overwritten and the
623 * new module is being returned
624 * (never occurs).
625 * 4 a module with `name' already existed; it was being read when
626 * we tried to open it again for reading (recursive require).
627 * The existing module is being returned.
628 * (never occurs).
629 * 5 The argument `do_not_overwrite' is TRUE and a module named
630 * `name' was found, returning it
631 * (never occurs).
632 *
633 * In summary, only -3 and 0 are expected returns. If we decide to
634 * have some less fascist string module naming scheme, we may reinstate
635 * some of these returns.
636 */
637 static
638 struct module_t *CreateStringModule(CONST char *name,
639 int * CONST status,
640 CONST char *keep_string)
641 {
642 /* if this is 1, lots of inappropriate for string buffers code is
643 * uncommented
644 */
645 #define USE_FOR_STRINGS 0
646
647 struct module_t *new_module; /* the newly created module */
648 struct module_t *dup = NULL; /* an existing module with the same name */
649 char filename[PATH_MAX]; /* work area to find module's filename */
650 #if USE_FOR_STRINGS
651 int error; /* errno returned by fopen() or stat() */
652 int result; /* return value when searching for module */
653 #endif /* use for strings */
654
655 asc_assert(name != NULL);
656 asc_assert(keep_string != NULL);
657 asc_assert(status != NULL);
658
659 /*
660 * Create space for the module and set its base_name to a "proper"
661 * name---i.e,, to the first character after the rightmost slash in
662 * the name the user passed to us.
663 */
664 new_module = NewModule( name );
665 if( new_module == NULL ) {
666 *status = -3;
667 return NULL;
668 }
669
670 /*
671 * Check to see if a module having the same base_name exists.
672 * If so, fetch it.
673 */
674 dup = SearchForModule( new_module );
675 asc_assert(dup == NULL); /* string modules are to be unique */
676 /* probably should be ascpanic to avoid mystery messages */
677
678 #if USE_FOR_STRINGS
679 /*
680 * If were we called from RequireModule, return if a module
681 * having this name already exists
682 */
683 if(( do_not_overwrite == TRUE ) && ( dup != NULL )) {
684 DeleteModule( new_module );
685 *status = 5;
686 return dup;
687 }
688 #endif /* use for strings */
689
690
691 #if USE_FOR_STRINGS
692 /*
693 * Search for the module in ASCENDLIBRARY and, if found, set its
694 * `f', `time_last_modified', and `line_number' fields.
695 */
696 result = ModuleSearchPath( name, filename, new_module, &error );
697
698 /*
699 * Check for a memory error in ModuleSearchPath.
700 */
701 if( result == -3 ) {
702 DeleteModule( new_module );
703 *status = -3;
704 return NULL;
705 }
706
707 /*
708 * If we couldn't find the module or a fopen error occurred, print
709 * a message and exit the function
710 */
711 if( result == -1 ) {
712 CONSOLE_DEBUG("ModuleSearchPath returned -1, name=%s, filename=%s",name,filename);
713 WriteWhyNotFound(filename, error );
714 DeleteModule(new_module);
715 *status = -2;
716 return NULL;
717 }
718 if( result == 1 ) {
719 ERROR_REPORTER_HERE(ASC_USER_ERROR,"Unable to locate file for module '%s'", name);
720 DeleteModule(new_module);
721 *status = -1;
722 return NULL;
723 }
724
725 #else
726 new_module->s = keep_string;
727 new_module->f = NULL;
728 new_module->linenum = 1;
729 /* The following is really dumb, but should keep everyone happy.
730 * I'll be damned if I can find a function call that returns
731 * time since the epoch without some other input pointer I don't have
732 * just by looking at the man pages.
733 */
734 new_module->time_last_modified = (time_t)g_string_modules_processed;
735 #endif /* use for strings */
736
737 /*
738 * Create a symbol for the filename. We created a symbol for the
739 * base_name when we created the module.
740 */
741 #if USE_FOR_STRINGS
742 new_module->filename = AddSymbol(filename);
743 #else
744 new_module->filename = NULL;
745 #endif /* use for strings */
746
747 /*
748 * If a module having the same base_name does not exist,
749 * set the version number to zero, insert the new module into
750 * the module list and return it.
751 */
752 if( dup == NULL ) { /* always TRUE */
753 /* no module with name 'name' exists. Save it and return */
754 new_module->open_count = 1;
755 new_module->version = 0;
756 sprintf(filename,"%s<%lu>",SCP(new_module->base_name),new_module->version);
757 new_module->name = AddSymbol(filename);
758 if( StoreModule( new_module ) != 0 ) {
759 DeleteModule( new_module );
760 *status = -3;
761 return NULL;
762 }
763 new_module->scanbuffer =
764 Asc_ScannerCreateStringBuffer(keep_string,strlen(keep_string));
765 *status = 0;
766 return new_module;
767 }
768
769 #if USE_FOR_STRINGS
770 /*
771 * If the existing module's (dup) provided_by pointer is not null,
772 * we are overwriting a module-alias.
773 */
774 if( dup->provided_by != NULL ) {
775 /* remove the module-alias from the module list and destroy it */
776 RemoveModule( dup );
777 DeleteModule( dup );
778 /* add the new_module to the list and return */
779 new_module->open_count = 1;
780 new_module->version = 0;
781 sprintf(filename,"%s<%lu>",SCP(new_module->base_name),new_module->version);
782 new_module->name = AddSymbol(filename);
783 if( StoreModule( new_module ) != 0 ) {
784 DeleteModule( new_module );
785 *status = -3;
786 return NULL;
787 }
788 *status = 3;
789 return new_module;
790 }
791
792 /*
793 * If the existing module's (dup) file pointer `f' is not null,
794 * we have some bizarre situation. Either return or PANIC.
795 */
796 if( dup->f != NULL ) {
797 if( CmpSymchar( dup->filename, new_module->filename ) != 0 ) {
798 /* we were reading `dup' as if it were module `mod_name' when we
799 * were told to treat `new_module' as if it were module `mod_name'.
800 * PANIC!
801 */
802 fclose(dup->f);
803 fclose(new_module->f);
804 Asc_Panic(2, "FindModuleFile", "While reading file \"%s\" for module %s,"
805 "\n\treceived a request to read \"%s\" as module %s",
806 SCP(dup->filename), SCP(dup->base_name),
807 SCP(new_module->filename), SCP(new_module->base_name));
808 }
809 if( dup->time_last_modified != new_module->time_last_modified ) {
810 /* timestamp changed while reading the file. PANIC!
811 */
812 fclose(dup->f);
813 fclose(new_module->f);
814 Asc_Panic(2, "FindModuleFile", "Timestamp on file \"%s\" changed\n"
815 "while file was open for reading", SCP(dup->filename));
816 }
817 /* recursive require! */
818 ERROR_REPORTER_HERE(ASC_USER_WARNING
819 ,"Module %s includes itself either directly or indirectly (ignoring)"
820 , SCP(new_module->base_name)
821 );
822 DeleteModule( new_module );
823 *status = 4;
824 return dup;
825 }
826
827 if(( CmpSymchar(dup->filename, new_module->filename) == 0 )
828 && ( dup->time_last_modified == new_module->time_last_modified ))
829 {
830 /*
831 * The same module. Copy the file pointer (f) from `new_module'
832 * to `dup', increment dup's open count, free `new_module', and
833 * return `dup'
834 */
835 dup->f = new_module->f;
836 dup->linenum = new_module->linenum;
837 dup->open_count++;
838 DeleteModule(new_module);
839 *status = 2;
840 return dup;
841 }
842
843 /*
844 * Either two different files both want to be called module `nmae',
845 * or the timestamp on the file has changed. In either case, treat
846 * `new_module' as a new version of `dup'.
847 */
848 new_module->open_count = 1;
849 new_module->version = 1 + dup->version;
850 sprintf(filename,"%s<%lu>",SCP(new_module->base_name),new_module->version);
851 new_module->name = AddSymbol(filename);
852 if( StoreModule( new_module ) != 0 ) {
853 DeleteModule( new_module );
854 *status = -3;
855 return NULL;
856 }
857 *status = 1;
858 return new_module;
859 #endif /* use for strings */
860 Asc_Panic(2, "CreateStringModule", "String buffer \"%s\" misunderstood"
861 "while opening for reading", new_module->name);
862
863 }
864
865
866 /*------------------------------------------------------------------------------
867 OPENING A MODULE FROM THE SEARCHPATH
868 */
869
870 struct ModuleSearchData{
871 struct FilePath *fp; /**< the relative path we're searching for */
872 int error; /**< error code (in case stat or fopen failed) */
873 time_t mtime; /**< mtime (from the stat command) */
874 FILE *f; /**< return the open file pointer */
875 ospath_stat_t buf;
876 struct FilePath *fp_found; /**< the full path we found */
877 };
878
879 FilePathTestFn module_searchpath_test;
880
881 /**
882 @return 1 on success
883 */
884 int module_searchpath_test(struct FilePath *path,void *searchdata){
885 struct FilePath *fp1;
886 struct ModuleSearchData *sd;
887 FILE *f;
888 /*char *tmp;*/
889
890 sd = (struct ModuleSearchData *)searchdata;
891 asc_assert(sd!=NULL);
892 asc_assert(sd->fp!=NULL);
893
894
895 /*
896 tmp=ospath_str(sd->fp);
897 CONSOLE_DEBUG("About to concat path '%s'...",tmp);
898 ospath_free_str(tmp);
899 */
900
901 fp1 = ospath_concat(path,sd->fp);
902 if(fp1==NULL){
903 CONSOLE_DEBUG("Couldn't concatenate path");
904 return 0;
905 }
906
907 /*
908 tmp = ospath_str(sd->fp);
909 CONSOLE_DEBUG("Checking for path '%s'...",tmp);
910 ospath_free_str(tmp);
911 */
912
913 if(ospath_stat(fp1,&sd->buf)){
914 sd->error = errno;
915 /* CONSOLE_DEBUG("Stat failed");*/
916 ospath_free(fp1);
917 return 0;
918 }
919
920 f = ospath_fopen(fp1, "r");
921 if(f==NULL){
922 sd->error = errno;
923 /* CONSOLE_DEBUG("Fopen failed"); */
924 ospath_free(fp1);
925 return 0;
926 }
927
928 sd->mtime = sd->buf.st_mtime;
929 sd->f = f;
930 sd->fp_found = fp1;
931
932 /* CONSOLE_DEBUG("File found"); */
933 return 1;
934 }
935
936
937 /**
938 This function tries to find a file corresponding to the argument
939 "name" by sending "name" to the function ModuleStatFile() which
940 will attempt to open "name" as a file. If that fails, this
941 function then prepends each entry in the search path
942 PATHENVIRONMENTVAR to "name" and attempts to open the resulting
943 file (by once again calling ModuleStatFile()).
944
945 On success, the argument "filename" will be set to the path to the
946 file, and the `f', `time_last_modified', and `linenum' members of
947 the module `m' will be set. (The 'FILE *' will be left open for
948 reading and the handle returned in the module struct.)
949
950 If ModuleStatFile() encounters an error opening the file, the
951 value of errno will be passed back to the caller in the `error'
952 argument.
953
954 @param name filename to be searched for (in cwd & in search path).
955 @param filename (output) the location of the found file (if found)
956 @param error (output) error code from ModuleStatFile
957 @param m (output) a pointer to the opened module_t object (if found)
958
959 @return
960 -4 Invalid partial path in parameter 'filename'.
961 -3 Memory error occurred when trying to get PATHENVIRONMENTVAR
962 -1 Error encountered in ModuleStatFile, check `error' argument
963 0 Success
964 1 Could not find a file named "name"
965 */
966 static
967 int ModuleSearchPath(CONST char *name,
968 char *filename,
969 struct module_t *m,
970 int * CONST error
971 ){
972 struct FilePath *fp1, *fp2;
973 char *tmp;
974 struct FilePath **sp1 = NULL;
975 struct ModuleSearchData sd;
976
977 asc_assert( name != NULL );
978 asc_assert( filename != NULL );
979 asc_assert( m != NULL );
980 asc_assert( error != NULL );
981
982 /* CONSOLE_DEBUG("Launching ModuleSearchPath with '%s'",name); */
983
984 fp1 = ospath_new_noclean(name);
985 if(fp1==NULL){
986 ERROR_REPORTER_HERE(ASC_USER_ERROR,"Invalid partial path '%s'",name);
987 ospath_free(fp1);
988 return -4;
989 }
990
991 tmp = ospath_str(fp1);
992 /* CONSOLE_DEBUG("Searching for '%s'",tmp); */
993 ospath_free_str(tmp);
994
995 /* attempt to open "name" directly */
996 if(0==ospath_stat(fp1,&sd.buf) && NULL!=(sd.f = ospath_fopen(fp1,"r")) ){
997
998 CONSOLE_DEBUG("File '%s' opened directly, without path search",name);
999 sd.fp_found = fp1;
1000
1001 }else{
1002
1003 /* CONSOLE_DEBUG("ENV var name is '%s'",PATHENVIRONMENTVAR); */
1004
1005 tmp = Asc_GetEnv(PATHENVIRONMENTVAR);
1006 if(tmp==NULL){
1007 ERROR_REPORTER_HERE(ASC_PROG_ERROR,"No paths to search (is env var '%s' set?)",PATHENVIRONMENTVAR);
1008 ospath_free(fp1);
1009 return 1;
1010 }
1011
1012 /* CONSOLE_DEBUG("ENV var value is '%s'",tmp); */
1013
1014 sp1 = ospath_searchpath_new(tmp);
1015 if(sp1==NULL){
1016 ERROR_REPORTER_HERE(ASC_PROG_ERROR,"Unable to process %s value '%s'",PATHENVIRONMENTVAR,tmp);
1017 /* memory error */
1018 ASC_FREE(tmp);
1019 ospath_free(fp1);
1020 return -3;
1021 }
1022 ascfree(tmp);
1023
1024 /* CONSOLE_DEBUG("Created SP with %d elements",ospath_searchpath_length(sp1)); */
1025
1026 sd.fp = fp1;
1027
1028 fp2 = ospath_searchpath_iterate(sp1, &module_searchpath_test, &sd);
1029
1030 if(fp2==NULL){
1031 *error = sd.error;
1032 CONSOLE_DEBUG("File '%s' not found in search path (%d)",name,sd.error);
1033 ospath_searchpath_free(sp1);
1034 return -1;
1035 }
1036
1037 tmp = ospath_str(fp2);
1038 asc_assert(tmp!=NULL);
1039 /* CONSOLE_DEBUG("Found file in '%s' in search path",tmp); */
1040 ospath_searchpath_free(sp1);
1041 ospath_free_str(tmp);
1042 }
1043
1044 m->f = sd.f;
1045 m->time_last_modified = sd.mtime;
1046 m->linenum = 1;
1047 ospath_strncpy(sd.fp_found,filename,PATH_MAX);
1048 if(fp1!=sd.fp_found){
1049 ospath_free(fp1);
1050 }
1051 ospath_free(sd.fp_found);
1052 return 0; /* success */
1053 }
1054
1055
1056 /**
1057 Print an error (based on the errno `error') explaining why we could
1058 not open/stat the file named `filename'.
1059 */
1060 static
1061 void WriteWhyNotFound(char *filename, int error)
1062 {
1063 switch( error ) {
1064 case EACCES:
1065 ERROR_REPORTER_HERE(ASC_USER_ERROR,
1066 "File or directory permissions don't allow you to access '%s'.",
1067 filename
1068 );
1069 break;
1070 case EFAULT:
1071 ERROR_REPORTER_HERE(ASC_USER_ERROR
1072 ,"Filename pointer or buffer pointer was bad."
1073 );
1074 break;
1075 case EIO:
1076 ERROR_REPORTER_HERE(ASC_USER_ERROR
1077 ,"I/O error in reading '%s'.",filename
1078 );
1079 break;
1080 case ENAMETOOLONG:
1081 ERROR_REPORTER_HERE(ASC_USER_ERROR
1082 ,"The path for '%s' is too long.",filename
1083 );
1084 break;
1085 case ENOENT:
1086 ERROR_REPORTER_HERE(ASC_USER_ERROR
1087 ,"File '%s' doesn't exist.",filename
1088 );
1089 break;
1090 case ENOTDIR:
1091 ERROR_REPORTER_HERE(ASC_USER_ERROR
1092 ,"A component of the path name '%s' is not a directory.",filename
1093 );
1094 break;
1095 #ifndef __WIN32__
1096 case ELOOP:
1097 /* no symlinks in windows land */
1098 ERROR_REPORTER_HERE(ASC_USER_ERROR
1099 ,"There are too many symbolic links in '%s'.",filename
1100 );
1101 break;
1102 #endif /* __WIN32__ */
1103 default:
1104 ERROR_REPORTER_HERE(ASC_USER_ERROR
1105 ,"File not available for unknown reasons (error %d)"
1106 ,error
1107 );
1108 break;
1109 }
1110 }
1111
1112
1113 /** See the header file for this function's documentation
1114 **/
1115 extern int Asc_ModuleCreateAlias(CONST struct module_t *m, CONST char *name)
1116 {
1117 struct module_t *new_module;
1118 struct module_t *dup;
1119 char mod_name[PATH_MAX];
1120
1121 asc_assert( m != NULL );
1122
1123 /*
1124 * Make sure the user gave us good data
1125 */
1126 if(( name == NULL ) || ( *name == '\0' )) {
1127 return -4;
1128 }
1129
1130 /*
1131 * Make sure m is not a module-alias. This shouldn't happen since
1132 * the user should not be able to get his hands on module-aliases.
1133 */
1134 if( m->provided_by != NULL ) {
1135 ERROR_REPORTER_HERE(ASC_USER_ERROR
1136 ,"Module '%s' is a module-alias. Module to alias must not be a module-alias\n"
1137 ,SCP(m->name)
1138 );
1139 return -4;
1140 }
1141
1142 /*
1143 * Create a new module or return -3 if we could not
1144 */
1145 new_module = NewModule( name );
1146 if( new_module == NULL ) {
1147 return -3;
1148 }
1149
1150 dup = SearchForModule( new_module );
1151
1152 if( dup == NULL ) {
1153 /* no module with this name exists. Set up the module-alias
1154 * and store it
1155 */
1156 new_module->provided_by = m;
1157 /* next line probably redundant */
1158 new_module->base_name = AddSymbol(SCP(new_module->base_name));
1159 new_module->version = 0;
1160 sprintf(mod_name,"%s<%lu>",SCP(new_module->base_name),new_module->version);
1161 new_module->name = AddSymbol(mod_name);
1162 if( StoreModule( new_module ) != 0 ) {
1163 DeleteModule( new_module );
1164 return -3;
1165 }
1166 return 0;
1167 }
1168
1169 /*
1170 * Check to see if a module-alias with this name already exists
1171 * that points to this module. If so, destroy the new one
1172 * silently and return.
1173 */
1174 if( dup->provided_by == m ) {
1175 DeleteModule( new_module );
1176 return 2;
1177 }
1178
1179 /*
1180 * Check to see if a module-alias with this name already exists
1181 * that points to different module. If so, check to see if the
1182 * filenames are the same. If the filename not the same, overwrite
1183 * the existing module noisly; else, overwrite it silently.
1184 */
1185 if( dup->provided_by != NULL ) {
1186 if( CmpSymchar( dup->provided_by->filename, m->filename ) != 0 ) {
1187 ERROR_REPORTER_HERE(ASC_USER_WARNING,
1188 "PROVIDE \"%s\" in file '%s' overwrites PROVIDE \"%s\" in file '%s'"
1189 ,SCP(new_module->base_name), SCP(m->filename)
1190 ,SCP(dup->base_name), SCP(dup->provided_by->filename)
1191 );
1192 }
1193 RemoveModule( dup );
1194 DeleteModule( dup );
1195 new_module->provided_by = m;
1196 /* probably redundant addsymbol next line */
1197 new_module->base_name = AddSymbol(SCP(new_module->base_name));
1198 new_module->version = 0;
1199 sprintf(mod_name,"%s<%lu>",SCP(new_module->base_name),new_module->version);
1200 new_module->name = AddSymbol(mod_name);
1201 if( StoreModule( new_module ) != 0 ) {
1202 DeleteModule( new_module );
1203 return -3;
1204 }
1205 return 3;
1206 }
1207
1208 /*
1209 * Check to see if the duplicate module is actually the current
1210 * module---i.e., module ``foo.a4c'' contains the statement
1211 * ``PROVIDE "foo.a4c";'' If so, destroy the new_module silently.
1212 */
1213 if( dup == g_current_module ) {
1214 DeleteModule( new_module );
1215 return 1;
1216 }
1217
1218 /*
1219 * If we made it here, we attempting to PROVIDE a real module that
1220 * already exists. Issue an error, destroy the new_module, and
1221 * return.
1222 */
1223 ERROR_REPORTER_HERE(ASC_USER_ERROR,
1224 "File \"%s\" cannot PROVIDE '%s' because a module with that name already exists (%s)."
1225 , SCP(m->filename), SCP(new_module->base_name), SCP(dup->name)
1226 );
1227 DeleteModule( new_module );
1228 return -2;
1229 }
1230
1231 /**
1232 Allocate space for a new module and set its fields to some
1233 reasonable defaults. If `name' is not NULL, set the module's
1234 base_name to point to the first character after the rightmost
1235 slash (`/' on UNIX, `/' on Windows) in `name', or to `name' if
1236 it contains no slashes. Note that this function will create
1237 a symbol for base_name. Return NULL if malloc fails.
1238 */
1239 static
1240 struct module_t *NewModule(CONST char *name){
1241 struct module_t *newmodule; /* the new module */
1242 char *tmp; /* result of strrchr(); used to get base_name */
1243 struct FilePath *fp1;
1244
1245 newmodule = ASC_NEW(struct module_t);
1246 if( newmodule == NULL ) {
1247 ERROR_REPORTER_HERE(ASC_PROG_ERR,"UNABLE TO MALLOC FOR NEW MODULE");
1248 return NULL;
1249 }
1250 newmodule->name = NULL;
1251 newmodule->filename = NULL;
1252 newmodule->f = NULL;
1253 newmodule->s = NULL;
1254 newmodule->stats = NULL;
1255 newmodule->scanbuffer = NULL;
1256 newmodule->required_by = NULL;
1257 newmodule->provided_by = NULL;
1258 newmodule->time_last_modified = (time_t)0;
1259 newmodule->linenum = 0;
1260 newmodule->open_count = 0;
1261 newmodule->version = ULONG_MAX;
1262
1263 /* CONSOLE_DEBUG("New path: %s",name); */
1264 fp1 = ospath_new(name);
1265 tmp = ospath_getbasefilename(fp1);
1266 if(tmp!=NULL && strlen(tmp)!=0){
1267 newmodule->base_name = AddSymbol(tmp);
1268 }
1269 ospath_free_str(tmp); /* we can free tmp, since 'AddSymbol' takes a copy */
1270 ospath_free(fp1);
1271
1272 /* CONSOLE_DEBUG("Module base-name: %s",newmodule->base_name); */
1273 return newmodule;
1274 }
1275
1276 /*------------------------------------------------------------------------------
1277 GLOBAL MODULE LIST MANAGEMENT
1278
1279 * The following four functions are used to store, remove, and search
1280 * for modules in the global module list, the gl_list `g_module_list'.
1281 * We do this (instead of inlining the calls to gl_*()) to provide a
1282 * bit of data abstraction, though I'm sure there are some implicit
1283 * assumptions in the code as to how modules are stored on the gl_list.
1284 *
1285 * These functions handle a NULL g_module_list gracefully.
1286 *
1287 * Modules are appended to the g_module_list in the order they are
1288 * OPENED, so later versions of the same file appear toward the end of
1289 * the list. Note that a module in the back of the list may define
1290 * types needed by module at the front of the list, due to the magic of
1291 * the REQUIRE statement.
1292 *
1293 * Since the modules are in the order opened, implementing a
1294 * Re-Read-All-Files function wouldn't be too difficult, but the
1295 * REQUIRE statements in each file would still have to be followed.
1296 *
1297 * Since module-aliases are implemented as modules and are stored on
1298 * the g_module_list, they must sometimes be replaced by actual
1299 * modules or new module-aliases. When this occurs, a module-alias
1300 * must be removed from the g_module_list.
1301 *
1302 * When searching for a module, we start at the end of the list and
1303 * move towards the front. The comparison function looks for the
1304 * base-names to be equal and for the version number of the found
1305 * module being less than or equal to the version number of the module
1306 * passed into the SearchForModule() function. The comparison
1307 * function uses less than or equal for the version number because one
1308 * doesn't know the version number of the most recently read version.
1309 * By setting the version number in the module passed to
1310 * SearchForModule() to be ULONG_MAX, you will get the first module
1311 * where the base-names match, which should be the most recently read
1312 * version of that module.
1313 *-------------------------------------------------
1314 */
1315
1316
1317 /** Store `m' in the global module gl_list `g_module_list', creating
1318 * the g_module_list if needed. Return 0 for success or 1 if the
1319 * g_module_list could not be created.
1320 *
1321 * Storing `m' in g_module_list simply appends it to the list.
1322 */
1323 static
1324 int StoreModule(CONST struct module_t *m)
1325 {
1326 /* initialize the global module list if required */
1327 if((g_module_list==NULL) && (Asc_InitModules(G_MODULE_LIST_INIT_SIZE)!=0)) {
1328 ERROR_REPORTER_HERE(ASC_PROG_ERR,"FAILED TO ASC_INITMODULES");
1329 return 1;
1330 }
1331 gl_append_ptr( g_module_list, (VOIDPTR)m );
1332 return 0;
1333 }
1334
1335
1336 /** Remove `m' from the global module gl_list `g_module_list'.
1337 *
1338 * This function searches backwards through g_module_list and uses
1339 * CmpModulesNameVers() to determine which module to remove.
1340 */
1341 static
1342 void RemoveModule(CONST struct module_t *m)
1343 {
1344 unsigned long place;
1345
1346 if( g_module_list == NULL ) {
1347 return;
1348 }
1349 place = gl_search_reverse( g_module_list, m, (CmpFunc)CmpModulesNameVers );
1350 if( place == 0 ) {
1351 return;
1352 }
1353 gl_delete( g_module_list, place, 0 );
1354 return;
1355 }
1356
1357
1358 /** Search for `m' in the global module gl_list `g_module_list'
1359 * and return it. Return the matching module or NULL if no matching
1360 * module exists or if the g_module_list is empty.
1361 *
1362 * This function searches backwards through g_module_list and uses
1363 * CmpModulesNameVers() to determine which module return.
1364 */
1365 static
1366 struct module_t *SearchForModule(CONST struct module_t *m){
1367 unsigned long place;
1368
1369 asc_assert(m != NULL);
1370
1371 if( g_module_list == NULL ) {
1372 return NULL;
1373 }
1374
1375 place = gl_search_reverse( g_module_list, m, (CmpFunc)CmpModulesNameVers );
1376 if( place == 0 ) {
1377 return NULL;
1378 }
1379 return gl_fetch( g_module_list, place );
1380 }
1381
1382
1383 /** Compare the base_names and version numbers of the modules
1384 * `m1' and `m2'.
1385 * Return:
1386 * >0 m1->base_name > m2->base_name
1387 * || (m1->base_name == m2->base_name
1388 * && m1->version > m2->version)
1389 * <0 m1->base_name < m2->base_name
1390 * 0 m1->base_name == m2->base_name
1391 * && m1->version <= m2->version
1392 */
1393 static
1394 int CmpModulesNameVers(CONST struct module_t *m1, CONST struct module_t *m2){
1395 int result;
1396
1397 if( (result = CmpSymchar(m1->base_name, m2->base_name)) != 0 ) {
1398 return result;
1399 }
1400 if( m1->version > m2->version ) {
1401 return 1;
1402 }
1403 return 0;
1404 }
1405
1406
1407
1408 extern int Asc_CloseCurrentModule(void){
1409 struct module_t *prev;
1410
1411 /*
1412 * If no current module, return TRUE
1413 */
1414 if (g_current_module == NULL) {
1415 return TRUE;
1416 }
1417
1418 /*
1419 * Store the scanner's position in the current module
1420 */
1421 g_current_module->linenum = LineNum();
1422
1423 /*
1424 * Close the current module's file or buffer.
1425 */
1426 if (g_current_module->f != NULL) {
1427 fclose(g_current_module->f);
1428 g_current_module->f = NULL;
1429 } else {
1430 asc_assert(g_current_module->s != NULL);
1431 Asc_ScannerReleaseStringBuffer(g_current_module->scanbuffer);
1432 g_current_module->scanbuffer = NULL;
1433 }
1434
1435 /*
1436 * Pop the module that REQUIRED the current module so
1437 * it becomes the current module
1438 */
1439 prev = g_current_module->required_by;
1440 g_current_module->required_by = NULL; /* unlink it */
1441 g_current_module = prev;
1442
1443 /*
1444 * No more modules
1445 */
1446 if (g_current_module == NULL) {
1447 return TRUE;
1448 }
1449
1450 /*
1451 * Inform the scanner after pop
1452 */
1453 if (g_current_module->s == NULL) {
1454 Asc_ScannerAssignFile(g_current_module->f,g_current_module->linenum);
1455 } else {
1456 asc_assert(g_current_module->scanbuffer != NULL);
1457 Asc_ScannerAssignString(g_current_module->scanbuffer,
1458 g_current_module->linenum,0);
1459 }
1460 return FALSE;
1461 }
1462
1463
1464 int Asc_ModuleAddStatements(struct module_t *m, struct gl_list_t *l)
1465 {
1466 if (l == NULL || gl_length(l) == 0 ||
1467 m == NULL || m->s == NULL || m->f != NULL) {
1468 return -1;
1469 /* list is empty or module is not a string module.
1470 * caller should dump l and contents.
1471 */
1472 }
1473 if (m->stats == NULL) {
1474 m->stats = l;
1475 /* we're keeping list and contents. */
1476 return 0;
1477 } else {
1478 gl_append_list(m->stats,l);
1479 /* we're keeping contents but not list. caller should destroy l. */
1480 return 1;
1481 }
1482 }
1483
1484
1485 extern CONST struct module_t *Asc_GetModuleByName(CONST char *module_name){
1486 char name[PATH_MAX];
1487 unsigned long vers;
1488 struct module_t *mod;
1489 struct module_t *result;
1490
1491 if( g_module_list == NULL ) {
1492 return NULL;
1493 }
1494
1495 /*
1496 * Convert the given name to an base name and version
1497 */
1498 vers = ModuleNameToInternalNameVers(module_name, name);
1499 if( vers == ULONG_MAX ) {
1500 ERROR_REPORTER_HERE(ASC_PROG_ERR
1501 ,"Bad format for module name %s, no version number found."
1502 ,name
1503 );
1504 return NULL;
1505 }
1506
1507 /*
1508 * Create a new module with this name and version---needed to
1509 * call SearchForModule()
1510 */
1511 mod = NewModule( name );
1512 if( mod == NULL ) {
1513 return NULL;
1514 }
1515 mod->version = vers;
1516
1517 /*
1518 * Search for the module and free the module we used for searching.
1519 */
1520 result = SearchForModule( mod );
1521 DeleteModule( mod );
1522
1523 /*
1524 * If result is a module-alias, return the module that PROVIDED it
1525 */
1526 if(( result != NULL ) && ( result->provided_by != NULL )) {
1527 return result->provided_by;
1528 }
1529 return result;
1530 }
1531
1532
1533 /**
1534 * Parse the module name given in `module_name' (e.g., "foo.a4c<0>")
1535 * into an base name and a version number. Copy the base_name
1536 * into the string `name' and use the version number as the return
1537 * value. Leading and trailing whitespace on `module_name' is removed.
1538 *
1539 * If `module_name' does not contain a valid module name, return
1540 * ULONG_MAX.
1541 */
1542 static
1543 unsigned long ModuleNameToInternalNameVers(CONST char *module_name,
1544 char * CONST name)
1545 {
1546 unsigned int t;
1547 unsigned long vers = ULONG_MAX;
1548
1549 asc_assert( name != NULL );
1550
1551 /*
1552 * Make sure we got good data
1553 */
1554 if(( module_name == NULL ) || ( *module_name == '\0' )) {
1555 return vers;
1556 }
1557
1558 /*
1559 * Ignore leading whitespace
1560 */
1561 while( isspace(*module_name) ) {
1562 module_name++;
1563 }
1564
1565 /*
1566 * Copy all of module_name into name
1567 */
1568 for( t = 0 ; ((name[t] = module_name[t]) != '\0') ; t++ );
1569
1570 /*
1571 * Remove trailing whitespace
1572 * Use t>1 in the while since we decrement t twice before we
1573 * check it again and we don't want to fall off the front of
1574 * the string.
1575 */
1576 while(( t > 1 ) && ( isspace(name[--t]) ));
1577
1578 /*
1579 * Check for '>' preceded by a number
1580 */
1581 if(( name[t] != '>' ) || ( ! isdigit(name[--t]) )) {
1582 return vers;
1583 }
1584
1585 /*
1586 * Back up over all the digits that make up the version number
1587 * Use t>1 in while since a valid base name has to have
1588 * at least one character.
1589 */
1590 while(( t > 1 ) && ( isdigit(name[--t]) ));
1591
1592 /*
1593 * Make sure we have a '<'
1594 */
1595 if( name[t] != '<' ) {
1596 return vers;
1597 }
1598
1599 /*
1600 * Convert the '<' to '\0' since this is where the name ends
1601 */
1602 name[t] = '\0';
1603
1604 /*
1605 * Covert the number to an unsigned long in base 10
1606 */
1607 vers = strtoul( (name + t + 1), NULL, 10 );
1608 if( vers == ULONG_MAX ) {
1609 return vers;
1610 }
1611
1612 return vers;
1613 }
1614
1615 CONST char *Asc_ModuleString(CONST struct module_t *m)
1616 {
1617 if (m==NULL) return NULL;
1618 return m->s;
1619 }
1620
1621 struct gl_list_t *Asc_ModuleStatementLists(CONST struct module_t *m)
1622 {
1623 if (m==NULL) return NULL;
1624 return m->stats;
1625 }
1626
1627
1628
1629 extern struct gl_list_t *Asc_ModuleList(int module_type){
1630 struct gl_list_t *new = NULL;
1631 struct module_t *m;
1632 struct gl_list_t *types = NULL;
1633 unsigned long c;
1634 unsigned long length;
1635
1636 if( g_module_list == NULL ) {
1637 return NULL;
1638 }
1639 length = gl_length(g_module_list);
1640 new = gl_create(length);
1641 if( new == NULL ) {
1642 return NULL;
1643 }
1644 for( c = length; c > 0; c-- ) {
1645 m = (struct module_t *)gl_fetch(g_module_list, c);
1646 switch (module_type) {
1647 case 0:
1648 types = Asc_TypeByModule(m);
1649 if( types != NULL ) {
1650 if( gl_length(types) > 0L ) {
1651 gl_append_ptr(new, (VOIDPTR)(m->name));
1652 }
1653 gl_destroy(types);
1654 types = NULL;
1655 }
1656 break;
1657 case 1:
1658 if (m != NULL && m->s != NULL) {
1659 gl_append_ptr(new, (VOIDPTR)(m->name));
1660 }
1661 break;
1662 case 2:
1663 if (m != NULL && m->stats != NULL) {
1664 gl_append_ptr(new, (VOIDPTR)(m->name));
1665 }
1666 break;
1667 default:
1668 break;
1669 }
1670 }
1671 return new;
1672 }
1673
1674
1675 extern void Asc_ModuleWrite(FILE *f, CONST struct module_t *m){
1676 asc_assert(m!=NULL);
1677 FPRINTF(f,"MODULE: %s\nFILENAME: %s\n",SCP(m->name),SCP(m->filename));
1678 FPRINTF(f,(m->f!=NULL)?"OPEN\n":"CLOSED\n");
1679 FPRINTF(f,"FILE DATE: %s",asctime(localtime( &(m->time_last_modified) )));
1680 }
1681
1682
1683 extern struct module_t *Asc_CurrentModuleF(void){
1684 return g_current_module;
1685 }
1686
1687
1688 extern CONST char *Asc_ModuleName(CONST struct module_t *m){
1689 return (( m != NULL ) ? SCP(m->name) : "");
1690 }
1691
1692
1693 extern CONST char *Asc_ModuleFileName(CONST struct module_t *m){
1694 return ((m != NULL) ? SCP(m->filename) : "");
1695 }
1696
1697 extern CONST char *Asc_ModuleBestName(CONST struct module_t *m){
1698 static char unk[] = "<UNKNOWN>";
1699 if (m == NULL) return "";
1700 if (SCP(m->filename) != NULL) return SCP(m->filename);
1701 if (SCP(m->name)!=NULL) return SCP(m->name);
1702 return unk;
1703 }
1704
1705
1706 extern unsigned long Asc_ModuleTimesOpened(CONST struct module_t *m){
1707 return ((m != NULL) ? (m->open_count) : 0);
1708 }
1709
1710
1711 extern struct tm *Asc_ModuleTimeModified(CONST struct module_t *m){
1712 return ((m != NULL) ? localtime(&(m->time_last_modified)) : NULL);
1713 }
1714
1715 extern int Asc_ModuleStringIndex(CONST struct module_t *m){
1716 return ((m != NULL) ? (int)(m->time_last_modified) : -1);
1717 }

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