ステートマシンを作ろうだいにっかい

のみのこしワインと共に!!!

さてさて前回は、http://d.hatena.ne.jp/ore_de_work/20090320 ステートマシンって便利だねー
っとところで終わりましたが、
実際に、改行コードのステートマシンを着くってみましょー

以下は行をCRLFでスプリットするサンプルです。

#include <stdio.h>
#include <string.h>

void LogDisp( const char *r )
{
	printf("%s\n", r);
}

int LogMachine( const char* msg )
{
	char *p, *r, *d;

	d = strdup(msg);
	p = r = d;
	for(;;)
	{
		if( *p == '\0' )
			goto DISP;

		if( *p == '\r' || *p == '\n' ) {
			*p = '\0';
			p++;
			if( *p == '\r' && *(p + 1) == '\n' ) p++;
			goto DISP;
		}

		p++;
		continue;

DISP:
		LogDisp( r );

		if( *p == '\0' ) break;
		p++;
		if( *p == '\0' ) break;
		r = p;
		continue;
	}

	free(d);
	return 0;
}

int main(void)
{
	LogMachine("123\n456\r\n789\naaaa");
	
	return 0;
}

上記をステートで書き直すと以下のようになります。

#include <stdio.h>
#include <string.h>

//#define DEGUG(x) x
#define DEGUG(x)

#define     START             0
#define     RUN               1
#define     DISP_NEXT_END     2
#define     SPLIT_CR          3
#define     SPLIT_LF          4
#define     DISP_NEXT_RUN     5
#define     END               6

char *disp_state[ ] = {
    "START         " ,
    "RUN           " ,
    "DISP_NEXT_END " ,
    "SPLIT_CR      " ,
    "SPLIT_LF      " ,
    "DISP_NEXT_RUN " ,
    "END           " ,
    "" ,
    "" ,
    "" ,
};
    


void LogDisp(char *r )
{
	printf("%s\n", r);
}


int LogMachine(char* msg)
{
	char *p, *r, *d;
	int state = START;

	for(;;)
	{
		DEGUG(printf("                         "
		             "[%s(%u/%u)]\n", disp_state[state], r - d , p - d ));
	
		switch( state )
		{
		case START:
			d = strdup(msg);
			p = r = d;
			state = RUN;
			break;
		case RUN:
			if( *p == '\0' ) {
				state = DISP_NEXT_END;
			}
			else if( *p == '\r' ) {
				state = SPLIT_CR;
			}
			else if( *p == '\n' ) {
				state = SPLIT_LF;
			}
			else {
				p++;
			}
			break;
			
		case SPLIT_CR:
			*p = '\0';
			p++;
			state = DISP_NEXT_RUN;
			
			if( *p == '\n' ) state = SPLIT_LF; /* CRLF */
			break;
		
		case SPLIT_LF:
			*p = '\0';
			p++;
			state = DISP_NEXT_RUN;
			break;
		
		case DISP_NEXT_END:
			LogDisp( r );
			LogDisp( r );
			r = p;
			p++;
			state = END;
			break;
		
		case DISP_NEXT_RUN:
			LogDisp( r );
			r = p;
			p++;
			state = RUN;
			break;
			
		case END:
			free(d);
			return 0;
			break;
		}
	}

	return 0;
}


int main(void)
{
	LogMachine("123\n456\r\n789\naaaa");
	
	return 0;
}

このコード、どちらも
# gcc hoge.c && ./a.out
123
56
89
aaa

となります。
さて、此処から、ESC や ^h を判定したりするルーチンをついかするばーい
どっちのほうが らくかーらくかーな
うわ
どっちもおんなじだorz

べ、、べつにあんたの(ry