fseek(fout,hdr.tags+count*sizeof(FUNCSTUB),SEEK_SET); sc_writebin(fout,&func,sizeof func); fseek(fout,func.nameofs,SEEK_SET);
fseek(fout,tags+count*sizeof(FUNCSTUB),SEEK_SET); sc_writebin(fout,&func,sizeof func); fseek(fout,nameofs,SEEK_SET);
SC_FUNC void assemble(FILE *fout,FILE *fin){  typedef struct tagFUNCSTUB {    uint32_t address,nameofs;  } FUNCSTUB;  AMX_HEADER hdr;  FUNCSTUB func;  int numpublics,numnatives,numlibraries,numpubvars,numtags,padding;  long nametablesize,nameofs;  char line[256],*instr,*params;  int i,pass;  int16_t count;  symbol *sym, **nativelist;  constvalue *constptr;  cell mainaddr;  #if !defined NDEBUG    /* verify that the opcode list is sorted (skip entry 1; it is reserved     * for a non-existant opcode)     */    assert(opcodelist[1].name!=NULL);    for (i=2; i<(sizeof opcodelist / sizeof opcodelist[0]); i++) {      assert(opcodelist[i].name!=NULL);      assert(stricmp(opcodelist[i].name,opcodelist[i-1].name)>0);    } /* for */  #endif  writeerror=FALSE;  nametablesize=sizeof(int16_t);  numpublics=0;  numnatives=0;  numpubvars=0;  mainaddr=-1;  /* count number of public and native functions and public variables */  for (sym=glbtab.next; sym!=NULL; sym=sym->next) {    char alias[sNAMEMAX+1]="";    int match=0;    if (sym->ident==iFUNCTN) {      assert(strlen(sym->name)<=sNAMEMAX);      if ((sym->usage & uNATIVE)!=0 && (sym->usage & uREAD)!=0 && sym->addr>=0) {        match=++numnatives;        if (!lookup_alias(alias,sym->name))          strcpy(alias,sym->name);      } /* if */      if ((sym->usage & uPUBLIC)!=0 && (sym->usage & uDEFINE)!=0) {        match=++numpublics;        strcpy(alias,sym->name);      } /* if */      if (strcmp(sym->name,uMAINFUNC)==0) {        assert(sym->vclass==sGLOBAL);        mainaddr=sym->addr;      } /* if */    } else if (sym->ident==iVARIABLE) {      if ((sym->usage & uPUBLIC)!=0) {        match=++numpubvars;        strcpy(alias,sym->name);      } /* if */    } /* if */    if (match) {      assert(strlen(alias)>0);      nametablesize+=strlen(alias)+1;    } /* if */  } /* for */  assert(numnatives==ntv_funcid);  /* count number of libraries */  numlibraries=0;  for (constptr=libname_tab.next; constptr!=NULL; constptr=constptr->next) {    if (constptr->value>0) {      assert(strlen(constptr->name)>0);      numlibraries++;      nametablesize+=strlen(constptr->name)+1;    } /* if */  } /* for */  /* count number of public tags */  numtags=0;  for (constptr=tagname_tab.next; constptr!=NULL; constptr=constptr->next) {    if ((constptr->value & PUBLICTAG)!=0) {      assert(strlen(constptr->name)>0);      numtags++;      nametablesize+=strlen(constptr->name)+1;    } /* if */  } /* for */  /* pad the header to sc_dataalign   * => thereby the code segment is aligned   * => since the code segment is padded to a sc_dataalign boundary, the data segment is aligned   * => and thereby the stack top is aligned too   */  assert(sc_dataalign!=0);  padding= sc_dataalign - (sizeof hdr + nametablesize) % sc_dataalign;  if (padding==sc_dataalign)    padding=0;  /* write the abstract machine header */  memset(&hdr, 0, sizeof hdr);  hdr.magic=(unsigned short)0xF1E0;  hdr.file_version=CUR_FILE_VERSION;  hdr.amx_version=MIN_AMX_VERSION;  hdr.flags=(short)(sc_debug & sSYMBOLIC);  if (charbits==16)    hdr.flags|=AMX_FLAG_CHAR16;  if (sc_compress)    hdr.flags|=AMX_FLAG_COMPACT;  if (sc_debug==0)    hdr.flags|=AMX_FLAG_NOCHECKS;  #if BYTE_ORDER==BIG_ENDIAN    hdr.flags|=AMX_FLAG_BIGENDIAN;  #endif  hdr.defsize=sizeof(FUNCSTUB);  assert((hdr.defsize % sizeof(cell))==0);  hdr.publics=sizeof hdr; /* public table starts right after the header */  hdr.natives=hdr.publics + numpublics*sizeof(FUNCSTUB);  hdr.libraries=hdr.natives + numnatives*sizeof(FUNCSTUB);  hdr.pubvars=hdr.libraries + numlibraries*sizeof(FUNCSTUB);  hdr.tags=hdr.pubvars + numpubvars*sizeof(FUNCSTUB);  hdr.nametable=hdr.tags + numtags*sizeof(FUNCSTUB);  hdr.cod=hdr.nametable + nametablesize + padding;  hdr.dat=hdr.cod + code_idx;  hdr.hea=hdr.dat + glb_declared*sizeof(cell);  hdr.stp=hdr.hea + sc_stksize*sizeof(cell);  hdr.cip=mainaddr;  hdr.size=hdr.hea; /* preset, this is incorrect in case of compressed output */  #if BYTE_ORDER==BIG_ENDIAN    align32(&hdr.size);    align16(&hdr.magic);    align16(&hdr.flags);    align16(&hdr.defsize);    align32(&hdr.publics);    align32(&hdr.natives);    align32(&hdr.libraries);    align32(&hdr.pubvars);    align32(&hdr.tags);    align32(&hdr.nametable);    align32(&hdr.cod);    align32(&hdr.dat);    align32(&hdr.hea);    align32(&hdr.stp);    align32(&hdr.cip);  #endif  sc_writebin(fout,&hdr,sizeof hdr);  /* dump zeros up to the rest of the header, so that we can easily "seek" */  for (nameofs=sizeof hdr; nameofs<hdr.cod; nameofs++)    putc(0,fout);  nameofs=hdr.nametable+sizeof(int16_t);  /* write the public functions table */  count=0;  for (sym=glbtab.next; sym!=NULL; sym=sym->next) {    if (sym->ident==iFUNCTN        && (sym->usage & uPUBLIC)!=0 && (sym->usage & uDEFINE)!=0)    {      assert(sym->vclass==sGLOBAL);      func.address=sym->addr;      func.nameofs=nameofs;      #if BYTE_ORDER==BIG_ENDIAN        align32(&func.address);        align32(&func.nameofs);      #endif      fseek(fout,hdr.publics+count*sizeof(FUNCSTUB),SEEK_SET);      sc_writebin(fout,&func,sizeof func);      fseek(fout,func.nameofs,SEEK_SET);      sc_writebin(fout,sym->name,strlen(sym->name)+1);      nameofs+=strlen(sym->name)+1;      count++;    } /* if */  } /* for */  /* write the natives table */  /* The native functions must be written in sorted order. (They are   * sorted on their "id", not on their name). A nested loop to find   * each successive function would be an O(n^2) operation. But we   * do not really need to sort, because the native function id's   * are sequential and there are no duplicates. So we first walk   * through the complete symbol list and store a pointer to every   * native function of interest in a temporary table, where its id   * serves as the index in the table. Now we can walk the table and   * have all native functions in sorted order.   */  if (numnatives>0) {    nativelist=(symbol **)malloc(numnatives*sizeof(symbol *));    if (nativelist==NULL)      error(103);               /* insufficient memory */    #if !defined NDEBUG      memset(nativelist,0,numnatives*sizeof(symbol *)); /* for NULL checking */    #endif    for (sym=glbtab.next; sym!=NULL; sym=sym->next) {      if (sym->ident==iFUNCTN && (sym->usage & uNATIVE)!=0 && (sym->usage & uREAD)!=0 && sym->addr>=0) {        assert(sym->addr < numnatives);        nativelist[(int)sym->addr]=sym;      } /* if */    } /* for */    count=0;    for (i=0; i<numnatives; i++) {      char alias[sNAMEMAX+1];      sym=nativelist[i];      assert(sym!=NULL);      if (!lookup_alias(alias,sym->name)) {        assert(strlen(sym->name)<=sNAMEMAX);        strcpy(alias,sym->name);      } /* if */      assert(sym->vclass==sGLOBAL);      func.address=0;      func.nameofs=nameofs;      #if BYTE_ORDER==BIG_ENDIAN        align32(&func.address);        align32(&func.nameofs);      #endif      fseek(fout,hdr.natives+count*sizeof(FUNCSTUB),SEEK_SET);      sc_writebin(fout,&func,sizeof func);      fseek(fout,func.nameofs,SEEK_SET);      sc_writebin(fout,alias,strlen(alias)+1);      nameofs+=strlen(alias)+1;      count++;    } /* for */    free(nativelist);  } /* if */  /* write the libraries table */  count=0;  for (constptr=libname_tab.next; constptr!=NULL; constptr=constptr->next) {    if (constptr->value>0) {      assert(strlen(constptr->name)>0);      func.address=0;      func.nameofs=nameofs;      #if BYTE_ORDER==BIG_ENDIAN        align32(&func.address);        align32(&func.nameofs);      #endif      fseek(fout,hdr.libraries+count*sizeof(FUNCSTUB),SEEK_SET);      sc_writebin(fout,&func,sizeof func);      fseek(fout,func.nameofs,SEEK_SET);      sc_writebin(fout,constptr->name,strlen(constptr->name)+1);      nameofs+=strlen(constptr->name)+1;      count++;    } /* if */  } /* for */  /* write the public variables table */  count=0;  for (sym=glbtab.next; sym!=NULL; sym=sym->next) {    if (sym->ident==iVARIABLE && (sym->usage & uPUBLIC)!=0) {      assert((sym->usage & uDEFINE)!=0);      assert(sym->vclass==sGLOBAL);      func.address=sym->addr;      func.nameofs=nameofs;      #if BYTE_ORDER==BIG_ENDIAN        align32(&func.address);        align32(&func.nameofs);      #endif      fseek(fout,hdr.pubvars+count*sizeof(FUNCSTUB),SEEK_SET);      sc_writebin(fout,&func,sizeof func);      fseek(fout,func.nameofs,SEEK_SET);      sc_writebin(fout,sym->name,strlen(sym->name)+1);      nameofs+=strlen(sym->name)+1;      count++;    } /* if */  } /* for */  /* write the public tagnames table */  count=0;  for (constptr=tagname_tab.next; constptr!=NULL; constptr=constptr->next) {    if ((constptr->value & PUBLICTAG)!=0) {      assert(strlen(constptr->name)>0);      func.address=constptr->value & TAGMASK;      func.nameofs=nameofs;      #if BYTE_ORDER==BIG_ENDIAN        align32(&func.address);        align32(&func.nameofs);      #endif      fseek(fout,hdr.tags+count*sizeof(FUNCSTUB),SEEK_SET);      sc_writebin(fout,&func,sizeof func);      fseek(fout,func.nameofs,SEEK_SET);      sc_writebin(fout,constptr->name,strlen(constptr->name)+1);      nameofs+=strlen(constptr->name)+1;      count++;    } /* if */  } /* for */  /* write the "maximum name length" field in the name table */  assert(nameofs==hdr.nametable+nametablesize);  fseek(fout,hdr.nametable,SEEK_SET);  count=sNAMEMAX;  #if BYTE_ORDER==BIG_ENDIAN    align16(&count);  #endif  sc_writebin(fout,&count,sizeof count);  fseek(fout,hdr.cod,SEEK_SET);  /* First pass: relocate all labels */  /* This pass is necessary because the code addresses of labels is only known   * after the peephole optimization flag. Labels can occur inside expressions   * (e.g. the conditional operator), which are optimized.   */  lbltab=NULL;  if (labnum>0) {    /* only very short programs have zero labels; no first pass is needed     * if there are no labels */    lbltab=(cell *)malloc(labnum*sizeof(cell));    if (lbltab==NULL)      error(103);               /* insufficient memory */    codeindex=0;    sc_resetasm(fin);    while (sc_readasm(fin,line,sizeof line)!=NULL) {      stripcomment(line);      instr=skipwhitespace(line);      /* ignore empty lines */      if (*instr=='\0')        continue;      if (tolower(*instr)=='l' && *(instr+1)=='.') {        int lindex=(int)hex2long(instr+2,NULL);        assert(lindex<labnum);        lbltab[lindex]=codeindex;      } else {        /* get to the end of the instruction (make use of the '\n' that fgets()         * added at the end of the line; this way we will *always* drop on a         * whitespace character) */        for (params=instr; *params!='\0' && !isspace(*params); params++)          /* nothing */;        assert(params>instr);        i=findopcode(instr,(int)(params-instr));        if (opcodelist[i].name==NULL) {          *params='\0';          error(104,instr);     /* invalid assembler instruction */        } /* if */        if (opcodelist[i].segment==sIN_CSEG)          codeindex+=opcodelist[i].func(NULL,skipwhitespace(params),opcodelist[i].opcode);      } /* if */    } /* while */  } /* if */  /* Second pass (actually 2 more passes, one for all code and one for all data) */  bytes_in=0;  bytes_out=0;  for (pass=sIN_CSEG; pass<=sIN_DSEG; pass++) {    sc_resetasm(fin);    while (sc_readasm(fin,line,sizeof line)!=NULL) {      stripcomment(line);      instr=skipwhitespace(line);      /* ignore empty lines and labels (labels have a special syntax, so these       * must be parsed separately) */      if (*instr=='\0' || tolower(*instr)=='l' && *(instr+1)=='.')        continue;      /* get to the end of the instruction (make use of the '\n' that fgets()       * added at the end of the line; this way we will *always* drop on a       * whitespace character) */      for (params=instr; *params!='\0' && !isspace(*params); params++)        /* nothing */;      assert(params>instr);      i=findopcode(instr,(int)(params-instr));      assert(opcodelist[i].name!=NULL);      if (opcodelist[i].segment==pass)        opcodelist[i].func(fout,skipwhitespace(params),opcodelist[i].opcode);    } /* while */  } /* for */  if (bytes_out-bytes_in>0)    error(106);         /* compression buffer overflow */  if (lbltab!=NULL) {    free(lbltab);    #if !defined NDEBUG      lbltab=NULL;    #endif  } /* if */  if (writeerror)    error(101,"disk full");  /* adjust the header */  if (sc_compress) {    hdr.size=sc_lengthbin(fout);    #if BYTE_ORDER==BIG_ENDIAN      align32(&hdr.size);    #endif    sc_resetbin(fout);  /* "size" is the very first field */    sc_writebin(fout,&hdr.size,sizeof hdr.size);  } /* if */}