int get_next_line(int const fd, char **line) { static char *rest[256] = {NULL}; int ret; char *buf; char *tmp; if (fd < 0 || fd == 1 || fd == 2 || BUFF_SIZE <= 0 || !line) return (-1); if (!rest[fd % 256]) { if (!(rest[fd % 256] = ft_strnew(BUFF_SIZE))) return (-1); if (read(fd, rest[fd % 256], BUFF_SIZE) == -1) return (-1); } if (!init_char(line, &buf)) return (-1); tmp = buf; ret = end_line(&rest[fd % 256], line, fd, buf); ft_memdel((void **)&tmp); if (ret == 0 && ft_strlen(rest[fd % 256]) > 0) { ft_memdel((void**)&rest[fd % 256]); return (1); } return (ret); }
static intptr_t open_conf_file(){ char_t *s=init_char(); add_chars(s,DAWN_HOME); add_chars(s,CONF_FILE); add_terminal(s); intptr_t fd=open(s->data,O_RDWR); if(fd==-1){ my_log(ERROR,"open config file error\n"); } destroy_char(s); return fd; }
int main(void) { char *line; char p[20]; char c; char *co; t_game *filler; c = 'p'; line = NULL; get_next_line(0, &co); c = init_char(co); ft_strcpy(p, "5 11\n"); while (get_next_line(0, &line)) if (ft_strlen(line) > 0) { filler = get_data(c, line); set_p(p, filler); free_filler(&filler); write(1, p, ft_strlen(p)); } return (0); }
/** * 加载配置文件 */ void init_conf(){ buffer_t *rbuf=alloc_buffer(CONF_READ_BUF); int fd=open_conf_file(); enum PARSE_STATE status=RAW; config_module_t *current_module; command_t *current_command; char_t *module_name=init_char(); char_t *command_key=init_char(); char_t *command_value=init_char(); while(1){ if(has_space(rbuf)){ intptr_t count=read(fd,rbuf->data+rbuf->limit,rbuf->size-rbuf->limit); if(count<=0){ goto CONFIG_END; } rbuf->limit+=count; } while(has_remaining(rbuf)){ char c=*(rbuf->data+rbuf->current); rbuf->current+=1; if(status==RAW&&c==brace_start){ status=MODULE_START; }else if(status==MODULE_START&&!char_is_special(c)){ if(c==brace_start){ add_terminal(module_name); current_module=find_config_module(module_name); if(current_module==NULL){ my_log(ERROR,"config error,please check\n"); goto CONFIG_END; }else{ status=FIND_COMMAND_KEY; } }else if(c==brace_end){ goto CONFIG_END; }else{ add_char(module_name,c); } }else if(status==FIND_COMMAND_KEY&&!char_is_special(c)){ if(c==brace_end){ current_module=NULL; reset_char(module_name); status=MODULE_START; }else{ add_char(command_key,c); status=COMMAND_KEY_START; } }else if(status==COMMAND_KEY_START){ if(!char_is_special(c)){ add_char(command_key,c); }else{ add_terminal(command_key); current_command=find_config_command(command_key,current_module); if(current_command==NULL){ my_log(ERROR,"config error,please check\n"); goto CONFIG_END; } status=COMMAND_VALUE_START; } }else if(status==COMMAND_VALUE_START&&!char_is_special(c)){ if(c!=semicolon){ add_char(command_value,c); }else{ add_terminal(command_value); current_command->set_value(command_value); current_command=NULL; reset_char(command_value); reset_char(command_key); status=FIND_COMMAND_KEY; } } } } CONFIG_END: destroy_buffer(rbuf); }
Datum custom_check(PG_FUNCTION_ARGS) { char *us = GET_STR(PG_GETARG_TEXT_P(0)); char *ge = GET_STR(PG_GETARG_TEXT_P(1)); short i; short is_tag; char *tag = NULL; char *value = NULL; struct User u = {NULL, NULL, 0, NULL, 0, NULL, 0}; short test; short ok; ok = 0; tag = init_char(); value = init_char(); is_tag = 1; for (i=0;us[i]!='\0';i++) { if (us[i] == ':') { is_tag = 0; } else if (us[i] == 'T') { append_char(&tag, us[i]); is_tag = 0; } else if (us[i] == ',') { user_add(&u, tag, value); is_tag = 1; pfree(tag); tag = init_char(); value = init_char(); } else if (is_tag == 1) { append_char(&tag, us[i]); } else { append_char(&value, us[i]); } } user_add(&u, tag, value); pfree(tag); test = 1; ok = 0; tag = init_char(); value = init_char(); is_tag = 1; for (i=0;ge[i]!='\0';i++) { if (ge[i] == ':') { is_tag = 0; } else if (ge[i] == 'T') { append_char(&tag, ge[i]); is_tag = 0; } else if (ge[i] == '+') { is_tag = 1; test *= check(u, tag, value); pfree(value); pfree(tag); if (test == 1) ok = 1; test = 1; tag = init_char(); value = init_char(); } else if (ge[i] == '*') { is_tag = 1; test *= check(u, tag, value); pfree(tag); pfree(value); tag = init_char(); value = init_char(); } else if (is_tag) { append_char(&tag, ge[i]); } else { append_char(&value, ge[i]); } } test *= check(u, tag, value); if (test == 1) ok = 1; pfree(tag); pfree(value); user_free(u); PG_RETURN_BOOL(ok == 1); }
int render_line(int buf, int uline) { if(bufs[buf].lpt[uline]) { int pline; for(pline=0;pline<bufs[buf].lpl[uline];pline++) free(bufs[buf].lpt[uline][pline]); free(bufs[buf].lpt[uline]); } if( // this is quite a complicated conditional, so I've split it up. It handles conference mode, quiet mode and debug mode (bufs[buf].conf&&( (bufs[buf].lm[uline]==JOIN) ||(bufs[buf].lm[uline]==PART) ||(bufs[buf].lm[uline]==NICK) ||(bufs[buf].lm[uline]==MODE) ||(bufs[buf].lm[uline]==QUIT) ) ) || (quiet&&(bufs[buf].lq[uline]==QUIET)) || (!debug&&(bufs[buf].lq[uline]==DEBUG)) ) { bufs[buf].lpt[uline]=NULL; bufs[buf].lpl[uline]=0; return(0); } char *tag=strdup(bufs[buf].ltag[uline]?bufs[buf].ltag[uline]:""); bool mergetype=((bufs[buf].lm[uline]==JOIN)&&*tag)||(bufs[buf].lm[uline]==PART)||(bufs[buf].lm[uline]==QUIT); bool merged=false; if(merge&&(bufs[buf].type==CHANNEL)&&mergetype) { int prevline=uline; while(1) { if(--prevline<0) { prevline+=bufs[buf].nlines; if(!bufs[buf].filled) break; } if(fabs(difftime(bufs[buf].ts[prevline], bufs[buf].ts[uline]))>5) break; if(bufs[buf].lm[prevline]==bufs[buf].lm[uline]) { if((bufs[buf].lm[uline]==QUIT)&&strcmp(bufs[buf].lt[uline], bufs[buf].lt[prevline])) break; const char *ltag=bufs[buf].ltag[prevline]; if(!ltag) ltag=""; if((bufs[buf].lm[uline]==JOIN)&&!*ltag) break; size_t nlen=strlen(tag)+strlen(ltag)+2; char *ntag=malloc(nlen); snprintf(ntag, nlen, "%s=%s", ltag, tag); free(tag); tag=ntag; int pline; for(pline=0;pline<bufs[buf].lpl[prevline];pline++) free(bufs[buf].lpt[prevline][pline]); free(bufs[buf].lpt[prevline]); bufs[buf].lpt[prevline]=NULL; bufs[buf].lpl[prevline]=0; merged=true; continue; } break; } } char *message=strdup(bufs[buf].lt[uline]); char *proc;size_t l,i; init_char(&proc, &l, &i); char stamp[STAMP_LEN]; timestamp(stamp, bufs[buf].ts[uline]); colour c={.fore=7, .back=0, .hi=false, .ul=false}; switch(bufs[buf].lm[uline]) { case MSG: { c=c_msg[bufs[buf].ls[uline]?0:1]; char mk[6]="<%s> "; if(show_prefix&&bufs[buf].lp[uline]) { mk[0]=mk[3]=bufs[buf].lp[uline]; } crush(&tag, maxnlen); char *ntag=mktag(mk, tag); free(tag); tag=ntag; } break; case NOTICE: { c=c_notice[bufs[buf].ls[uline]?0:1]; if(*tag) { crush(&tag, maxnlen); char *ntag=mktag("(%s) ", tag); free(tag); tag=ntag; } } break; case PREFORMAT: c=c_notice[bufs[buf].ls[uline]?0:1]; break; case ACT: { c=c_actn[bufs[buf].ls[uline]?0:1]; crush(&tag, maxnlen); char *ntag=mktag("* %s ", tag); free(tag); tag=ntag; } break; case JOIN: c=c_join[bufs[buf].ls[uline]?0:1]; if(tag&&*tag) { free(message); const char *bn=bufs[buf].bname; if(!bn) bn="the channel"; size_t l=16+strlen(bn); message=malloc(l); if(merged) snprintf(message, l, "have joined %s", bufs[buf].bname); else snprintf(message, l, "has joined %s", bufs[buf].bname); } goto eqtag; case PART: c=c_part[bufs[buf].ls[uline]?0:1]; if(tag&&*tag) { free(message); const char *bn=bufs[buf].bname; if(!bn) bn="the channel"; size_t l=16+strlen(bn); message=malloc(l); if(merged) snprintf(message, l, "have left %s", bufs[buf].bname); else snprintf(message, l, "has left %s", bufs[buf].bname); } goto eqtag; case QUIT: c=c_quit[bufs[buf].ls[uline]?0:1]; if(tag&&*tag) { const char *bn=bufs[buf].bname; if(!bn) bn="the channel"; size_t l=16+strlen(bn)+strlen(message); char *nmessage=malloc(l); if(merged) snprintf(nmessage, l, "have left %s (%s)", bufs[buf].bname, message); else snprintf(nmessage, l, "has left %s (%s)", bufs[buf].bname, message); free(message); message=nmessage; } goto eqtag; case QUIT_PREFORMAT: c=c_quit[bufs[buf].ls[uline]?0:1]; break; case NICK: { c=c_nick[bufs[buf].ls[uline]?0:1]; eqtag: if(!merge) crush(&tag, maxnlen); char *ntag=mktag("=%s= ", tag); free(tag); tag=ntag; } break; case MODE: c=c_nick[bufs[buf].ls[uline]?0:1]; break; case STA: c=c_status; break; case ERR: c=c_err; break; case UNK: c=c_unk; break; case UNK_NOTICE: c=c_unk; if(*tag) { crush(&tag, maxnlen); char *ntag=mktag("(%s) ", tag); free(tag); tag=ntag; } break; case UNN: c=c_unn; break; default: break; } int x=wordline(stamp, 0, &proc, &l, &i, c); x=wordline(tag, indent?x:0, &proc, &l, &i, c); free(tag); wordline(message, indent?x:0, &proc, &l, &i, c); free(message); bufs[buf].lpl[uline]=0; bufs[buf].lpt[uline]=NULL; bufs[buf].lpc[uline]=c; char *curr=strtok(proc, "\n"); while(curr) { int pline=bufs[buf].lpl[uline]++; char **nlpt=realloc(bufs[buf].lpt[uline], bufs[buf].lpl[uline]*sizeof(char *)); if(!nlpt) { add_to_buffer(0, ERR, NORMAL, 0, false, "realloc failed; buffer may be corrupted", "render_buffer: "); free(proc); return(1); } (bufs[buf].lpt[uline]=nlpt)[pline]=strdup(curr); curr=strtok(NULL, "\n"); } free(proc); return(0); } void in_update(iline inp) { height=max(height, 5); // anything less than this is /silly/ width=max(width, 30); // widths less than 30 break things, and are /also silly/ resetcol(); locate(height-1, 1); // tab strip int mbw = (width-1)/nbufs; if(mbw>1) { int b; for(b=0;b<nbufs;b++) { colour c={7, hilite_tabstrip?5:0, false, false}; setcolour(c); putchar(' '); // (status) {server} [channel] <user> char brack[2]={'!', '!'}; switch(bufs[b].type) { case STATUS: brack[0]='(';brack[1]=')'; break; case SERVER: brack[0]='{';brack[1]='}'; break; case CHANNEL: brack[0]='[';brack[1]=']'; break; case PRIVATE: brack[0]='<';brack[1]='>'; break; } if(b==cbuf) { c.back=2; // green c.hi=true; } else if(b==bufs[cbuf].server) { c.back=4; // blue c.ul=true; } if(bufs[b].hi_alert%2) { c.fore=6; // cyan c.hi=true; } else if(bufs[b].alert) { c.fore=1; // red c.hi=true; } if((!LIVE(b)) && (c.fore!=6)) { c.fore=3; // yellow c.hi=true; } setcolour(c); putchar(brack[0]); if(mbw>3) { char *tab=strdup(bufs[b].bname); if(bufs[b].type==SERVER) { scrush(&tab, mbw-3); } else { crush(&tab, mbw-3); } printf("%s", tab); free(tab); } if(mbw>2) putchar(brack[1]); c.fore=7; c.back=hilite_tabstrip?5:0; c.hi=c.ul=false; setcolour(c); } } else { setcolour((colour){.fore=0, .back=1, .hi=true, .ul=false}); printf("buf %u [0 to %u]", cbuf, nbufs-1); }
/* * Loads a character for review. */ void do_rload( CHAR_DATA *ch, char *arg ) { char *name; CHAR_DATA *rch; DESCRIPTOR_DATA *d; char strsave[MAX_INPUT_LENGTH]; FILE *fp; if ( arg == NULL || arg[0] == '\0' ) { send_to_char("Syntax: rload <character>\n\r", ch ); return; } name = capitalize( arg ); for ( rch = char_list; rch != NULL; rch = rch->next ) { if ( !IS_NPC(rch) && !str_cmp( rch->name, name ) ) { send_to_char("That character is already in the game.\n\r", ch ); return; } } for ( d = descriptor_list; d != NULL; d = d->next ) { if ( d->character == NULL ) continue; if ( !str_cmp( d->character->name, name ) ) { send_to_char("That character is logging on.\n\r", ch ); return; } } sprintf( strsave, "%s%s", PLAYER_DIR, name ); if ( ( fp = fopen( strsave, "r" ) ) == NULL ) { sprintf( strsave, "%s%s", UNAPPROVED_DIR, name ); fp = fopen( strsave, "r" ); } if ( fp == NULL ) { sprintf( strsave, "%s%s", REJECTED_DIR, name ); fp = fopen( strsave, "r" ); } if ( fp == NULL ) { send_to_char("No such character exists.\n\r", ch ); return; } if ( char_free == NULL ) { rch = alloc_perm( sizeof(*ch) ); } else { rch = char_free; char_free = char_free->next; } clear_char( rch ); init_char( rch, name, TRUE ); rch->desc = NULL; load_char_from_file( rch, fp ); fclose( fp ); char_to_room( rch, get_room_index( ROOM_VNUM_REVIEW_ROOM ), FALSE ); SET_BIT( rch->act, PLR_REVIEWING ); rch->next = char_list; char_list = rch; send_to_char( "Character loaded to review room.\n\r", ch ); return; }
int main(int argc, char *argv[]) { /* SET UP TABLES ETC */ mktoktbl(); /* END: SET UP TABLES ETC */ /* PARSE ARGUMENTS */ int ninbas=0; char **inbas=NULL; int ninobj=0; char **inobj=NULL; enum {NONE, OBJ, TAPE} outtype=NONE; char *outfile=NULL; bool emu=false; int arg; int state=0; for(arg=1;arg<argc;arg++) { char *varg=argv[arg]; if(strcmp(varg, "-")==0) varg="/dev/stdin"; if(*varg=='-') { if(strcmp(varg, "-V")==0) { printf(VERSION_MSG); return(EXIT_SUCCESS); } else if(strcmp(varg, "--emu")==0) { emu=true; } else if(strcmp(varg, "--no-emu")==0) { emu=false; } else if(strcmp(varg, "--debug")==0) { debug=true; } else if(strcmp(varg, "--no-debug")==0) { debug=false; } else if(strcmp(varg, "-b")==0) state=1; else if(strcmp(varg, "-l")==0) state=7; else if(strcmp(varg, "-t")==0) state=2; else if(strcmp(varg, "-W")==0) state=3; else if(strcmp(varg, "-W-")==0) state=4; else if(strcmp(varg, "-O")==0) state=5; else if(strcmp(varg, "-O-")==0) state=6; else { fprintf(stderr, "bast: No such option %s\n", varg); return(EXIT_FAILURE); } } else { bool flag=false; switch(state) { case 0: case 1: if(addinbas(&ninbas, &inbas, varg)) { fprintf(stderr, "bast: Internal error: Failed to add %s to inbas list\n", varg); return(EXIT_FAILURE); } state=0; break; case 7: if(addinbas(&ninobj, &inobj, varg)) { fprintf(stderr, "bast: Internal error: Failed to add %s to inobj list\n", varg); return(EXIT_FAILURE); } state=0; break; case 2: outtype=TAPE; outfile=strdup(varg); state=0; break; case 3: flag=true; // fallthrough case 4: if(strcmp("all", varg)==0) { Wobjlen=flag; state=0; } else if(strcmp("object-length", varg)==0) { Wobjlen=flag; state=0; } else if(strcmp("object-checksum", varg)==0) { Wobjsum=flag; state=0; } else if(strcmp("se-basic", varg)==0) { Wsebasic=flag; state=0; } else if(strcmp("embedded-newline", varg)==0) { Wembeddednewline=flag; state=0; } break; case 5: flag=true; // fallthrough case 6: if(strcmp("cut-numbers", varg)==0) { Ocutnumbers=flag; state=0; } break; default: fprintf(stderr, "bast: Internal error: Bad state %u in args\n", state); return(EXIT_FAILURE); break; } } } /* END: PARSE ARGUMENTS */ if(!(ninbas||ninobj)) { fprintf(stderr, "bast: No input files specified\n"); return(EXIT_FAILURE); } if((outtype==NONE)||!outfile) { fprintf(stderr, "bast: No output file specified\n"); return(EXIT_FAILURE); } int nsegs=0; segment * data=NULL; /* READ BASIC FILES */ if(ninbas&&!inbas) { fprintf(stderr, "bast: Internal error: ninbas!=0 and inbas is NULL\n"); return(EXIT_FAILURE); } int fbas; for(fbas=0;fbas<ninbas;fbas++) { int fline=0; int dfl=0; FILE *fp=fopen(inbas[fbas], "r"); if(!fp) { fprintf(stderr, "bast: Failed to open input file %s\n", inbas[fbas]); return(EXIT_FAILURE); } segment *curr=addsegment(&nsegs, &data); if(!curr) { fprintf(stderr, "bast: Internal error: failed to add segment for file %s\n", inbas[fbas]); return(EXIT_FAILURE); } curr->name=(char *)malloc(10); sprintf(curr->name, "bas%u", fbas); curr->type=BASIC; curr->data.bas.nlines=0; curr->data.bas.basic=NULL; curr->data.bas.line=0; curr->data.bas.lline=NULL; curr->data.bas.renum=0; curr->data.bas.block=NULL; while(!feof(fp)) { char *line=fgetl(fp); if(line) { fline+=dfl+1; dfl=0; if(*line) { while(line[strlen(line)-1]=='\\') // line splicing { char *second=fgetl(fp); if(!second) continue; dfl++; if(!*second) { free(second); continue; } line[strlen(line)-1]=0; char *splice=(char *)realloc(line, strlen(line)+strlen(second)+2); if(!splice) { free(second); continue; } line=splice; strcat(splice, second); free(second); } if(Wembeddednewline && strchr(line, '\x0D')) // 0x0D is newline in ZX BASIC { fprintf(stderr, "bast: Warning: embedded newline (\\0D) in ZX Basic line\n\t"LOC"\n", LOCARG); } if(addbasline(&curr->data.bas.nlines, &curr->data.bas.basic, line)) { fprintf(stderr, "bast: Internal error: Failed to store line as text\n\t"LOC"\n", LOCARG); return(EXIT_FAILURE); } curr->data.bas.basic[curr->data.bas.nlines-1].sline=fline; if(*line=='#') { char *cmd=strtok(line, " "); if(cmd) { if(strcmp(cmd, "#pragma")==0) { char *prgm=strtok(NULL, " "); if(prgm) { if(strcmp(prgm, "name")==0) { char *basname=strtok(NULL, ""); if(basname) { if(curr->name) free(curr->name); curr->name=strdup(basname); } } else if(strcmp(prgm, "line")==0) { char *pline=strtok(NULL, ""); if(pline) { unsigned int val; if(sscanf(pline, "%u", &val)==1) { curr->data.bas.line=val; } else { curr->data.bas.line=-1; curr->data.bas.lline=strdup(pline); } } else { fprintf(stderr, "bast: Warning: #pragma line missing argument\n\t"LOC"\n", LOCARG); } } else if(strcmp(prgm, "renum")==0) { curr->data.bas.renum=1; curr->data.bas.rnstart=0; curr->data.bas.rnoffset=0; curr->data.bas.rnend=0; char *arg=strtok(NULL, " "); while(arg) { unsigned int val=0; if(*arg) sscanf(arg+1, "%u", &val); switch(*arg) { case '=': curr->data.bas.rnstart=val; break; case '+': curr->data.bas.rnoffset=val; break; case '-': curr->data.bas.rnend=val; break; default: fprintf(stderr, "bast: Warning: #pragma renum bad argument %s\n\t"LOC"\n", arg, LOCARG); break; } arg=strtok(NULL, " "); } } else { fprintf(stderr, "bast: Warning: #pragma %s not recognised (ignoring)\n\t"LOC"\n", prgm, LOCARG); } } else { fprintf(stderr, "bast: #pragma without identifier\n\t"LOC"\n", LOCARG); return(EXIT_FAILURE); } } else if(strcmp(cmd, "##")==0) { // comment, ignore } else { fprintf(stderr, "bast: Unrecognised directive %s\n\t"LOC"\n", cmd, LOCARG); return(EXIT_FAILURE); } } } } free(line); } } fprintf(stderr, "bast: BASIC segment '%s', read %u physical lines\n", curr->name, curr->data.bas.nlines); } /* END: READ BASIC FILES */ /* READ OBJECT FILES */ int fobj; for(fobj=0;fobj<ninobj;fobj++) { FILE *fp=fopen(inobj[fobj], "r"); if(!fp) { fprintf(stderr, "bast: Failed to open input file %s\n", inobj[fobj]); return(EXIT_FAILURE); } segment *curr=addsegment(&nsegs, &data); if(!curr) { fprintf(stderr, "bast: Internal error: failed to add segment for file %s\n", inobj[fobj]); return(EXIT_FAILURE); } curr->name=(char *)malloc(10); sprintf(curr->name, "bin%u", fobj); curr->type=BINARY; err=false; bin_load(inobj[fobj], fp, &curr->data.bin, &curr->name); if(err) { fprintf(stderr, "bast: Failed to load BINARY segment from file %s\n", inobj[fobj]); return(EXIT_FAILURE); } } /* END: READ OBJECT FILES */ /* TODO: fork the assembler for each #[r]asm/#endasm block */ /* TOKENISE BASIC SEGMENTS */ if(ninbas) { int i; for(i=0;i<nsegs;i++) { if(data[i].type==BASIC) { data[i].data.bas.blines=0; fprintf(stderr, "bast: Tokenising BASIC segment %s\n", data[i].name); int j; for(j=0;j<data[i].data.bas.nlines;j++) { err=false; if(debug) fprintf(stderr, "bast: tokenising line %s\n", data[i].data.bas.basic[j].text); tokenise(&data[i].data.bas.basic[j], inbas, i, data[i].data.bas.renum); if(data[i].data.bas.basic[j].ntok) data[i].data.bas.blines++; if(err) return(EXIT_FAILURE); } fprintf(stderr, "bast: Tokenised BASIC segment %s (%u logical lines)\n", data[i].name, data[i].data.bas.blines); } } } /* END: TOKENISE BASIC SEGMENTS */ /* LINKER & LABELS */ // PASS 1: Find labels, renumber labelled BASIC sources, load in !links as attached bin_segs int nlabels=0; label * labels=NULL; int i; for(i=0;i<nsegs;i++) { fprintf(stderr, "bast: Linker (Pass 1): %s\n", data[i].name); switch(data[i].type) { case BASIC:; int num=0,dnum=0; if(data[i].data.bas.renum==1) { dnum=data[i].data.bas.rnoffset?data[i].data.bas.rnoffset:10; int end=data[i].data.bas.rnend?data[i].data.bas.rnend:9999; while(data[i].data.bas.blines*dnum>end) { dnum--; if((dnum==7)||(dnum==9)) dnum--; } if(!dnum) { fprintf(stderr, "bast: Renumber: Couldn't fit %s into available lines\n", data[i].name); return(EXIT_FAILURE); } num=data[i].data.bas.rnstart?data[i].data.bas.rnstart:dnum; fprintf(stderr, "bast: Renumber: BASIC segment %s, start %u, spacing %u, end <=%u\n", data[i].name, num, dnum, end); } int dl; init_char(&data[i].data.bas.block, &dl, (int *)&data[i].data.bas.blen); int last=0; int j; for(j=0;j<data[i].data.bas.nlines;j++) { if(data[i].data.bas.basic[j].ntok) { if(num) { if(data[i].data.bas.renum!=1) { fprintf(stderr, "bast: Linker (Pass 1): Internal error (num!=0 but renum!=1), %s\n", data[i].name); return(EXIT_FAILURE); } data[i].data.bas.basic[j].number=num; num+=dnum; } else { if(data[i].data.bas.renum) { fprintf(stderr, "bast: Linker (Pass 1): Internal error (num==0 but renum!=0), %s\n", data[i].name); return(EXIT_FAILURE); } while(last<nlabels) { labels[last].sline=j; labels[last++].line=data[i].data.bas.basic[j].number; } } int k; for(k=0;k<data[i].data.bas.basic[j].ntok;k++) { if(data[i].data.bas.basic[j].tok[k].tok==TOKEN_RLINK) { if(data[i].data.bas.basic[j].tok[k].data) { FILE *fp=fopen(data[i].data.bas.basic[j].tok[k].data, "rb"); if(fp) { data[i].data.bas.basic[j].tok[k].data2=(char *)malloc(sizeof(bin_seg)); err=false; bin_load(data[i].data.bas.basic[j].tok[k].data, fp, (bin_seg *)data[i].data.bas.basic[j].tok[k].data2, NULL); if(err) { fprintf(stderr, "bast: Linker: failed to attach BINARY segment\n\t%s:%u\n", data[i].name, j); return(EXIT_FAILURE); } } else { fprintf(stderr, "bast: Linker: failed to open rlinked file %s\n\t%s:%u\n", data[i].data.bas.basic[j].tok[k].data, data[i].name, j); return(EXIT_FAILURE); } } else { fprintf(stderr, "bast: Linker: Internal error: TOKEN_RLINK without filename\n\t%s:%u", data[i].name, j); return(EXIT_FAILURE); } } } } else if(*data[i].data.bas.basic[j].text=='.') { if(isvalidlabel(data[i].data.bas.basic[j].text+1)) { label lbl; lbl.text=strdup(data[i].data.bas.basic[j].text+1); lbl.seg=i; lbl.line=num; lbl.sline=j; addlabel(&nlabels, &labels, lbl); } } } buildbas(&data[i].data.bas, false); if(data[i].data.bas.blen==-1) { fprintf(stderr, "bast: Failed to link BASIC segment %s\n", data[i].name); return(EXIT_FAILURE); } if(data[i].data.bas.renum) data[i].data.bas.renum=2; break; case BINARY: // TODO: export symbol table (we don't have symbols in object files yet) // Nothing else on pass 1 break; default: fprintf(stderr, "bast: Linker: Internal error: Bad segment-type %u\n", data[i].type); return(EXIT_FAILURE); break; } } // PASS 2: Replace labels with the linenumbers/addresses to which they point for(i=0;i<nsegs;i++) { fprintf(stderr, "bast: Linker (Pass 2): %s\n", data[i].name); switch(data[i].type) { case BASIC: if(data[i].data.bas.line<0) { if(!data[i].data.bas.lline) { fprintf(stderr, "bast: Linker: Internal error: line<0 but lline=NULL, %s\n", data[i].name); return(EXIT_FAILURE); } int l; for(l=0;l<nlabels;l++) { // TODO limit label scope to this file & the files it has #imported if((data[labels[l].seg].type==BASIC) && (strcmp(data[i].data.bas.lline, labels[l].text)==0)) { data[i].data.bas.line=labels[l].line; break; } } if(l==nlabels) { fprintf(stderr, "bast: Linker: Undefined label %s\n\t%s:#pragma line\n", data[i].data.bas.lline, data[i].name); return(EXIT_FAILURE); } } int j; for(j=0;j<data[i].data.bas.nlines;j++) { int k; for(k=0;k<data[i].data.bas.basic[j].ntok;k++) { if(data[i].data.bas.basic[j].tok[k].tok==TOKEN_LABEL) { int l; for(l=0;l<nlabels;l++) { // TODO limit label scope to this file & the files it has #imported if((data[labels[l].seg].type==BASIC) && (strcmp(data[i].data.bas.basic[j].tok[k].data, labels[l].text)==0)) { if(debug) fprintf(stderr, "bast: Linker: expanded %%%s", data[i].data.bas.basic[j].tok[k].data); if(data[i].data.bas.basic[j].tok[k].index) { if(debug) fprintf(stderr, "%s%02x", data[i].data.bas.basic[j].tok[k].index>0?"+":"-", abs(data[i].data.bas.basic[j].tok[k].index)); } data[i].data.bas.basic[j].tok[k].tok=TOKEN_ZXFLOAT; if(Ocutnumbers) { data[i].data.bas.basic[j].tok[k].data=strdup("."); if(debug) fprintf(stderr, " to %u (cut)\n", labels[l].line+data[i].data.bas.basic[j].tok[k].index); } else { data[i].data.bas.basic[j].tok[k].data=(char *)malloc(6); sprintf(data[i].data.bas.basic[j].tok[k].data, "%05u", labels[l].line+data[i].data.bas.basic[j].tok[k].index); if(debug) fprintf(stderr, " to %s\n", data[i].data.bas.basic[j].tok[k].data); } data[i].data.bas.basic[j].tok[k].data2=(char *)malloc(6); zxfloat(data[i].data.bas.basic[j].tok[k].data2, labels[l].line+data[i].data.bas.basic[j].tok[k].index); break; } } if(l==nlabels) { fprintf(stderr, "bast: Linker: Undefined label %s\n\t"LOC"\n", data[i].data.bas.basic[j].tok[k].data, data[i].name, j); return(EXIT_FAILURE); } } else if(data[i].data.bas.basic[j].tok[k].tok==TOKEN_PTRLBL) { int l; for(l=0;l<nlabels;l++) { // TODO limit label scope to this file & the files it has #imported if((data[labels[l].seg].type==BASIC) && (strcmp(data[i].data.bas.basic[j].tok[k].data, labels[l].text)==0)) { if(debug) fprintf(stderr, "bast: Linker: expanded @%s", data[i].data.bas.basic[j].tok[k].data); if(data[i].data.bas.basic[j].tok[k].index) { if(debug) fprintf(stderr, "%s%02x", data[i].data.bas.basic[j].tok[k].index>0?"+":"-", abs(data[i].data.bas.basic[j].tok[k].index)); } data[i].data.bas.basic[j].tok[k].tok=TOKEN_ZXFLOAT; if(Ocutnumbers) { data[i].data.bas.basic[j].tok[k].data=strdup("."); if(debug) fprintf(stderr, " to %u (cut)\n", (unsigned int)data[labels[l].seg].data.bas.basic[labels[l].sline].offset+data[i].data.bas.basic[j].tok[k].index); } else { data[i].data.bas.basic[j].tok[k].data=(char *)malloc(6); sprintf(data[i].data.bas.basic[j].tok[k].data, "%05u", (unsigned int)data[labels[l].seg].data.bas.basic[labels[l].sline].offset+data[i].data.bas.basic[j].tok[k].index); if(debug) fprintf(stderr, " to %s\n", data[i].data.bas.basic[j].tok[k].data); } data[i].data.bas.basic[j].tok[k].data2=(char *)malloc(6); zxfloat(data[i].data.bas.basic[j].tok[k].data2, data[labels[l].seg].data.bas.basic[labels[l].sline].offset+data[i].data.bas.basic[j].tok[k].index); break; } } if(l==nlabels) { fprintf(stderr, "bast: Linker: Undefined label %s\n\t"LOC"\n", data[i].data.bas.basic[j].tok[k].data, data[i].name, j); return(EXIT_FAILURE); } } } } break; case BINARY: if(data[i].data.bin.nbytes) { int j; for(j=0;j<data[i].data.bin.nbytes;j++) { switch(data[i].data.bin.bytes[j].type) { case BYTE: // do nothing break; // TODO LBL, LBM (labelpointer parsing) default: fprintf(stderr, "bast: Linker: Bad byte-type %u\n\t%s+0x%04X\n", data[i].data.bin.bytes[j].type, data[i].name, j); return(EXIT_FAILURE); break; } } } break; default: fprintf(stderr, "bast: Linker: Internal error: Bad segment-type %u\n", data[i].type); return(EXIT_FAILURE); break; } } fprintf(stderr, "bast: Linker passed all segments\n"); /* END: LINKER & LABELS */ /* CREATE OUTPUT */ switch(outtype) { case TAPE: fprintf(stderr, "bast: Creating TAPE output\n"); if(nsegs) { FILE *fout=fopen(outfile, "wb"); if(!fout) { fprintf(stderr, "bast: Could not open output file %s for writing!\n", outfile); return(EXIT_FAILURE); } int i; for(i=0;i<nsegs;i++) { // write header fputc(0x13, fout); fputc(0x00, fout); unsigned char cksum=0; fputc(0x00, fout); // HEADER int j; char name[10]; switch(data[i].type) { case BASIC: fputc(0, fout); // PROGRAM memset(name, ' ', 10); memcpy(name, data[i].name, min(10, strlen(data[i].name))); for(j=0;j<10;j++) { fputc(name[j], fout); cksum^=name[j]; } buildbas(&data[i].data.bas, true); if(data[i].data.bas.blen==-1) { fprintf(stderr, "bast: Failed to link BASIC segment %s\n", data[i].name); return(EXIT_FAILURE); } fputc(data[i].data.bas.blen, fout); cksum^=data[i].data.bas.blen&0xFF; fputc(data[i].data.bas.blen>>8, fout); cksum^=data[i].data.bas.blen>>8; if(data[i].data.bas.line) // Parameter 1 = autostart line { fputc(data[i].data.bas.line, fout); cksum^=data[i].data.bas.line&0xFF; fputc(data[i].data.bas.line>>8, fout); cksum^=data[i].data.bas.line>>8; } else // Parameter 1 = 0xFFFF { fputc(0xFF, fout); fputc(0xFF, fout); } // Parameter 2 = data[i].data.bas.blen fputc(data[i].data.bas.blen, fout); cksum^=data[i].data.bas.blen&0xFF; fputc(data[i].data.bas.blen>>8, fout); cksum^=data[i].data.bas.blen>>8; fputc(cksum, fout); // write data block fputc((data[i].data.bas.blen+2), fout); fputc((data[i].data.bas.blen+2)>>8, fout); fputc(0xFF, fout); // DATA cksum=0xFF; for(j=0;j<data[i].data.bas.blen;j++) { fputc(data[i].data.bas.block[j], fout); cksum^=data[i].data.bas.block[j]; } fputc(cksum, fout); free(data[i].data.bas.block); break; case BINARY: fputc(3, fout); // CODE cksum^=3; memset(name, ' ', 10); memcpy(name, data[i].name, min(10, strlen(data[i].name))); for(j=0;j<10;j++) { fputc(name[j], fout); cksum^=name[j]; } fputc(data[i].data.bin.nbytes, fout); cksum^=data[i].data.bin.nbytes&0xFF; fputc(data[i].data.bin.nbytes>>8, fout); cksum^=data[i].data.bin.nbytes>>8; // Parameter 1 = address fputc(data[i].data.bin.org, fout); cksum^=data[i].data.bin.org&0xFF; fputc(data[i].data.bin.org>>8, fout); cksum^=data[i].data.bin.org>>8; // Parameter 2 = 0x8000 fputc(0x00, fout); fputc(0x80, fout); cksum^=0x80; fputc(cksum, fout); // write data block fputc((data[i].data.bin.nbytes+2), fout); fputc((data[i].data.bin.nbytes+2)>>8, fout); fputc(0xFF, fout); // DATA cksum=0xFF; for(j=0;j<data[i].data.bin.nbytes;j++) { fputc(data[i].data.bin.bytes[j].byte, fout); cksum^=data[i].data.bin.bytes[j].byte; } fputc(cksum, fout); free(data[i].data.bin.bytes); break; default: fprintf(stderr, "bast: Internal error: Don't know how to make TAPE output of segment type %u\n", data[i].type); return(EXIT_FAILURE); break; } fprintf(stderr, "bast: Wrote segment %s\n", data[i].name); } fclose(fout); }