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

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