⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ccasmb.c

📁 KCC , a good c compiler, write by Ken Harrenstien
💻 C
📖 第 1 页 / 共 3 页
字号:
/*	CCASMB.C - Assembler and Linker invocation
**
**	(c) Copyright Ken Harrenstien 1989
**		All changes after v.97, 12-Aug-1988
**	(c) Copyright Ken Harrenstien, SRI International 1985, 1986
**		All changes after v.23, 8-Aug-1985
**
**	Original version (c) 1981 K. Chen
*/

#include "ccsite.h"
#include "ccchar.h"
#include "cc.h"
#include <stdlib.h>			/* calloc, realloc, free */
#include <sys/types.h>			/* For stat(), for symval stuff */
#include <sys/stat.h>

#if !__MSDOS__ 							// FW KCC-NT
 #include <sys/file.h>			/* For open() */
#endif

#include <errno.h>			/* For strerror */
#include <string.h>			/* For strchr etc */

#if !__MSDOS__							// FW KCC-NT
 #include <frkxec.h>			/* New stuff */
#endif

#if __MSDOS__				/* 4/92 avoid non-ANSI stat() */
 #define stats stat			/* just use stat() function */
#else

 #ifdef mod /* KAR-4/92, remove collision with mod in comdef (boom!) */
  #undef mod
 #endif

 #include <sys/usysio.h>

 #undef sixbit	/* KAR-8/92, accomodate comdef.h def of sixbit */
 #include <csimon.h>	/* KAR-5/92, for MON_ calls for times */
 #define sixbit _sixbit /* KAR-8/92, see comment on #undef */

int	    stats (char *source_fname, struct stat *statb);
static
int	    long to_sixbit (char *str);
static
char	    stats_parse = 0;
#endif

#include <stdio.h>

#if !__MSDOS__							// FW KCC-NT
 #define _getpid(_pid)  ((MUUO_VAL("PJOB", &_pid)), _pid)

 #include <muuo.h>	/* For TMPCOR etc */
#endif
#define PRGBLEN 0

#ifndef RH
 #define RH 0777777L	/* Mask for RH of a word */
#endif

#ifndef LH
 #define LH (-1<<18)	/* Mask for LH */
#endif

#ifndef XWD		/* Put halves together */
 #define XWD(a,b) (((unsigned)(a)<<18) | ((unsigned)(b)&RH))
#endif

/* Exported routines */

int	    asmb (char *, char *, char *);
char*	    fnparse (char *, char *, char *, char *, char *);
int	    fnxisrel (char *);
void	    runlink (int, int, char **, char *, char *);
int	    symval (char *fnam, char *sym, int valf);
char*	    estrcpy (char *, char *);
char*	    fstrcpy (char *, char *, char *);
INT	    sixbit (char *);

/* Imported routines */

#if !SYS_CSI /* KAR-3/92, removed LIBC dependency, use ANSI calls */

extern
int	    open (char *path, int flags),		/* , int mode)?? */
	    getpid (void),
	    stat (char *, struct stat *),
	    fstat (int handle, struct stat *),

#ifdef __COMPILER_KCC		/* BC++ error */
	    unlink (char *),		/* Syscalls */
#endif

	    close (int fd),
	    read (int fd, char *buf, int nbytes);
#else
extern
int	    remove (const char *);
#endif

#ifdef __COMPILER_KCC__
extern
int	    forkexec (struct frkxec *f);
#endif /* KCC */

/* Internal routines */

static
char*	    gtmpfile (char *);
static
int*	    stmpfile (char *, char *, char *);
static
int*	    maktflink (int, char **, char *, char *),
	    crsfunv (char *, long),
	    hackfork (char *, int *, int, int, int),
	    ldsymfile (char *);

#if DEBUG_KCC	/* 8/91 KCC size */
static
int	    tdebug = 0;	/* Set non-zero to print out tmpcor args */
#endif

static
char*	    asmtfptr = NULL;	/* Assembler tmpcor file contents */
static
int	    asmtflen = 0;	/* Length not including trailing NUL */

/* BP7 - macro to convert a char ptr into a 7-bit byte pointer */

