318 lines
		
	
	
	
		
			6.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			318 lines
		
	
	
	
		
			6.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* $Id$ */
 | |
| /*
 | |
|  * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
 | |
|  * See the copyright notice in the ACK home directory, in the file "Copyright".
 | |
|  */
 | |
| /*  I N T E R M E D I A T E   C O D E
 | |
|  *
 | |
|  *  I C _ L I B . C
 | |
|  */
 | |
| 
 | |
| #include <stdio.h>
 | |
| #include <em_spec.h>
 | |
| #include <em_pseu.h>
 | |
| #include <em_mes.h>
 | |
| #include <arch.h>
 | |
| #include "../share/types.h"
 | |
| #include "../share/debug.h"
 | |
| #include "ic.h"
 | |
| #include "ic_lookup.h"
 | |
| #include "ic_io.h"
 | |
| #include "../share/global.h"
 | |
| #include "../share/files.h"
 | |
| #include "ic_lib.h"
 | |
| 
 | |
| STATIC skip_string(n)
 | |
|     offset n;
 | |
| {
 | |
| 	/* Read a string of length n and void it */
 | |
| 
 | |
| 	while (n--)
 | |
| 	{
 | |
| 		readchar();
 | |
| 	}
 | |
| }
 | |
| 
 | |
| STATIC void skip_arguments()
 | |
