File:  [gforth] / gforth / engine / main.c
Revision 1.100: download - view: text, annotated - select for diffs
Thu Jan 30 16:14:31 2003 UTC (21 years, 2 months ago) by anton
Branches: MAIN
CVS tags: HEAD
eliminated some (hopefully outdated) hppa special treatments
rewrote hppa cacheflush
prims2x can now process CRLF inputs (but the output is partly unixified)
prims2x can now process several sync lines in sequence
minor fixes

    1: /* command line interpretation, image loading etc. for Gforth
    2: 
    3: 
    4:   Copyright (C) 1995,1996,1997,1998,2000 Free Software Foundation, Inc.
    5: 
    6:   This file is part of Gforth.
    7: 
    8:   Gforth is free software; you can redistribute it and/or
    9:   modify it under the terms of the GNU General Public License
   10:   as published by the Free Software Foundation; either version 2
   11:   of the License, or (at your option) any later version.
   12: 
   13:   This program is distributed in the hope that it will be useful,
   14:   but WITHOUT ANY WARRANTY; without even the implied warranty of
   15:   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   16:   GNU General Public License for more details.
   17: 
   18:   You should have received a copy of the GNU General Public License
   19:   along with this program; if not, write to the Free Software
   20:   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
   21: */
   22: 
   23: #include "config.h"
   24: #include "forth.h"
   25: #include <errno.h>
   26: #include <ctype.h>
   27: #include <stdio.h>
   28: #include <unistd.h>
   29: #include <string.h>
   30: #include <math.h>
   31: #include <sys/types.h>
   32: #ifndef STANDALONE
   33: #include <sys/stat.h>
   34: #endif
   35: #include <fcntl.h>
   36: #include <assert.h>
   37: #include <stdlib.h>
   38: #ifndef STANDALONE
   39: #if HAVE_SYS_MMAN_H
   40: #include <sys/mman.h>
   41: #endif
   42: #endif
   43: #include "io.h"
   44: #include "getopt.h"
   45: #ifdef STANDALONE
   46: #include <systypes.h>
   47: #endif
   48: 
   49: /* global variables for engine.c 
   50:    We put them here because engine.c is compiled several times in
   51:    different ways for the same engine. */
   52: Cell *SP;
   53: Float *FP;
   54: Address UP=NULL;
   55: 
   56: #ifdef GFORTH_DEBUGGING
   57: /* define some VM registers as global variables, so they survive exceptions;
   58:    global register variables are not up to the task (according to the 
   59:    GNU C manual) */
   60: Xt *saved_ip;
   61: Cell *rp;
   62: #endif
   63: 
   64: #ifdef NO_IP
   65: Label next_code;
   66: #endif
   67: 
   68: #ifdef HAS_FILE
   69: char* fileattr[6]={"rb","rb","r+b","r+b","wb","wb"};
   70: char* pfileattr[6]={"r","r","r+","r+","w","w"};
   71: 
   72: #ifndef O_BINARY
   73: #define O_BINARY 0
   74: #endif
   75: #ifndef O_TEXT
   76: #define O_TEXT 0
   77: #endif
   78: 
   79: int ufileattr[6]= {
   80:   O_RDONLY|O_BINARY, O_RDONLY|O_BINARY,
   81:   O_RDWR  |O_BINARY, O_RDWR  |O_BINARY,
   82:   O_WRONLY|O_BINARY, O_WRONLY|O_BINARY };
   83: #endif
   84: /* end global vars for engine.c */
   85: 
   86: #define PRIM_VERSION 1
   87: /* increment this whenever the primitives change in an incompatible way */
   88: 
   89: #ifndef DEFAULTPATH
   90: #  define DEFAULTPATH "."
   91: #endif
   92: 
   93: #ifdef MSDOS
   94: jmp_buf throw_jmp_buf;
   95: #endif
   96: 
   97: #if defined(DOUBLY_INDIRECT)
   98: #  define CFA(n)	({Cell _n = (n); ((Cell)(((_n & 0x4000) ? symbols : xts)+(_n&~0x4000UL)));})
   99: #else
  100: #  define CFA(n)	((Cell)(symbols+((n)&~0x4000UL)))
  101: #endif
  102: 
  103: #define maxaligned(n)	(typeof(n))((((Cell)n)+sizeof(Float)-1)&-sizeof(Float))
  104: 
  105: static UCell dictsize=0;
  106: static UCell dsize=0;
  107: static UCell rsize=0;
  108: static UCell fsize=0;
  109: static UCell lsize=0;
  110: int offset_image=0;
  111: int die_on_signal=0;
  112: #ifndef INCLUDE_IMAGE
  113: static int clear_dictionary=0;
  114: UCell pagesize=1;
  115: char *progname;
  116: #else
  117: char *progname = "gforth";
  118: int optind = 1;
  119: #endif
  120: 
  121: #define CODE_BLOCK_SIZE (256*1024)
  122: Address code_area=0;
  123: Cell code_area_size = CODE_BLOCK_SIZE;
  124: Address code_here=NULL+CODE_BLOCK_SIZE; /* does for code-area what HERE
  125: 					   does for the dictionary */
  126: Address start_flush=NULL; /* start of unflushed code */
  127: Cell last_jump=0; /* if the last prim was compiled without jump, this
  128:                      is it's number, otherwise this contains 0 */
  129: 
  130: static int no_super=0;   /* true if compile_prim should not fuse prims */
  131: static int no_dynamic=NO_DYNAMIC_DEFAULT; /* if true, no code is generated
  132: 					     dynamically */
  133: 
  134: #ifdef HAS_DEBUG
  135: int debug=0;
  136: #else
  137: # define perror(x...)
  138: # define fprintf(x...)
  139: #endif
  140: 
  141: ImageHeader *gforth_header;
  142: Label *vm_prims;
  143: #ifdef DOUBLY_INDIRECT
  144: Label *xts; /* same content as vm_prims, but should only be used for xts */
  145: #endif
  146: 
  147: #ifdef MEMCMP_AS_SUBROUTINE
  148: int gforth_memcmp(const char * s1, const char * s2, size_t n)
  149: {
  150:   return memcmp(s1, s2, n);
  151: }
  152: #endif
  153: 
  154: /* image file format:
  155:  *  "#! binary-path -i\n" (e.g., "#! /usr/local/bin/gforth-0.4.0 -i\n")
  156:  *   padding to a multiple of 8
  157:  *   magic: "Gforth3x" means format 0.6,
  158:  *              where x is a byte with
  159:  *              bit 7:   reserved = 0
  160:  *              bit 6:5: address unit size 2^n octets
  161:  *              bit 4:3: character size 2^n octets
  162:  *              bit 2:1: cell size 2^n octets
  163:  *              bit 0:   endian, big=0, little=1.
  164:  *  The magic are always 8 octets, no matter what the native AU/character size is
  165:  *  padding to max alignment (no padding necessary on current machines)
  166:  *  ImageHeader structure (see forth.h)
  167:  *  data (size in ImageHeader.image_size)
  168:  *  tags ((if relocatable, 1 bit/data cell)
  169:  *
  170:  * tag==1 means that the corresponding word is an address;
  171:  * If the word is >=0, the address is within the image;
  172:  * addresses within the image are given relative to the start of the image.
  173:  * If the word =-1 (CF_NIL), the address is NIL,
  174:  * If the word is <CF_NIL and >CF(DODOES), it's a CFA (:, Create, ...)
  175:  * If the word =CF(DODOES), it's a DOES> CFA
  176:  * If the word =CF(DOESJUMP), it's a DOES JUMP (2 Cells after DOES>,
  177:  *					possibly containing a jump to dodoes)
  178:  * If the word is <CF(DOESJUMP) and bit 14 is set, it's the xt of a primitive
  179:  * If the word is <CF(DOESJUMP) and bit 14 is clear, 
  180:  *                                        it's the threaded code of a primitive
  181:  * bits 13..9 of a primitive token state which group the primitive belongs to,
  182:  * bits 8..0 of a primitive token index into the group
  183:  */
  184: 
  185: static Cell groups[32] = {
  186:   0,
  187: #undef GROUP
  188: #define GROUP(x, n) DOESJUMP+1+n,
  189: #include "prim_grp.i"
  190: #undef GROUP
  191: #define GROUP(x, n)
  192: };
  193: 
  194: void relocate(Cell *image, const char *bitstring, 
  195:               int size, Cell base, Label symbols[])
  196: {
  197:   int i=0, j, k, steps=(size/sizeof(Cell))/RELINFOBITS;
  198:   Cell token;
  199:   char bits;
  200:   Cell max_symbols;
  201:   /* 
  202:    * A virtual start address that's the real start address minus 
  203:    * the one in the image 
  204:    */
  205:   Cell *start = (Cell * ) (((void *) image) - ((void *) base));
  206: 
  207:   /* group index into table */
  208:   
  209: /* printf("relocating to %x[%x] start=%x base=%x\n", image, size, start, base); */
  210:   
  211:   for (max_symbols=DOESJUMP+1; symbols[max_symbols]!=0; max_symbols++)
  212:     ;
  213:   max_symbols--;
  214:   size/=sizeof(Cell);
  215: 
  216:   for(k=0; k<=steps; k++) {
  217:     for(j=0, bits=bitstring[k]; j<RELINFOBITS; j++, i++, bits<<=1) {
  218:       /*      fprintf(stderr,"relocate: image[%d]\n", i);*/
  219:       if((i < size) && (bits & (1U << (RELINFOBITS-1)))) {
  220: 	/* fprintf(stderr,"relocate: image[%d]=%d of %d\n", i, image[i], size/sizeof(Cell)); */
  221:         token=image[i];
  222: 	if(token<0) {
  223: 	  int group = (-token & 0x3E00) >> 9;
  224: 	  if(group == 0) {
  225: 	    switch(token|0x4000) {
  226: 	    case CF_NIL      : image[i]=0; break;
  227: #if !defined(DOUBLY_INDIRECT)
  228: 	    case CF(DOCOL)   :
  229: 	    case CF(DOVAR)   :
  230: 	    case CF(DOCON)   :
  231: 	    case CF(DOUSER)  : 
  232: 	    case CF(DODEFER) : 
  233: 	    case CF(DOFIELD) : MAKE_CF(image+i,symbols[CF(token)]); break;
  234: 	    case CF(DOESJUMP): image[i]=0; break;
  235: #endif /* !defined(DOUBLY_INDIRECT) */
  236: 	    case CF(DODOES)  :
  237: 	      MAKE_DOES_CF(image+i,(Xt *)(image[i+1]+((Cell)start)));
  238: 	      break;
  239: 	    default          : /* backward compatibility */
  240: /*	      printf("Code field generation image[%x]:=CFA(%x)\n",
  241: 		     i, CF(image[i])); */
  242: 	      if (CF((token | 0x4000))<max_symbols) {
  243: 		image[i]=(Cell)CFA(CF(token));
  244: #ifdef DIRECT_THREADED
  245: 		if ((token & 0x4000) == 0) /* threade code, no CFA */
  246: 		  compile_prim1(&image[i]);
  247: #endif
  248: 	      } else
  249: 		fprintf(stderr,"Primitive %ld used in this image at $%lx is not implemented by this\n engine (%s); executing this code will crash.\n",(long)CF(token),(long)&image[i],PACKAGE_VERSION);
  250: 	    }
  251: 	  } else {
  252: 	    int tok = -token & 0x1FF;
  253: 	    if (tok < (groups[group+1]-groups[group])) {
  254: #if defined(DOUBLY_INDIRECT)
  255: 	      image[i]=(Cell)CFA(((groups[group]+tok) | (CF(token) & 0x4000)));
  256: #else
  257: 	      image[i]=(Cell)CFA((groups[group]+tok));
  258: #endif
  259: #ifdef DIRECT_THREADED
  260: 	      if ((token & 0x4000) == 0) /* threade code, no CFA */
  261: 		compile_prim1(&image[i]);
  262: #endif
  263: 	    } else
  264: 	      fprintf(stderr,"Primitive %lx, %d of group %d used in this image at $%lx is not implemented by this\n engine (%s); executing this code will crash.\n", (long)-token, tok, group, (long)&image[i],PACKAGE_VERSION);
  265: 	  }
  266: 	} else {
  267:           // if base is > 0: 0 is a null reference so don't adjust
  268:           if (token>=base) {
  269:             image[i]+=(Cell)start;
  270:           }
  271:         }
  272:       }
  273:     }
  274:   }
  275:   finish_code();
  276:   ((ImageHeader*)(image))->base = (Address) image;
  277: }
  278: 
  279: UCell checksum(Label symbols[])
  280: {
  281:   UCell r=PRIM_VERSION;
  282:   Cell i;
  283: 
  284:   for (i=DOCOL; i<=DOESJUMP; i++) {
  285:     r ^= (UCell)(symbols[i]);
  286:     r = (r << 5) | (r >> (8*sizeof(Cell)-5));
  287:   }
  288: #ifdef DIRECT_THREADED
  289:   /* we have to consider all the primitives */
  290:   for (; symbols[i]!=(Label)0; i++) {
  291:     r ^= (UCell)(symbols[i]);
  292:     r = (r << 5) | (r >> (8*sizeof(Cell)-5));
  293:   }
  294: #else
  295:   /* in indirect threaded code all primitives are accessed through the
  296:      symbols table, so we just have to put the base address of symbols
  297:      in the checksum */
  298:   r ^= (UCell)symbols;
  299: #endif
  300:   return r;
  301: }
  302: 
  303: Address verbose_malloc(Cell size)
  304: {
  305:   Address r;
  306:   /* leave a little room (64B) for stack underflows */
  307:   if ((r = malloc(size+64))==NULL) {
  308:     perror(progname);
  309:     exit(1);
  310:   }
  311:   r = (Address)((((Cell)r)+(sizeof(Float)-1))&(-sizeof(Float)));
  312:   if (debug)
  313:     fprintf(stderr, "malloc succeeds, address=$%lx\n", (long)r);
  314:   return r;
  315: }
  316: 
  317: static Address next_address=0;
  318: void after_alloc(Address r, Cell size)
  319: {
  320:   if (r != (Address)-1) {
  321:     if (debug)
  322:       fprintf(stderr, "success, address=$%lx\n", (long) r);
  323:     if (pagesize != 1)
  324:       next_address = (Address)(((((Cell)r)+size-1)&-pagesize)+2*pagesize); /* leave one page unmapped */
  325:   } else {
  326:     if (debug)
  327:       fprintf(stderr, "failed: %s\n", strerror(errno));
  328:   }
  329: }
  330: 
  331: #ifndef MAP_FAILED
  332: #define MAP_FAILED ((Address) -1)
  333: #endif
  334: #ifndef MAP_FILE
  335: # define MAP_FILE 0
  336: #endif
  337: #ifndef MAP_PRIVATE
  338: # define MAP_PRIVATE 0
  339: #endif
  340: #if !defined(MAP_ANON) && defined(MAP_ANONYMOUS)
  341: # define MAP_ANON MAP_ANONYMOUS
  342: #endif
  343: 
  344: #if defined(HAVE_MMAP)
  345: static Address alloc_mmap(Cell size)
  346: {
  347:   Address r;
  348: 
  349: #if defined(MAP_ANON)
  350:   if (debug)
  351:     fprintf(stderr,"try mmap($%lx, $%lx, ..., MAP_ANON, ...); ", (long)next_address, (long)size);
  352:   r = mmap(next_address, size, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
  353: #else /* !defined(MAP_ANON) */
  354:   /* Ultrix (at least) does not define MAP_FILE and MAP_PRIVATE (both are
  355:      apparently defaults) */
  356:   static int dev_zero=-1;
  357: 
  358:   if (dev_zero == -1)
  359:     dev_zero = open("/dev/zero", O_RDONLY);
  360:   if (dev_zero == -1) {
  361:     r = MAP_FAILED;
  362:     if (debug)
  363:       fprintf(stderr, "open(\"/dev/zero\"...) failed (%s), no mmap; ", 
  364: 	      strerror(errno));
  365:   } else {
  366:     if (debug)
  367:       fprintf(stderr,"try mmap($%lx, $%lx, ..., MAP_FILE, dev_zero, ...); ", (long)next_address, (long)size);
  368:     r=mmap(next_address, size, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_FILE|MAP_PRIVATE, dev_zero, 0);
  369:   }
  370: #endif /* !defined(MAP_ANON) */
  371:   after_alloc(r, size);
  372:   return r;  
  373: }
  374: #endif
  375: 
  376: Address my_alloc(Cell size)
  377: {
  378: #if HAVE_MMAP
  379:   Address r;
  380: 
  381:   r=alloc_mmap(size);
  382:   if (r!=MAP_FAILED)
  383:     return r;
  384: #endif /* HAVE_MMAP */
  385:   /* use malloc as fallback */
  386:   return verbose_malloc(size);
  387: }
  388: 
  389: Address dict_alloc_read(FILE *file, Cell imagesize, Cell dictsize, Cell offset)
  390: {
  391:   Address image = MAP_FAILED;
  392: 
  393: #if defined(HAVE_MMAP)
  394:   if (offset==0) {
  395:     image=alloc_mmap(dictsize);
  396:     if (debug)
  397:       fprintf(stderr,"try mmap($%lx, $%lx, ..., MAP_FIXED|MAP_FILE, imagefile, 0); ", (long)image, (long)imagesize);
  398:     image = mmap(image, imagesize, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_FIXED|MAP_FILE|MAP_PRIVATE, fileno(file), 0);
  399:     after_alloc(image,dictsize);
  400:   }
  401: #endif /* defined(HAVE_MMAP) */
  402:   if (image == MAP_FAILED) {
  403:     image = my_alloc(dictsize+offset)+offset;
  404:     rewind(file);  /* fseek(imagefile,0L,SEEK_SET); */
  405:     fread(image, 1, imagesize, file);
  406:   }
  407:   return image;
  408: }
  409: 
  410: void set_stack_sizes(ImageHeader * header)
  411: {
  412:   if (dictsize==0)
  413:     dictsize = header->dict_size;
  414:   if (dsize==0)
  415:     dsize = header->data_stack_size;
  416:   if (rsize==0)
  417:     rsize = header->return_stack_size;
  418:   if (fsize==0)
  419:     fsize = header->fp_stack_size;
  420:   if (lsize==0)
  421:     lsize = header->locals_stack_size;
  422:   dictsize=maxaligned(dictsize);
  423:   dsize=maxaligned(dsize);
  424:   rsize=maxaligned(rsize);
  425:   lsize=maxaligned(lsize);
  426:   fsize=maxaligned(fsize);
  427: }
  428: 
  429: void alloc_stacks(ImageHeader * header)
  430: {
  431:   header->dict_size=dictsize;
  432:   header->data_stack_size=dsize;
  433:   header->fp_stack_size=fsize;
  434:   header->return_stack_size=rsize;
  435:   header->locals_stack_size=lsize;
  436: 
  437:   header->data_stack_base=my_alloc(dsize);
  438:   header->fp_stack_base=my_alloc(fsize);
  439:   header->return_stack_base=my_alloc(rsize);
  440:   header->locals_stack_base=my_alloc(lsize);
  441: }
  442: 
  443: #warning You can ignore the warnings about clobbered variables in go_forth
  444: int go_forth(Address image, int stack, Cell *entries)
  445: {
  446:   volatile ImageHeader *image_header = (ImageHeader *)image;
  447:   Cell *sp0=(Cell*)(image_header->data_stack_base + dsize);
  448:   Cell *rp0=(Cell *)(image_header->return_stack_base + rsize);
  449:   Float *fp0=(Float *)(image_header->fp_stack_base + fsize);
  450: #ifdef GFORTH_DEBUGGING
  451:   volatile Cell *orig_rp0=rp0;
  452: #endif
  453:   Address lp0=image_header->locals_stack_base + lsize;
  454:   Xt *ip0=(Xt *)(image_header->boot_entry);
  455: #ifdef SYSSIGNALS
  456:   int throw_code;
  457: #endif
  458: 
  459:   /* ensure that the cached elements (if any) are accessible */
  460:   IF_spTOS(sp0--);
  461:   IF_fpTOS(fp0--);
  462:   
  463:   for(;stack>0;stack--)
  464:     *--sp0=entries[stack-1];
  465: 
  466: #ifdef SYSSIGNALS
  467:   get_winsize();
  468:    
  469:   install_signal_handlers(); /* right place? */
  470:   
  471:   if ((throw_code=setjmp(throw_jmp_buf))) {
  472:     static Cell signal_data_stack[8];
  473:     static Cell signal_return_stack[8];
  474:     static Float signal_fp_stack[1];
  475: 
  476:     signal_data_stack[7]=throw_code;
  477: 
  478: #ifdef GFORTH_DEBUGGING
  479:     if (debug)
  480:       fprintf(stderr,"\ncaught signal, throwing exception %d, ip=%p rp=%p\n",
  481: 	      throw_code, saved_ip, rp);
  482:     if (rp <= orig_rp0 && rp > (Cell *)(image_header->return_stack_base+5)) {
  483:       /* no rstack overflow or underflow */
  484:       rp0 = rp;
  485:       *--rp0 = (Cell)saved_ip;
  486:     }
  487:     else /* I love non-syntactic ifdefs :-) */
  488:       rp0 = signal_return_stack+8;
  489: #else  /* !defined(GFORTH_DEBUGGING) */
  490:     if (debug)
  491:       fprintf(stderr,"\ncaught signal, throwing exception %d\n", throw_code);
  492:       rp0 = signal_return_stack+8;
  493: #endif /* !defined(GFORTH_DEBUGGING) */
  494:     /* fprintf(stderr, "rp=$%x\n",rp0);*/
  495:     
  496:     return((int)(Cell)engine(image_header->throw_entry, signal_data_stack+7,
  497: 		       rp0, signal_fp_stack, 0));
  498:   }
  499: #endif
  500: 
  501:   return((int)(Cell)engine(ip0,sp0,rp0,fp0,lp0));
  502: }
  503: 
  504: #ifndef INCLUDE_IMAGE
  505: void print_sizes(Cell sizebyte)
  506:      /* print size information */
  507: {
  508:   static char* endianstring[]= { "   big","little" };
  509:   
  510:   fprintf(stderr,"%s endian, cell=%d bytes, char=%d bytes, au=%d bytes\n",
  511: 	  endianstring[sizebyte & 1],
  512: 	  1 << ((sizebyte >> 1) & 3),
  513: 	  1 << ((sizebyte >> 3) & 3),
  514: 	  1 << ((sizebyte >> 5) & 3));
  515: }
  516: 
  517: #define MAX_IMMARGS 2
  518: 
  519: #ifndef NO_DYNAMIC
  520: typedef struct {
  521:   Label start;
  522:   Cell length; /* only includes the jump iff superend is true*/
  523:   Cell restlength; /* length of the rest (i.e., the jump or (on superend) 0) */
  524:   char superend; /* true if primitive ends superinstruction, i.e.,
  525:                      unconditional branch, execute, etc. */
  526:   Cell nimmargs;
  527:   struct immarg {
  528:     Cell offset; /* offset of immarg within prim */
  529:     char rel;    /* true if immarg is relative */
  530:   } immargs[MAX_IMMARGS];
  531: } PrimInfo;
  532: 
  533: PrimInfo *priminfos;
  534: PrimInfo **decomp_prims;
  535: 
  536: int compare_priminfo_length(const void *_a, const void *_b)
  537: {
  538:   PrimInfo **a = (PrimInfo **)_a;
  539:   PrimInfo **b = (PrimInfo **)_b;
  540:   Cell diff = (*a)->length - (*b)->length;
  541:   if (diff)
  542:     return diff;
  543:   else /* break ties by start address; thus the decompiler produces
  544:           the earliest primitive with the same code (e.g. noop instead
  545:           of (char) and @ instead of >code-address */
  546:     return (*b)->start - (*a)->start;
  547: }
  548: 
  549: #endif /* defined(NO_DYNAMIC) */
  550: Cell npriminfos=0;
  551: 
  552: 
  553: void check_prims(Label symbols1[])
  554: {
  555:   int i;
  556: #ifndef NO_DYNAMIC
  557:   Label *symbols2, *symbols3, *ends1;
  558:   static char superend[]={
  559: #include "prim_superend.i"
  560:   };
  561: #endif
  562: 
  563:   if (debug)
  564: #ifdef __VERSION__
  565:     fprintf(stderr, "Compiled with gcc-" __VERSION__ "\n");
  566: #else
  567: #define xstr(s) str(s)
  568: #define str(s) #s
  569:   fprintf(stderr, "Compiled with gcc-" xstr(__GNUC__) "." xstr(__GNUC_MINOR__) "\n"); 
  570: #endif
  571:   for (i=DOESJUMP+1; symbols1[i+1]!=0; i++)
  572:     ;
  573:   npriminfos = i;
  574:   
  575: #ifndef NO_DYNAMIC
  576:   if (no_dynamic)
  577:     return;
  578:   symbols2=engine2(0,0,0,0,0);
  579: #if NO_IP
  580:   symbols3=engine3(0,0,0,0,0);
  581: #else
  582:   symbols3=symbols1;
  583: #endif
  584:   ends1 = symbols1+i+1-DOESJUMP;
  585:   priminfos = calloc(i,sizeof(PrimInfo));
  586:   for (i=DOESJUMP+1; symbols1[i+1]!=0; i++) {
  587:     int prim_len = ends1[i]-symbols1[i];
  588:     PrimInfo *pi=&priminfos[i];
  589:     int j=0;
  590:     char *s1 = (char *)symbols1[i];
  591:     char *s2 = (char *)symbols2[i];
  592:     char *s3 = (char *)symbols3[i];
  593: 
  594:     pi->start = s1;
  595:     pi->superend = superend[i-DOESJUMP-1]|no_super;
  596:     if (pi->superend)
  597:       pi->length = symbols1[i+1]-symbols1[i];
  598:     else
  599:       pi->length = prim_len;
  600:     pi->restlength = symbols1[i+1] - symbols1[i] - pi->length;
  601:     pi->nimmargs = 0;
  602:     if (debug)
  603:       fprintf(stderr, "Prim %3d @ %p %p %p, length=%3ld restlength=%2ld superend=%1d",
  604: 	      i, s1, s2, s3, (long)(pi->length), (long)(pi->restlength), pi->superend);
  605:     assert(prim_len>=0);
  606:     while (j<(pi->length+pi->restlength)) {
  607:       if (s1[j]==s3[j]) {
  608: 	if (s1[j] != s2[j]) {
  609: 	  pi->start = NULL; /* not relocatable */
  610: 	  if (debug)
  611: 	    fprintf(stderr,"\n   non_reloc: engine1!=engine2 offset %3d",j);
  612: 	  /* assert(j<prim_len); */
  613: 	  break;
  614: 	}
  615: 	j++;
  616:       } else {
  617: 	struct immarg *ia=&pi->immargs[pi->nimmargs];
  618: 
  619: 	pi->nimmargs++;
  620: 	ia->offset=j;
  621: 	if ((~*(Cell *)&(s1[j]))==*(Cell *)&(s3[j])) {
  622: 	  ia->rel=0;
  623: 	  if (debug)
  624: 	    fprintf(stderr,"\n   absolute immarg: offset %3d",j);
  625: 	} else if ((&(s1[j]))+(*(Cell *)&(s1[j]))+4 ==
  626: 		   symbols1[DOESJUMP+1]) {
  627: 	  ia->rel=1;
  628: 	  if (debug)
  629: 	    fprintf(stderr,"\n   relative immarg: offset %3d",j);
  630: 	} else {
  631: 	  pi->start = NULL; /* not relocatable */
  632: 	  if (debug)
  633: 	    fprintf(stderr,"\n   non_reloc: engine1!=engine3 offset %3d",j);
  634: 	  /* assert(j<prim_len);*/
  635: 	  break;
  636: 	}
  637: 	j+=4;
  638:       }
  639:     }
  640:     if (debug)
  641:       fprintf(stderr,"\n");
  642:   }
  643:   decomp_prims = calloc(i,sizeof(PrimInfo *));
  644:   for (i=DOESJUMP+1; i<npriminfos; i++)
  645:     decomp_prims[i] = &(priminfos[i]);
  646:   qsort(decomp_prims+DOESJUMP+1, npriminfos-DOESJUMP-1, sizeof(PrimInfo *),
  647: 	compare_priminfo_length);
  648: #endif
  649: }
  650: 
  651: void flush_to_here(void)
  652: {
  653: #ifndef NO_DYNAMIC
  654:   if (start_flush)
  655:     FLUSH_ICACHE(start_flush, code_here-start_flush);
  656:   start_flush=code_here;
  657: #endif
  658: }
  659: 
  660: #ifndef NO_DYNAMIC
  661: void append_jump(void)
  662: {
  663:   if (last_jump) {
  664:     PrimInfo *pi = &priminfos[last_jump];
  665:     
  666:     memcpy(code_here, pi->start+pi->length, pi->restlength);
  667:     code_here += pi->restlength;
  668:     last_jump=0;
  669:   }
  670: }
  671: 
  672: /* Gforth remembers all code blocks in this list.  On forgetting (by
  673: executing a marker) the code blocks are not freed (because Gforth does
  674: not remember how they were allocated; hmm, remembering that might be
  675: easier and cleaner).  Instead, code_here etc. are reset to the old
  676: value, and the "forgotten" code blocks are reused when they are
  677: needed. */
  678: 
  679: struct code_block_list {
  680:   struct code_block_list *next;
  681:   Address block;
  682:   Cell size;
  683: } *code_block_list=NULL, **next_code_blockp=&code_block_list;
  684: 
  685: Address append_prim(Cell p)
  686: {
  687:   PrimInfo *pi = &priminfos[p];
  688:   Address old_code_here = code_here;
  689: 
  690:   if (code_area+code_area_size < code_here+pi->length+pi->restlength) {
  691:     struct code_block_list *p;
  692:     append_jump();
  693:     flush_to_here();
  694:     if (*next_code_blockp == NULL) {
  695:       code_here = start_flush = code_area = my_alloc(code_area_size);
  696:       p = (struct code_block_list *)malloc(sizeof(struct code_block_list));
  697:       *next_code_blockp = p;
  698:       p->next = NULL;
  699:       p->block = code_here;
  700:       p->size = code_area_size;
  701:     } else {
  702:       p = *next_code_blockp;
  703:       code_here = start_flush = code_area = p->block;
  704:     }
  705:     old_code_here = code_here;
  706:     next_code_blockp = &(p->next);
  707:   }
  708:   memcpy(code_here, pi->start, pi->length);
  709:   code_here += pi->length;
  710:   return old_code_here;
  711: }
  712: #endif
  713: 
  714: int forget_dyncode(Address code)
  715: {
  716: #ifdef NO_DYNAMIC
  717:   return -1;
  718: #else
  719:   struct code_block_list *p, **pp;
  720: 
  721:   for (pp=&code_block_list, p=*pp; p!=NULL; pp=&(p->next), p=*pp) {
  722:     if (code >= p->block && code < p->block+p->size) {
  723:       next_code_blockp = &(p->next);
  724:       code_here = start_flush = code;
  725:       code_area = p->block;
  726:       last_jump = 0;
  727:       return -1;
  728:     }
  729:   }
  730:   return -no_dynamic;
  731: #endif /* !defined(NO_DYNAMIC) */
  732: }
  733: 
  734: Label decompile_code(Label _code)
  735: {
  736: #ifdef NO_DYNAMIC
  737:   return _code;
  738: #else /* !defined(NO_DYNAMIC) */
  739:   Cell i;
  740:   struct code_block_list *p;
  741:   Address code=_code;
  742: 
  743:   /* first, check if we are in code at all */
  744:   for (p = code_block_list;; p = p->next) {
  745:     if (p == NULL)
  746:       return code;
  747:     if (code >= p->block && code < p->block+p->size)
  748:       break;
  749:   }
  750:   /* reverse order because NOOP might match other prims */
  751:   for (i=npriminfos-1; i>DOESJUMP; i--) {
  752:     PrimInfo *pi=decomp_prims[i];
  753:     if (pi->start==code || (pi->start && memcmp(code,pi->start,pi->length)==0))
  754:       return pi->start;
  755:   }
  756:   return code;
  757: #endif /* !defined(NO_DYNAMIC) */
  758: }
  759: 
  760: #ifdef NO_IP
  761: int nbranchinfos=0;
  762: 
  763: struct branchinfo {
  764:   Label *targetptr; /* *(bi->targetptr) is the target */
  765:   Cell *addressptr; /* store the target here */
  766: } branchinfos[100000];
  767: 
  768: int ndoesexecinfos=0;
  769: struct doesexecinfo {
  770:   int branchinfo; /* fix the targetptr of branchinfos[...->branchinfo] */
  771:   Cell *xt; /* cfa of word whose does-code needs calling */
  772: } doesexecinfos[10000];
  773: 
  774: /* definitions of N_execute etc. */
  775: #include "prim_num.i"
  776: 
  777: void set_rel_target(Cell *source, Label target)
  778: {
  779:   *source = ((Cell)target)-(((Cell)source)+4);
  780: }
  781: 
  782: void register_branchinfo(Label source, Cell targetptr)
  783: {
  784:   struct branchinfo *bi = &(branchinfos[nbranchinfos]);
  785:   bi->targetptr = (Label *)targetptr;
  786:   bi->addressptr = (Cell *)source;
  787:   nbranchinfos++;
  788: }
  789: 
  790: Cell *compile_prim1arg(Cell p)
  791: {
  792:   int l = priminfos[p].length;
  793:   Address old_code_here=code_here;
  794: 
  795:   assert(vm_prims[p]==priminfos[p].start);
  796:   append_prim(p);
  797:   return (Cell*)(old_code_here+priminfos[p].immargs[0].offset);
  798: }
  799: 
  800: Cell *compile_call2(Cell targetptr)
  801: {
  802:   Cell *next_code_target;
  803:   PrimInfo *pi = &priminfos[N_call2];
  804:   Address old_code_here = append_prim(N_call2);
  805: 
  806:   next_code_target = (Cell *)(old_code_here + pi->immargs[0].offset);
  807:   register_branchinfo(old_code_here + pi->immargs[1].offset, targetptr);
  808:   return next_code_target;
  809: }
  810: #endif
  811: 
  812: void finish_code(void)
  813: {
  814: #ifdef NO_IP
  815:   Cell i;
  816: 
  817:   compile_prim1(NULL);
  818:   for (i=0; i<ndoesexecinfos; i++) {
  819:     struct doesexecinfo *dei = &doesexecinfos[i];
  820:     branchinfos[dei->branchinfo].targetptr = DOES_CODE1((dei->xt));
  821:   }
  822:   ndoesexecinfos = 0;
  823:   for (i=0; i<nbranchinfos; i++) {
  824:     struct branchinfo *bi=&branchinfos[i];
  825:     set_rel_target(bi->addressptr, *(bi->targetptr));
  826:   }
  827:   nbranchinfos = 0;
  828: #endif
  829:   flush_to_here();
  830: }
  831: 
  832: void compile_prim1(Cell *start)
  833: {
  834: #if defined(DOUBLY_INDIRECT)
  835:   Label prim=(Label)*start;
  836:   if (prim<((Label)(xts+DOESJUMP)) || prim>((Label)(xts+npriminfos))) {
  837:     fprintf(stderr,"compile_prim encountered xt %p\n", prim);
  838:     *start=(Cell)prim;
  839:     return;
  840:   } else {
  841:     *start = (Cell)(prim-((Label)xts)+((Label)vm_prims));
  842:     return;
  843:   }
  844: #elif defined(NO_IP)
  845:   static Cell *last_start=NULL;
  846:   static Xt last_prim=NULL;
  847:   /* delay work by one call in order to get relocated immargs */
  848: 
  849:   if (last_start) {
  850:     unsigned i = last_prim-vm_prims;
  851:     PrimInfo *pi=&priminfos[i];
  852:     Cell *next_code_target=NULL;
  853: 
  854:     assert(i<npriminfos);
  855:     if (i==N_execute||i==N_perform||i==N_lit_perform) {
  856:       next_code_target = compile_prim1arg(N_set_next_code);
  857:     }
  858:     if (i==N_call) {
  859:       next_code_target = compile_call2(last_start[1]);
  860:     } else if (i==N_does_exec) {
  861:       struct doesexecinfo *dei = &doesexecinfos[ndoesexecinfos++];
  862:       *compile_prim1arg(N_lit) = (Cell)PFA(last_start[1]);
  863:       /* we cannot determine the callee now (last_start[1] may be a
  864:          forward reference), so just register an arbitrary target, and
  865:          register in dei that we need to fix this before resolving
  866:          branches */
  867:       dei->branchinfo = nbranchinfos;
  868:       dei->xt = (Cell *)(last_start[1]);
  869:       next_code_target = compile_call2(NULL);
  870:     } else if (pi->start == NULL) { /* non-reloc */
  871:       next_code_target = compile_prim1arg(N_set_next_code);
  872:       set_rel_target(compile_prim1arg(N_abranch),*(Xt)last_prim);
  873:     } else {
  874:       unsigned j;
  875:       Address old_code_here = append_prim(i);
  876: 
  877:       for (j=0; j<pi->nimmargs; j++) {
  878: 	struct immarg *ia = &(pi->immargs[j]);
  879: 	Cell argval = last_start[pi->nimmargs - j]; /* !! specific to prims */
  880: 	if (ia->rel) { /* !! assumption: relative refs are branches */
  881: 	  register_branchinfo(old_code_here + ia->offset, argval);
  882: 	} else /* plain argument */
  883: 	  *(Cell *)(old_code_here + ia->offset) = argval;
  884:       }
  885:     }
  886:     if (next_code_target!=NULL)
  887:       *next_code_target = (Cell)code_here;
  888:   }
  889:   if (start) {
  890:     last_prim = (Xt)*start;
  891:     *start = (Cell)code_here;
  892:   }
  893:   last_start = start;
  894:   return;
  895: #elif !defined(NO_DYNAMIC)
  896:   Label prim=(Label)*start;
  897:   unsigned i;
  898:   Address old_code_here;
  899: 
  900:   i = ((Xt)prim)-vm_prims;
  901:   prim = *(Xt)prim;
  902:   if (no_dynamic) {
  903:     *start = (Cell)prim;
  904:     return;
  905:   }
  906:   if (i>=npriminfos || priminfos[i].start == 0) { /* not a relocatable prim */
  907:     append_jump();
  908:     *start = (Cell)prim;
  909:     return;
  910:   }
  911:   assert(priminfos[i].start = prim); 
  912: #ifdef ALIGN_CODE
  913:   /*  ALIGN_CODE;*/
  914: #endif
  915:   assert(prim==priminfos[i].start);
  916:   old_code_here = append_prim(i);
  917:   last_jump = (priminfos[i].superend) ? 0 : i;
  918:   *start = (Cell)old_code_here;
  919:   return;
  920: #else /* !defined(DOUBLY_INDIRECT), no code replication */
  921:   Label prim=(Label)*start;
  922: #if !defined(INDIRECT_THREADED)
  923:   prim = *(Xt)prim;
  924: #endif
  925:   *start = (Cell)prim;
  926:   return;
  927: #endif /* !defined(DOUBLY_INDIRECT) */
  928: }
  929: 
  930: Label compile_prim(Label prim)
  931: {
  932:   Cell x=(Cell)prim;
  933:   assert(0);
  934:   compile_prim1(&x);
  935:   return (Label)x;
  936: }
  937: 
  938: #if defined(PRINT_SUPER_LENGTHS) && !defined(NO_DYNAMIC)
  939: Cell prim_length(Cell prim)
  940: {
  941:   return priminfos[prim+DOESJUMP+1].length;
  942: }
  943: #endif
  944: 
  945: Address loader(FILE *imagefile, char* filename)
  946: /* returns the address of the image proper (after the preamble) */
  947: {
  948:   ImageHeader header;
  949:   Address image;
  950:   Address imp; /* image+preamble */
  951:   Char magic[8];
  952:   char magic7; /* size byte of magic number */
  953:   Cell preamblesize=0;
  954:   Cell data_offset = offset_image ? 56*sizeof(Cell) : 0;
  955:   UCell check_sum;
  956:   Cell ausize = ((RELINFOBITS ==  8) ? 0 :
  957: 		 (RELINFOBITS == 16) ? 1 :
  958: 		 (RELINFOBITS == 32) ? 2 : 3);
  959:   Cell charsize = ((sizeof(Char) == 1) ? 0 :
  960: 		   (sizeof(Char) == 2) ? 1 :
  961: 		   (sizeof(Char) == 4) ? 2 : 3) + ausize;
  962:   Cell cellsize = ((sizeof(Cell) == 1) ? 0 :
  963: 		   (sizeof(Cell) == 2) ? 1 :
  964: 		   (sizeof(Cell) == 4) ? 2 : 3) + ausize;
  965:   Cell sizebyte = (ausize << 5) + (charsize << 3) + (cellsize << 1) +
  966: #ifdef WORDS_BIGENDIAN
  967:        0
  968: #else
  969:        1
  970: #endif
  971:     ;
  972: 
  973:   vm_prims = engine(0,0,0,0,0);
  974:   check_prims(vm_prims);
  975: #ifndef DOUBLY_INDIRECT
  976: #ifdef PRINT_SUPER_LENGTHS
  977:   print_super_lengths();
  978: #endif
  979:   check_sum = checksum(vm_prims);
  980: #else /* defined(DOUBLY_INDIRECT) */
  981:   check_sum = (UCell)vm_prims;
  982: #endif /* defined(DOUBLY_INDIRECT) */
  983:   
  984:   do {
  985:     if(fread(magic,sizeof(Char),8,imagefile) < 8) {
  986:       fprintf(stderr,"%s: image %s doesn't seem to be a Gforth (>=0.6) image.\n",
  987: 	      progname, filename);
  988:       exit(1);
  989:     }
  990:     preamblesize+=8;
  991:   } while(memcmp(magic,"Gforth3",7));
  992:   magic7 = magic[7];
  993:   if (debug) {
  994:     magic[7]='\0';
  995:     fprintf(stderr,"Magic found: %s ", magic);
  996:     print_sizes(magic7);
  997:   }
  998: 
  999:   if (magic7 != sizebyte)
 1000:     {
 1001:       fprintf(stderr,"This image is:         ");
 1002:       print_sizes(magic7);
 1003:       fprintf(stderr,"whereas the machine is ");
 1004:       print_sizes(sizebyte);
 1005:       exit(-2);
 1006:     };
 1007: 
 1008:   fread((void *)&header,sizeof(ImageHeader),1,imagefile);
 1009: 
 1010:   set_stack_sizes(&header);
 1011:   
 1012: #if HAVE_GETPAGESIZE
 1013:   pagesize=getpagesize(); /* Linux/GNU libc offers this */
 1014: #elif HAVE_SYSCONF && defined(_SC_PAGESIZE)
 1015:   pagesize=sysconf(_SC_PAGESIZE); /* POSIX.4 */
 1016: #elif PAGESIZE
 1017:   pagesize=PAGESIZE; /* in limits.h according to Gallmeister's POSIX.4 book */
 1018: #endif
 1019:   if (debug)
 1020:     fprintf(stderr,"pagesize=%ld\n",(unsigned long) pagesize);
 1021: 
 1022:   image = dict_alloc_read(imagefile, preamblesize+header.image_size,
 1023: 			  preamblesize+dictsize, data_offset);
 1024:   imp=image+preamblesize;
 1025:   alloc_stacks((ImageHeader *)imp);
 1026:   if (clear_dictionary)
 1027:     memset(imp+header.image_size, 0, dictsize-header.image_size);
 1028:   if(header.base==0 || header.base  == (Address)0x100) {
 1029:     Cell reloc_size=((header.image_size-1)/sizeof(Cell))/8+1;
 1030:     char reloc_bits[reloc_size];
 1031:     fseek(imagefile, preamblesize+header.image_size, SEEK_SET);
 1032:     fread(reloc_bits, 1, reloc_size, imagefile);
 1033:     relocate((Cell *)imp, reloc_bits, header.image_size, (Cell)header.base, vm_prims);
 1034: #if 0
 1035:     { /* let's see what the relocator did */
 1036:       FILE *snapshot=fopen("snapshot.fi","wb");
 1037:       fwrite(image,1,imagesize,snapshot);
 1038:       fclose(snapshot);
 1039:     }
 1040: #endif
 1041:   }
 1042:   else if(header.base!=imp) {
 1043:     fprintf(stderr,"%s: Cannot load nonrelocatable image (compiled for address $%lx) at address $%lx\n",
 1044: 	    progname, (unsigned long)header.base, (unsigned long)imp);
 1045:     exit(1);
 1046:   }
 1047:   if (header.checksum==0)
 1048:     ((ImageHeader *)imp)->checksum=check_sum;
 1049:   else if (header.checksum != check_sum) {
 1050:     fprintf(stderr,"%s: Checksum of image ($%lx) does not match the executable ($%lx)\n",
 1051: 	    progname, (unsigned long)(header.checksum),(unsigned long)check_sum);
 1052:     exit(1);
 1053:   }
 1054: #ifdef DOUBLY_INDIRECT
 1055:   ((ImageHeader *)imp)->xt_base = xts;
 1056: #endif
 1057:   fclose(imagefile);
 1058: 
 1059:   /* unnecessary, except maybe for CODE words */
 1060:   /* FLUSH_ICACHE(imp, header.image_size);*/
 1061: 
 1062:   return imp;
 1063: }
 1064: 
 1065: /* pointer to last '/' or '\' in file, 0 if there is none. */
 1066: char *onlypath(char *filename)
 1067: {
 1068:   return strrchr(filename, DIRSEP);
 1069: }
 1070: 
 1071: FILE *openimage(char *fullfilename)
 1072: {
 1073:   FILE *image_file;
 1074:   char * expfilename = tilde_cstr(fullfilename, strlen(fullfilename), 1);
 1075: 
 1076:   image_file=fopen(expfilename,"rb");
 1077:   if (image_file!=NULL && debug)
 1078:     fprintf(stderr, "Opened image file: %s\n", expfilename);
 1079:   return image_file;
 1080: }
 1081: 
 1082: /* try to open image file concat(path[0:len],imagename) */
 1083: FILE *checkimage(char *path, int len, char *imagename)
 1084: {
 1085:   int dirlen=len;
 1086:   char fullfilename[dirlen+strlen(imagename)+2];
 1087: 
 1088:   memcpy(fullfilename, path, dirlen);
 1089:   if (fullfilename[dirlen-1]!=DIRSEP)
 1090:     fullfilename[dirlen++]=DIRSEP;
 1091:   strcpy(fullfilename+dirlen,imagename);
 1092:   return openimage(fullfilename);
 1093: }
 1094: 
 1095: FILE * open_image_file(char * imagename, char * path)
 1096: {
 1097:   FILE * image_file=NULL;
 1098:   char *origpath=path;
 1099:   
 1100:   if(strchr(imagename, DIRSEP)==NULL) {
 1101:     /* first check the directory where the exe file is in !! 01may97jaw */
 1102:     if (onlypath(progname))
 1103:       image_file=checkimage(progname, onlypath(progname)-progname, imagename);
 1104:     if (!image_file)
 1105:       do {
 1106: 	char *pend=strchr(path, PATHSEP);
 1107: 	if (pend==NULL)
 1108: 	  pend=path+strlen(path);
 1109: 	if (strlen(path)==0) break;
 1110: 	image_file=checkimage(path, pend-path, imagename);
 1111: 	path=pend+(*pend==PATHSEP);
 1112:       } while (image_file==NULL);
 1113:   } else {
 1114:     image_file=openimage(imagename);
 1115:   }
 1116: 
 1117:   if (!image_file) {
 1118:     fprintf(stderr,"%s: cannot open image file %s in path %s for reading\n",
 1119: 	    progname, imagename, origpath);
 1120:     exit(1);
 1121:   }
 1122: 
 1123:   return image_file;
 1124: }
 1125: #endif
 1126: 
 1127: #ifdef HAS_OS
 1128: UCell convsize(char *s, UCell elemsize)
 1129: /* converts s of the format [0-9]+[bekMGT]? (e.g. 25k) into the number
 1130:    of bytes.  the letter at the end indicates the unit, where e stands
 1131:    for the element size. default is e */
 1132: {
 1133:   char *endp;
 1134:   UCell n,m;
 1135: 
 1136:   m = elemsize;
 1137:   n = strtoul(s,&endp,0);
 1138:   if (endp!=NULL) {
 1139:     if (strcmp(endp,"b")==0)
 1140:       m=1;
 1141:     else if (strcmp(endp,"k")==0)
 1142:       m=1024;
 1143:     else if (strcmp(endp,"M")==0)
 1144:       m=1024*1024;
 1145:     else if (strcmp(endp,"G")==0)
 1146:       m=1024*1024*1024;
 1147:     else if (strcmp(endp,"T")==0) {
 1148: #if (SIZEOF_CHAR_P > 4)
 1149:       m=1024L*1024*1024*1024;
 1150: #else
 1151:       fprintf(stderr,"%s: size specification \"%s\" too large for this machine\n", progname, endp);
 1152:       exit(1);
 1153: #endif
 1154:     } else if (strcmp(endp,"e")!=0 && strcmp(endp,"")!=0) {
 1155:       fprintf(stderr,"%s: cannot grok size specification %s: invalid unit \"%s\"\n", progname, s, endp);
 1156:       exit(1);
 1157:     }
 1158:   }
 1159:   return n*m;
 1160: }
 1161: 
 1162: void gforth_args(int argc, char ** argv, char ** path, char ** imagename)
 1163: {
 1164:   int c;
 1165: 
 1166:   opterr=0;
 1167:   while (1) {
 1168:     int option_index=0;
 1169:     static struct option opts[] = {
 1170:       {"appl-image", required_argument, NULL, 'a'},
 1171:       {"image-file", required_argument, NULL, 'i'},
 1172:       {"dictionary-size", required_argument, NULL, 'm'},
 1173:       {"data-stack-size", required_argument, NULL, 'd'},
 1174:       {"return-stack-size", required_argument, NULL, 'r'},
 1175:       {"fp-stack-size", required_argument, NULL, 'f'},
 1176:       {"locals-stack-size", required_argument, NULL, 'l'},
 1177:       {"path", required_argument, NULL, 'p'},
 1178:       {"version", no_argument, NULL, 'v'},
 1179:       {"help", no_argument, NULL, 'h'},
 1180:       /* put something != 0 into offset_image */
 1181:       {"offset-image", no_argument, &offset_image, 1},
 1182:       {"no-offset-im", no_argument, &offset_image, 0},
 1183:       {"clear-dictionary", no_argument, &clear_dictionary, 1},
 1184:       {"die-on-signal", no_argument, &die_on_signal, 1},
 1185:       {"debug", no_argument, &debug, 1},
 1186:       {"no-super", no_argument, &no_super, 1},
 1187:       {"no-dynamic", no_argument, &no_dynamic, 1},
 1188:       {"dynamic", no_argument, &no_dynamic, 0},
 1189:       {0,0,0,0}
 1190:       /* no-init-file, no-rc? */
 1191:     };
 1192:     
 1193:     c = getopt_long(argc, argv, "+i:m:d:r:f:l:p:vhoncsx", opts, &option_index);
 1194:     
 1195:     switch (c) {
 1196:     case EOF: return;
 1197:     case '?': optind--; return;
 1198:     case 'a': *imagename = optarg; return;
 1199:     case 'i': *imagename = optarg; break;
 1200:     case 'm': dictsize = convsize(optarg,sizeof(Cell)); break;
 1201:     case 'd': dsize = convsize(optarg,sizeof(Cell)); break;
 1202:     case 'r': rsize = convsize(optarg,sizeof(Cell)); break;
 1203:     case 'f': fsize = convsize(optarg,sizeof(Float)); break;
 1204:     case 'l': lsize = convsize(optarg,sizeof(Cell)); break;
 1205:     case 'p': *path = optarg; break;
 1206:     case 'o': offset_image = 1; break;
 1207:     case 'n': offset_image = 0; break;
 1208:     case 'c': clear_dictionary = 1; break;
 1209:     case 's': die_on_signal = 1; break;
 1210:     case 'x': debug = 1; break;
 1211:     case 'v': fputs(PACKAGE_STRING"\n", stderr); exit(0);
 1212:     case 'h': 
 1213:       fprintf(stderr, "Usage: %s [engine options] ['--'] [image arguments]\n\
 1214: Engine Options:\n\
 1215:   --appl-image FILE		    equivalent to '--image-file=FILE --'\n\
 1216:   --clear-dictionary		    Initialize the dictionary with 0 bytes\n\
 1217:   -d SIZE, --data-stack-size=SIZE   Specify data stack size\n\
 1218:   --debug			    Print debugging information during startup\n\
 1219:   --die-on-signal		    exit instead of CATCHing some signals\n\
 1220:   --dynamic			    use dynamic native code\n\
 1221:   -f SIZE, --fp-stack-size=SIZE	    Specify floating point stack size\n\
 1222:   -h, --help			    Print this message and exit\n\
 1223:   -i FILE, --image-file=FILE	    Use image FILE instead of `gforth.fi'\n\
 1224:   -l SIZE, --locals-stack-size=SIZE Specify locals stack size\n\
 1225:   -m SIZE, --dictionary-size=SIZE   Specify Forth dictionary size\n\
 1226:   --no-dynamic			    Use only statically compiled primitives\n\
 1227:   --no-offset-im		    Load image at normal position\n\
 1228:   --no-super                        No dynamically formed superinstructions\n\
 1229:   --offset-image		    Load image at a different position\n\
 1230:   -p PATH, --path=PATH		    Search path for finding image and sources\n\
 1231:   -r SIZE, --return-stack-size=SIZE Specify return stack size\n\
 1232:   -v, --version			    Print engine version and exit\n\
 1233: SIZE arguments consist of an integer followed by a unit. The unit can be\n\
 1234:   `b' (byte), `e' (element; default), `k' (KB), `M' (MB), `G' (GB) or `T' (TB).\n",
 1235: 	      argv[0]);
 1236:       optind--;
 1237:       return;
 1238:     }
 1239:   }
 1240: }
 1241: #endif
 1242: 
 1243: #ifdef INCLUDE_IMAGE
 1244: extern Cell image[];
 1245: extern const char reloc_bits[];
 1246: #endif
 1247: 
 1248: int main(int argc, char **argv, char **env)
 1249: {
 1250: #ifdef HAS_OS
 1251:   char *path = getenv("GFORTHPATH") ? : DEFAULTPATH;
 1252: #else
 1253:   char *path = DEFAULTPATH;
 1254: #endif
 1255: #ifndef INCLUDE_IMAGE
 1256:   char *imagename="gforth.fi";
 1257:   FILE *image_file;
 1258:   Address image;
 1259: #endif
 1260:   int retvalue;
 1261: 	  
 1262: #if defined(i386) && defined(ALIGNMENT_CHECK)
 1263:   /* turn on alignment checks on the 486.
 1264:    * on the 386 this should have no effect. */
 1265:   __asm__("pushfl; popl %eax; orl $0x40000, %eax; pushl %eax; popfl;");
 1266:   /* this is unusable with Linux' libc.4.6.27, because this library is
 1267:      not alignment-clean; we would have to replace some library
 1268:      functions (e.g., memcpy) to make it work. Also GCC doesn't try to keep
 1269:      the stack FP-aligned. */
 1270: #endif
 1271: 
 1272:   /* buffering of the user output device */
 1273: #ifdef _IONBF
 1274:   if (isatty(fileno(stdout))) {
 1275:     fflush(stdout);
 1276:     setvbuf(stdout,NULL,_IONBF,0);
 1277:   }
 1278: #endif
 1279: 
 1280:   progname = argv[0];
 1281: 
 1282: #ifdef HAS_OS
 1283:   gforth_args(argc, argv, &path, &imagename);
 1284: #endif
 1285: 
 1286: #ifdef INCLUDE_IMAGE
 1287:   set_stack_sizes((ImageHeader *)image);
 1288:   if(((ImageHeader *)image)->base != image)
 1289:     relocate(image, reloc_bits, ((ImageHeader *)image)->image_size,
 1290: 	     (Label*)engine(0, 0, 0, 0, 0));
 1291:   alloc_stacks((ImageHeader *)image);
 1292: #else
 1293:   image_file = open_image_file(imagename, path);
 1294:   image = loader(image_file, imagename);
 1295: #endif
 1296:   gforth_header=(ImageHeader *)image; /* used in SIGSEGV handler */
 1297: 
 1298:   {
 1299:     char path2[strlen(path)+1];
 1300:     char *p1, *p2;
 1301:     Cell environ[]= {
 1302:       (Cell)argc-(optind-1),
 1303:       (Cell)(argv+(optind-1)),
 1304:       (Cell)strlen(path),
 1305:       (Cell)path2};
 1306:     argv[optind-1] = progname;
 1307:     /*
 1308:        for (i=0; i<environ[0]; i++)
 1309:        printf("%s\n", ((char **)(environ[1]))[i]);
 1310:        */
 1311:     /* make path OS-independent by replacing path separators with NUL */
 1312:     for (p1=path, p2=path2; *p1!='\0'; p1++, p2++)
 1313:       if (*p1==PATHSEP)
 1314: 	*p2 = '\0';
 1315:       else
 1316: 	*p2 = *p1;
 1317:     *p2='\0';
 1318:     retvalue = go_forth(image, 4, environ);
 1319: #ifdef VM_PROFILING
 1320:     vm_print_profile(stderr);
 1321: #endif
 1322:     deprep_terminal();
 1323:   }
 1324:   return retvalue;
 1325: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>