#if __MSDOS__
#include <process.h>	/* getpid() */
#define bp7(cp) ((char *)(cp))
#else
#define bp7(cp) ((char *)(int)(_char7 *)(cp))
#endif

/*
Description of COMPIL (or RPG) argument passing mechanism.

On TOPS-10 and CSI there is a convention for passing arguments
amongst programs which compile and load programs.  This is known as
RPG ("Rapid Program Generation"), and is only invoked by the so-called
COMPIL-class commands:
    COMPILE, LOAD, EXECUTE, DEBUG.

When a program is invoked by the TOPS-20 EXEC (or the TOPS-10
monitor) at its starting address plus 1, it is expected to look for
command input from a temporary file rather than from the user's TTY.
This consists of first looking for a TMPCOR file of a specific name
associated with that program (MAC for MACRO, LNK for LINK, KCC for
KCC, etc.).

This is done with the TMPCOR UUO.  The file is deleted when read.
If there is no such temporary file, then the program is expected to look
for an actual disk file of the name:
DSK:nnnNAM.TMP where nnn is the job number in decimal (right-justified
with leading zeros).  This file should likewise be deleted after reading.

The TMPCOR file furnished to a compiler/assembler contains a single
command line for each file to be compiled, of the
format:
NAME,=NAME.EXT<crlf>

The monitor has arcane special knowledge of just how each
program, especially LINK, likes its commands formatted.  The above
appears to be most common, however.  Finally, the way that the monitor sets
up a chain of programs is by adding a final command line to the file
of the form:
<program-file>!<crlf>
which instructs the compiler/assembler to load and run the specified
program, starting it with an offset of 1.  This is a full filename
specification and no searching should be needed.  For KCC this will normally
be SYS:LINK.EXE if LINK is to be invoked next.
*/

/*
 * ASMB - Set up assembler arguments.  We must defer assembly to the end
 *		of compilation, so remember all the assembler arguments
 *		in an allocated buffer.
 *
 *		Returns -1 if error, 0 if arguments successfully stored.
 */

int
asmb (char *m, char *f1, char *f2)
    {
    char	str[FNAMESIZE*4];	/* Big enough for 3 names plus punct */
    char*	nptr;
    int		n;


    sprintf (str, "%s%s=%s%s%s%s%s\n",
	     m,				/* Specify output file name */
	     (longidents ? "/k" : ""),	/* FW 2A(51) Using long identifiers? */
	     (f1 ? f1 : ""),		/* Specify 1st input file if one */
	     ((f1 && delete) ? "/d" : ""), /* delete asm source  */
	     (f1 && f2) ? "," : "",	/* Use separator if 2 inputs */
	     (f2 ? f2 : ""),		/* Specify 2nd input file if exists */
	     ((f2 && delete && (!mlist)) ? "/d" : ""));
					/* Specify delete asm source */

    /* Add new command to assembler's saved TMPCOR file block */

    n = strlen (str);			/* Find # chars needed */

    if ((nptr = realloc (asmtfptr, asmtflen + n + 1)) == NULL)
	jerr ("Out of memory for assembler tmpcor file (%d chars)", asmtflen);
    else
	{
	asmtfptr = nptr;
	strcpy (asmtfptr + asmtflen, str); /* Add new cmd to end */
	asmtflen += n;
	}

    return 0;				/* Say assembly was deferred */
    }

/*
 * EXECARGS - Get args, UNIX style, from exec or monitor TMPCOR file
 *	The code is given a char pointer to a TMPCOR-format file
 * in memory, and assumes that this memory will stay constant throughout
 * this invocation of KCC, so it is OK to traffic in pointers into this
 * area.
 */

