/*
	Little Smalltalk
		misc lexer related routines
		timothy a. budd 12/84
*/
/*
	The source code for the Little Smalltalk System may be freely
	copied provided that the source of all files is acknowledged
	and that this condition is copied with each file.

	The Little Smalltalk System is distributed without responsibility
	for the performance of the program and without any guarantee of
	maintenance.

	All questions concerning Little Smalltalk should be addressed to:

		Professor Tim Budd
		Department of Computer Science
		The University of Arizona
		Tucson, Arizona
		85721
		USA
*/
# include <stdio.h>
# include "env.h"
# include <ctype.h>

extern char toktext[];

/* dolexcommand - read a ) type directive, and process it */
dolexcommand(p)
char *p;
{       char *q, buffer[100];

	/* replace trailing newline with end of string */
	for (q = p; *q && *q != '\n'; q++);
	if (*q == '\n') *q = '\0';

        switch( *++p) {
           case '!': 
# ifndef NOSYSTEM
		system(++p); 
# endif
		break;

           case 'e': for (++p; isspace(*p); p++);
		     if (! lexedit(p)) lexinclude(p);
                     break;

	   case 'g': for (++p; isspace(*p); p++);
		     sprintf(buffer,"%s/%s", LIBLOC, p);
		     lexread(buffer);
		     break;

           case 'i': for (++p; isspace(*p); p++);
                     lexinclude(p);
                     break;

           case 'r': for (++p; isspace(*p); p++);
                     lexread(p);
                     break;

	   case 's': for(++p; isspace(*p); p++);
		     dosave(p);
		     break;

	   case 'l': for(++p; isspace(*p); p++);
		     doload(p);
		     break;

           default:  lexerr("unknown command %s", toktext);
           }
}

/* doload/dosave routines written by nick buchholz */
/*
	doload and dosave routines make the following assumptions
	1. version is the first global variable declared in main.
	2. main is the first procedure seen by the loader
	3. the loader allocates memory in the order it sees the procedures
	4. memory is laid out as on the vax 780 under 4.2

	on other machines any or all of these might be false and the
	doload/dosave routines will not work
*/
extern int version;

dosave(p) char *p;{
    int fd; 
    char *start, *end, *sbrk(); 
    unsigned int length, len;
    int dlen;

# ifdef OPEN3ARG
    if ((fd = open(p, O_WRONLY|O_CREAT|O_TRUNC, 0666)) == -1)
# endif
# ifndef OPEN3ARG
    if ((fd = creat(p, 0666)) == -1)
# endif
   	fprintf(stderr,"can't open: %s\n",p);

    start = (char *) &version;
    end = sbrk(0);
    length = end - start;

    write(fd, &version, sizeof(int));
    write(fd, &start, sizeof(char *));
    write(fd, &length, sizeof(unsigned int));

    for (len = 0; len < length; len += dlen) {
	dlen = ((length - len) > 512) ? 512 : (length - len);
	if (dlen != write(fd, start + len, dlen)) {
		cant_happen(23);
		}
	}

    fprintf(stderr,"%u bytes written\n",len);

    close(fd);
}

# ifdef ENVSAVE
extern char **environ;
# endif

doload(p) char *p;{
    int fd; 
    char *start, *end, *brk(); 
    unsigned int length, len; 
    int dlen;
    int test;
# ifdef ENVSAVE
    char **evsave;
# endif

# ifdef OPEN3ARG
    if ((fd = open(p, O_RDONLY, 0)) == -1)
# endif
# ifndef OPEN3ARG
    if ((fd = open(p, 0 )) == -1)
# endif
	fprintf(stderr,"no such context as: %s\n", p);

    else {
	read(fd, &test, sizeof(int));
	read(fd, &start, sizeof(char *));
	read(fd, &length, sizeof(unsigned int));

	if ((test != version) || (start != (char *) &version))
	    fprintf(stderr,"%s: not a valid context file for version %d\n", 
				p, version);
	else {
	    start = (char *) &version;
	    end = brk(start + length + 1);
# ifdef ENVSAVE
	    evsave = environ;
# endif

    	    for (len = 0; len < length; len += dlen) {
		dlen = ((length - len) > 512) ? 512 : (length - len);
		if (dlen != read(fd, start + len, dlen)) {
			cant_happen(23);
			}
		}
# ifdef ENVSAVE
	   environ = evsave;
# endif
	    fprintf(stderr,"%u bytes read\n",len);
	}
	close(fd);
    }
}

/* lexread - read commands from a file */
lexread(name)
char *name;
{	FILE *fd;

	fd = fopen(name, "r");
	if (fd == NULL) {
		fprintf(stderr,"can't open %s\n", name);
		}
	else {
		set_file(fd);
		}
}

/* lexinclude - parse a class and include the class description */
lexinclude(name)
char *name;
{  char template[60], cmdbuf[120];
   int  i;

# ifndef NOSYSTEM
   gettemp(template);
   sprintf(cmdbuf,"%s %s %s", PARSER, name, template); /* WMK removed > */
   i = system(cmdbuf);
/* printf("%s = %d\n", cmdbuf, i); */
   if (i == 0)
   	lexread(template);
# endif
# ifdef NOSYSTEM
   fprintf(stderr,")i does not work on this system\n");
# endif
}

/* lexedit - edit a class description */
int lexedit(name)
char *name;
{	char *e, buffer[100], *getenv();

# ifndef NOSYSTEM
	e = getenv("EDITOR");
	if (!e) e = "ed";
	sprintf(buffer,"%s %s", e, name);
	return(system(buffer));
# endif
# ifdef NOSYSTEM
	fprintf(stderr,")e does not work on this system\n");
	return(1);
# endif
}

char *brk(addr) {return (addr);}

void *malloc();

char *sbrk(incr) {return (malloc(incr));}
