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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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