char *
execargs (int *cntp, char ***vecp)
    {
#define MAXARGS 200
    static char *vecs[MAXARGS];		/* Easier than calloc */
    int c, vcnt;
    char *cp, *err = NULL;
    char *nextprog = NULL,
	 *p = gtmpfile("KCC"); /* Get temp file of this name */
#if DEBUG_KCC
    char *begp = p;
    int flen = strlen(begp); /* Remember length now before chopping it up */
#endif


    if (p == NULL)
	{
	*cntp = 0;
	*vecp = NULL;
	return NULL;
	}

    vecs[0] = "exec-args";	/* Always furnish 1st arg */
    vcnt = 1;
    while (1)			/* For each command line in file */
	/* Skip to start of input filename */
	{
	cp = p;			/* Remember start of stuff */
	while (1)
	    {
	    switch (c = *p)
		{
		case '=':		/* Found filename to compile? */
		    break;		/* just get out of loop. */

		case '\0':		/* Ran out of input */
		    if (cp != p)	/* If not at beg of line, */
			err = "command line doesn't end with CR or LF";
		    break;

		case '!':		/* Chain through this program */
		    if (cp == p)
			err = "null program name for chain";
		    *p = '\0';		/* Terminate program name */
		    nextprog = cp;	/* Save pointer to it */
		    if (*++p != '\r' && *p != '\n')	/* Must end in EOL */
			err = "no EOL after chain program name";
		    else if (*++p	/* If there is another char */
			&& ((*p != '\r' && *p != '\n')	/* it shd be EOL */
			   || *++p))	/* followed by a null. */
			err = "unexpected stuff after chain program name";
		    break;

		case '\r':
		case '\n':
		    if (cp == p)	/* Allow null lines */
			{
			cp = ++p;	/* Just reset ptr */
			continue;
			}
		    /* Line has something but we didn't understand it */
		    err = "command line not in recognized format";
		    break;

		default:
		    ++p;
		    continue;
		}
	    break;
	    }
	if (!c || err)		/* If hit end of input, or had error, */
	    break;		/* stop now. */

	c = *++p;		/* Hit '=', move on to next char */

    /*
    ** Allow /LANGUAGE-SWITCHES:" -x" to work
    ** This is done by scanning the argument string for spaces,
    ** and processing strings after the spaces as separate arguments.
    **
    ** We can't just do the usual thing of breaking on slashes
    ** because we treat those as parts of the filenames, for UNIX
    ** pseudo-compatibility.  This may change someday.
    */
	while(1)
	    {
	    while(c == ' ')
		c = *++p;	/* Skip over initial spaces */
	    vecs[vcnt] = p;		/* Remember this pointer */

	    while ((c != '\0') && (c != '\n') && (c != '\r')
			&& (c != ' '))
		{
		c = *++p;
		}
	    if (vecs[vcnt] != p)	/* Did we get anything? */
		{
		*p = '\0';		/* Yes, ensure null-terminated */
		if (vcnt >= MAXARGS-2)
		    {
		    err = "too many arguments!  (internal error)";
		    break;
		    }
		vcnt++;			/* Welcome it to the ranks */
		}
	    if (c != ' ')
		break;	/* Unless space, done */
	    } /* end inner loop (process line) */
	if (!c || err)
	    break;		/* If done or error, stop now */
	++p;				/* Move on to next char */
	}
    vecs[vcnt] = NULL;		/* Make list end with null */

#if DEBUG_KCC	/* 8/91 KCC size */
    if (tdebug || err)
	{
	if (err)
	    jerr("Bad exec/monitor args - %s", err);
	fprintf(outmsgs,"Contents of PRARG%%/TMPCOR file:\n");
	fwrite(begp, sizeof(char), flen, outmsgs);
	fprintf(outmsgs, "\nKCC args:");
	for (c = 0; c < vcnt; ++c)
	    fprintf(outmsgs, " %s", vecs[c]);
	fprintf(outmsgs, "\n");
	if (err)
	    {
	    *cntp = 0;
	    *vecp = NULL;
	    return NULL;
	    }
	}
#endif
    *cntp = vcnt;		/* Set return value = # of args */
    *vecp = vecs;
    return nextprog;
}