| {
 | |
| 	/* Skip the arguments of a MES pseudo. The argument
 | |
| 	 * list is terminated by a sp_cend byte.
 | |
| 	 */
 | |
| 
 | |
| 	for (;;)
 | |
| 	{
 | |
| 		switch (table2())
 | |
| 		{
 | |
| 			case sp_scon:
 | |
| 				get_off(); /* void */
 | |
| 			/* fall through !!! */
 | |
| 			case sp_icon:
 | |
| 			case sp_ucon:
 | |
| 			case sp_fcon:
 | |
| 				get_int(); /* void */
 | |
| 				skip_string(get_off());
 | |
| 				break;
 | |
| 			case sp_cend:
 | |
| 				return;
 | |
| 			default:
 | |
| 				break;
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| STATIC bool proc_wanted(name) char* name;
 | |
| {
 | |
| 	/* See if 'name' is the name of an external procedure
 | |
| 	 * that has been used before, but for which no body
 | |
| 	 * has been given so far.
 | |
| 	 */
 | |
| 
 | |
| 	proc_p p;
 | |
| 
 | |
| 	if ((p = proclookup(name, IMPORTING)) != (proc_p)0 && !(p->p_flags1 & PF_BODYSEEN))
 | |
| 	{
 | |
| 		return TRUE;
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		return FALSE;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| STATIC bool data_wanted(name) char* name;
 | |
| {
 | |
| 	/* See if 'name' is the name of an externally visible
 | |
| 	 * data block that has been used before, but for which
 | |
| 	 * no defining occurrence has been given yet.
 | |
| 	 */
 | |
| 
 | |
| 	dblock_p db;
 | |
| 
 | |
| 	if ((db = symlookup(name, IMPORTING)) != (dblock_p)0 && db->d_pseudo == DUNKNOWN)
 | |
| 	{
 | |
| 		return TRUE;
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		return FALSE;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| STATIC bool wanted_names()
 | |
| {
 | |
| 	/* Read the names of procedures and data labels,
 | |
| 	 * appearing in a 'MES ms_ext' pseudo. Those are
 | |
| 	 * the names of entities that are imported by
 | |
| 	 * a library module.
 | |
| 	 * If any of them is wanted, return TRUE.
 | |
| 	 * A name is wanted if it is the name of a procedure
 | |
| 	 * or data block for which applied occurrences but
 | |
| 	 * no defining occurrence has been met.
 | |
| 	 */
 | |
| 
 | |
| 	for (;;)
 | |
| 	{
 | |
| 		switch (table2())
 | |
| 		{
 | |
| 			case DLBX:
 | |
| 				if (data_wanted(string))
 | |
| 				{
 | |
| 					return TRUE;
 | |
| 				}
 | |
| 				/* A data entity with the name
 | |
| 				 * string is available.
 | |
| 				 */
 | |
| 				break;
 | |
| 			case sp_pnam:
 | |
| 				if (proc_wanted(string))
 | |
| 				{
 | |
| 					return TRUE;
 | |
| 				}
 | |
| 				break;
 | |
| 			case sp_cend:
 | |
| 				return FALSE;
 | |
| 			default:
 | |
| 				error("wrong argument of MES %d", ms_ext);
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| STATIC FILE* curfile = NULL;
 | |
| STATIC bool useful()
 | |
| {
 | |
| 	/* Determine if any entity imported by the current
 | |
| 	 * compact EM assembly file  (which will usually be
 | |
| 	 * part of an archive file) is useful to us.
 | |
| 	 * The file must contain (before any other non-MES line)
 | |
| 	 * a 'MES ms_ext' pseudo that has as arguments the names
 | |
| 	 * of the entities imported.
 | |
| 	 */
 | |
| 
 | |
| 	for (;;)
 | |
| 	{
 | |
| 		if (table1() != PSEU || tabval != ps_mes)
 | |
| 		{
 | |
| 			error("cannot find MES %d in library file", ms_ext);
 | |
| 		}
 | |
| 		if (table2() != CSTX1)
 | |
| 		{
 | |
| 			error("message number expected");
 | |
| 		}
 | |
| 		if (tabval == ms_ext)
 | |
| 		{
 | |
| 			/* This is the one we searched */
 | |
| 			return wanted_names();
 | |
| 			/* Read the names of the imported entities
 | |
| 			 * and check if any of them is wanted.
 | |
| 			 */
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			skip_arguments(); /* skip remainder of this MES */
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| STATIC bool is_archive(name) char* name;
 | |
| {
 | |
| 	/* See if 'name' is the name of an archive file, i.e. it
 | |
| 	 * should end on ".ma" and should at least be four characters
 | |
| 	 * long (i.e. the name ".ma" is not accepted as an archive name!).
 | |
| 	 */
 | |
| 
 | |
| 	register char* p;
 | |
| 
 | |
| 	for (p = name; *p; p++)
 | |
| 		;
 | |
| 	return (p > name + 3) && (*--p == 'a') && (*--p == 'm') && (*--p == '.');
 | |
| }
 | |
| 
 | |
| STATIC struct ar_hdr hdr;
 | |
| 
 | |
| STATIC bool read_hdr()
 | |
| {
 | |
| 	/* Read the header of an archive module */
 | |
| 
 | |
| 	char buf[AR_TOTAL];
 | |
| 	register char* c = buf;
 | |
| 	register char* p = hdr.ar_name;
 | |
| 	register int i;
 | |
| 
 | |
| 	fread(c, AR_TOTAL, 1, curfile);
 | |
| 	if (feof(curfile))
 | |
| 		return 0;
 | |
| 	i = 14;
 | |
| 	while (i--)
 | |
| 	{
 | |
| 		*p++ = *c++;
 | |
| 	}
 | |
| 
 | |
| #define get2(c) (((c)[0] & 0377) | ((unsigned)((c)[1] & 0377) << 8))
 | |
| 
 | |
| 	hdr.ar_date = ((long)get2(c)) << 16;
 | |
| 	c += 2;
 | |
| 	hdr.ar_date |= ((long)get2(c)) & 0xffff;
 | |
| 	c += 2;
 | |
| 	hdr.ar_uid = *c++;
 | |
| 	hdr.ar_gid = *c++;
 | |
| 	hdr.ar_mode = get2(c);
 | |
| 	c += 2;
 | |
| 	hdr.ar_size = (long)get2(c) << 16;
 | |
| 	c += 2;
 | |
| 	hdr.ar_size |= (long)get2(c) & 0xffff;
 | |
| 
 | |
| 	return 1;
 | |
| }
 | |
| 
 | |
| STATIC int argcnt = 0;
 | |
| STATIC short arstate = NO_ARCHIVE;
 | |
| 
 | |
| FILE* next_file(argc, argv) int argc;
 | |
| char* argv[];
 | |
| {
 | |
| 	/* See if there are more EM input files. The file names
 | |
| 	 * are given via argv. If a file is an archive file
 | |
| 	 * it is supposed to be a library of EM compact assembly
 | |
| 	 * files. A module (file) contained in this archive file
 | |
| 	 * is only used if it imports at least one procedure or
 | |
| 	 * datalabel for which we have not yet seen a defining
 | |
| 	 * occurrence, although we have seen a used occurrence.
 | |
| 	 */
 | |
| 
 | |
| 	long ptr;
 | |
| 
 | |
| 	for (;;)
 | |
| 	{
 | |
| 		/* This loop is only exited via a return */
 | |
| 		if (arstate == ARCHIVE)
 | |
| 		{
 | |
| 			/* We were reading an archive file */
 | |
| 			if (ftell(curfile) & 1)
 | |
| 			{
 | |
| 				/* modules in an archive file always
 | |
| 				 * begin on a word boundary, i.e. at
 | |
| 				 * an even address.
 | |
| 				 */
 | |
| 				fseek(curfile, 1L, 1);
 | |
| 			}
 | |
| 			if (read_hdr())
 | |
| 			{ /* read header of next module */
 | |
| 				ptr = ftell(curfile); /* file position */
 | |
| 				file_init(curfile, ARCHIVE, hdr.ar_size);
 | |
| 				/* tell i/o package that we're reading
 | |
| 				 * an archive module of given length.
 | |
| 				 */
 | |
| 				if (useful())
 | |
| 				{
 | |
| 					/* re-initialize file, because 'useful'
 | |
| 					 * has read some bytes too.
 | |
| 					 */
 | |
| 					fseek(curfile, ptr, 0); /* start module */
 | |
| 					file_init(curfile, ARCHIVE, hdr.ar_size);
 | |
| 					return curfile;
 | |
| 				}
 | |
| 				else
 | |
| 				{
 | |
| 					/* skip this module */
 | |
| 					fseek(curfile,
 | |
| 					    ptr + hdr.ar_size, 0);
 | |
| 				}
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				/* done with this archive */
 | |
| 				arstate = NO_ARCHIVE;
 | |
| 			}
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			/* open next file, close old */
 | |
| 			if (curfile != NULL)
 | |
| 			{
 | |
| 				fclose(curfile);
 | |
| 			}
 | |
| 			argcnt++;
 | |
| 			if (argcnt >= argc)
 | |
| 			{
 | |
| 				/* done with all arguments */
 | |
| 				return NULL;
 | |
| 			}
 | |
| 			filename = argv[argcnt];
 | |
| 			if ((curfile = fopen(filename, "r")) == NULL)
 | |
| 			{
 | |
| 				error("cannot open %s", filename);
 | |
| 			}
 | |
| 			if (is_archive(filename))
 | |
| 			{
 | |
| 				/* ends on '.ma' */
 | |
| 				arstate = ARCHIVE;
 | |
| 				arch_init(curfile); /* read magic ar number */
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				file_init(curfile, NO_ARCHIVE, 0L);
 | |
| 				return curfile;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 |