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

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