Exemplo n.º 1
0
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);
}
Exemplo n.º 2
0
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;
}
Exemplo n.º 3
0
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);
}
Exemplo n.º 4
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);
}
Exemplo n.º 5
0
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);
}
Exemplo n.º 6
0
Arquivo: buffer.c Projeto: ec429/quIRC
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);
	}
Exemplo n.º 7
0
/*
 * 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;
}
Exemplo n.º 8
0
Arquivo: bast.c Projeto: ec429/bast
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);
			}