/* GTMPFILE - Get "temporary file" which contains arguments to program.
**	See description of RPG argument passing.
*/
static char *
gtmpfile(char *name)
{
    int nchars, i, c;
    char *cp, *rp;
    FILE *tf;
    char tmpfile[20];		/* For DSK:nnnNAM.TMP */
    int pid = 0;

    /* See if TMPCOR UUO has anything for us */
	{
	INT argblk[2];
	int junk, ret = 20;		/* MUUO call sets ret */
	char *tfbuf;

	argblk[0] = sixbit(name) & ~RH;		/* Set up TMPCOR arg blk */
	argblk[1] = XWD(0, &junk-1);
#ifdef __COMPILER_KCC__
	if (MUUO_ACVAL("TMPCOR", XWD(uuosym(".TCRRF"),argblk), &ret) > 0)
#endif
	    {
	/* If we succeed, file exists and # wds is now in ret */
	    if ((tfbuf = calloc(1,ret*sizeof(int)+1)) == NULL)
		{
		jerr("Unable to alloc %d wds for TMP file %s", ret,tmpfile);
		return NULL;
		}
	    argblk[1] = XWD(-ret, ((int *)tfbuf)-1);
	    tfbuf[ret*sizeof(int)] = '\0';	/* Ensure null-terminated */
#ifdef __COMPILER_KCC__	
	    if (MUUO_AC("TMPCOR", XWD(uuosym(".TCRDF"),argblk)) <= 0)
		{
		jerr("TMPCOR of %s failed on re-read", tmpfile);
		return NULL;
		}
	    return bp7(tfbuf);		/* Return 7-bit byte ptr */
#endif
	    }
	}

    /* Try opening a .TMP file */
    sprintf(tmpfile,
#if !__MSDOS__
	/* KAR-3/92, use new _getpid() macro instead of routine in LIBC */
	"DSK:%03.3d%.3s.TMP", ((pid == 0) ? _getpid(pid) : pid)
#else
	"%03.3d%.3s.TMP", getpid()
#endif
		    , name);
    if ((tf = fopen(tmpfile, "r")) == NULL)
	return NULL;
#define TMPBSIZ (0400*sizeof(int))		/* # chars in incr blk */
    nchars = TMPBSIZ;
    rp = calloc(1,nchars);
    cp = rp-1;
    for (;;)
	{
	if (rp == NULL)
	    {
	    jerr("Unable to alloc %d chars for TMP file %s", nchars, tmpfile);
	    return NULL;
	    }
	for (i = TMPBSIZ; --i >= 0;)
	    {
	    if ((c = getc(tf)) == EOF)
		{
		*++cp = 0;		/* Fix up last char */
		fclose(tf);		/* Close the stream */

		remove(tmpfile);
		return rp;		/* Won! */
		}
	    *++cp = c;
	    }
	rp = realloc(rp, (nchars + TMPBSIZ));
	if (rp)
	    cp = rp + nchars - 1;	/* Point to last char deposited */
	nchars += TMPBSIZ;
	}
}



/* STMPFILE - Set "temporary file" furnishing args to another program.
**	See description of RPG argument passing.
*/
#if 0				/* 8/91  KCC size */
static int usetmpcor = 0;	/* For time being, don't use it! */
#endif

static int *
stmpfile(char *name, char *str, char *nextprog)
{
    FILE *tf;
    char *cp = NULL;
    char tmpfile[20];		/* For DSK:nnnNAM.TMP */
    int nchs = strlen(str) + 1;		/* total chs we'll need */
    int pid = 0;

#if 0		/* 8/91  KCC size */
    int nwds = (nchs+4)/5;
#endif

    if (nextprog && *nextprog)
	{
	nchs += strlen(nextprog)+3;	/* nextprog can add ! and CRLF */
	if ((cp = calloc(1,nchs)) == NULL)
	    {
	    jerr("Cannot get memory for %s program args", name);
	    return NULL;
	    }
	estrcpy(estrcpy(estrcpy(cp, str), nextprog), "!\r\n");
	str = cp;
	}
    if (vrbld)
	fprintf(outmsgs, "%s program args: \"%s\"\n", name, str);

#if 0		/* 8/91  KCC size */
    /* Try invoking TMPCOR UUO */
    if (usetmpcor)
	{
	INT argblk[2];

	argblk[0] = sixbit(name) & ~RH;		/* Set up TMPCOR arg blk */
	argblk[1] = XWD(-nwds, ((int *)str)-1);
	strcpy(bp7(str), str); /* Make 7-bit buff */
	if (MUUO_AC("TMPCOR", XWD(uuosym(".TCRWF"),argblk)) > 0)
	    {
	    if (cp)
		free(cp);
	    return NULL;			/* Won, that's all! */
	    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -