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

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