/*
 *	Step Count Program
 *
 *		By  A.Kobayashi  '91.5.22
 *		By  A.Kobayashi  '98.1.14
 *		By  A.Kobayashi 2003.4.17
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#if defined(AIX) || defined(WIN)
#define SJIS
#else
#define EUC
#endif
#define NSEP	13
#define NMTAB	32
#define MAXDEFINE	1000
#define MAXIFNEST	100

typedef struct {
	int sp;
	char *w;
} SSP_S;

typedef struct {
	char name[64];
	char val[64];
} DEFINE_S;

int define_cnt;
DEFINE_S define[MAXDEFINE];
char sep[NSEP]={' ','\t','\n',';',',','(',')','/','{','}','"','\'','='};
char buf[512],name[128],w[128],ww[128],w1[16];
int tcnt,tmcnt,mcnt,ccnt,dcnt,bcnt,scnt,mnum,nest,p_nest;
int ifnest_cnt,ifnest[MAXIFNEST];
char mode;
int iDEFINE=1;

int issjis(c)
unsigned char c;
{
	if ((c>=0x80 && c<=0x9f) || (c>=0xe0 && c<=0xfc))
		return (1);
	else
		return (0);
}

int iskanji1(c1)
unsigned char c1;
{
	if (mode == 'e') {
		/**************************/
		/*    EUC                 */
		/**************************/
		if ( (c1==0x8e) || ( (c1>=0xa1) && (c1<=0xfe) ) ) return (1);
		return (0);
	}
	else {
		/**************************/
		/*    SJIS                */
		/**************************/
		return (issjis(c1));
	}
}

int get_line(s)
char *s;
{
	int c,l;

	l=-1;
	while ((c=getchar())!=EOF) {
		l++;
		if (c=='\n') break;
		else if (c!='\r') *s++ = (char)c;
	}
	*s='\0';
	return (l);
}

mygetw(s,ssp)
char *s;
SSP_S *ssp;
{
	char c,*w;
	int i,l;

	s += ssp->sp;
	w=ssp->w;
	while ((c = *s) == ' ' || c=='\t') {
		s++;
		ssp->sp++;
	}
	if (!iskanji1(c)) {
		for (i=0;i<NSEP;i++)
			if (c==sep[i]) {
				*w++ = c;
				*w = '\0';
				ssp->sp++;
				return (-1);
			}
	}
	l=0;
	*w = '\0';
	while (c = *s++) {
		if (iskanji1(c)) {
			l+=2;
			*w++ = c;
			*w++ = *s++;
			ssp->sp++;
		}
		else {
			for (i=0;i<NSEP;i++)
				if (c==sep[i])
					break;
			if (i<NSEP)
				break;
			else {
				l++;
				*w++ = c;
			}
		}
		ssp->sp++;
	}
	*w = '\0';
	return (l);
}

q_skip(buf,ssp,quat)
char *buf,quat;
SSP_S *ssp;
{
	char c;
#ifdef DEBUG
printf("*** q_skip start.\n");
#endif

	for (;;) {
		if (c=buf[ssp->sp++]) {
			if (c=='\\' || iskanji1(c)==1)
				ssp->sp++;
			else if (c==quat)
				break;
		}
		else {
			if (get_line(buf)<0)
				break;
			ssp->sp=0;
			tcnt++;
			mcnt++;
		}
	}
}

c_skip(buf,ssp,cflg)
char *buf;
SSP_S *ssp;
int *cflg;
{
	char c;
#ifdef DEBUG
printf("*** c_skip start.\n");
#endif

	ssp->sp++;
	for (;;) {
		if (c=buf[ssp->sp++]) {
			if (iskanji1(c))
				ssp->sp++;
			else if (c=='*') {
				if (buf[ssp->sp]=='/') {
					ssp->sp++;
					break;
				}
			}
		}
		else {
			if (*cflg)
				ccnt++;
			if (get_line(buf)<0)
				break;
			ssp->sp=0;
			tcnt++;
			mcnt++;
			*cflg=2;
		}
	}
}

set_define(argc,argv)
int  argc;
char *argv[];
{
	int i;
	char *p;

	argc--;
	argv++;
	while (argc) {
		p = *argv;
		if (strlen(p) >= 2) {
			if (!memcmp(p,"-D",2)) {
				p+=2;
				if (!*p) {
					argc--;
					if (argc<=0) break;
					argv++;
					p=*argv;
				}
				for (i=0;i<define_cnt;i++) {
					if (!strcmp(define[i].name,p)) break;
				}
				if (i < MAXDEFINE) {
#ifdef DEBUG_1
printf("-D=%s i=%d\n",p,i);
#endif
					strcpy(define[i].name,p);
					if (i>=define_cnt) define_cnt++;
				}
			}
			else if (!memcmp(p,"-e",2)) mode = 'e';
			else if (!memcmp(p,"-s",2)) mode = 's';
			else if (!memcmp(p,"-i",2)) iDEFINE = 0;
			
		}
		argc--;
		argv++;
	}
}

main(argc,argv)
int  argc;
char *argv[];
{
	int l,cflg,fflg,dflg,i,bflg,fvflg,ifflg;
	char *p,c;
	SSP_S ssp;
	int len,yenflg;
	int op,stack[2],istack,v;

#ifdef SJIS
	mode = 's';
#else
	mode = 'e';
#endif
	define_cnt=0;
	set_define(argc,argv);
	ifnest_cnt=0;
	ifnest[ifnest_cnt]=1;
	ifflg=1;
	tcnt=tmcnt=mcnt=mnum=bcnt=dcnt=nest=fflg=fvflg=ccnt=scnt=yenflg=p_nest=0;
	ssp.w=w;
	name[0]='\0';
	while ((len=get_line(buf))>=0) {
		if (len>0 && yenflg) {
/*
printf("buf=[%s]\n",buf);
*/
			if (buf[len-1] == '\\') {
				tcnt++;
				if (!ifflg) scnt++;
			}
			else yenflg=0;
			continue;
		}
		ssp.sp=0;
		if (iDEFINE && buf[0]=='#') {
			dcnt++;
			dflg=1;
			ssp.sp=1;
			l=mygetw(buf,&ssp);
			strcpy(w1,w);
			if (!strcmp(w1,"define")) {
/*
printf("buf=[%s]\n",buf);
*/
				if (ifflg) {
					l=mygetw(buf,&ssp);
					for (i=0;i<define_cnt;i++) {
						if (!strcmp(define[i].name,w)) break;
					}
					if (i < MAXDEFINE) {
						strcpy(define[i].name,w);
					/*
						l=mygetw(buf,&ssp);
						strcpy(define[i].val,w);
					*/
#ifdef DEBUG_1
printf("define=%s val=%s i=%d\n",define[i].name,define[i].val,i);
#endif
						if (i>=define_cnt) define_cnt++;
					}
				}
				if (buf[len-1] == '\\') {
/*
printf("buf=[%s]\n",buf);
*/
					yenflg = 1;
				}
			}
			else if (!strcmp(w1,"ifdef")) {
				l=mygetw(buf,&ssp);
				for (i=0;i<define_cnt;i++) {
					if (!strcmp(define[i].name,w)) break;
				}
				ifnest_cnt++;
 				if (ifnest_cnt>=MAXIFNEST) {
					printf("if nest over!!\n");
					break;
				}
				if (i<define_cnt) ifnest[ifnest_cnt]=1;
				else ifnest[ifnest_cnt]=0;
#ifdef DEBUG_1
printf("ifdef=%s ifnest_cnt=%d ifnest=%d\n",w,ifnest_cnt,ifnest[ifnest_cnt]);
#endif
			}
			else if (!strcmp(w1,"ifndef")) {
				l=mygetw(buf,&ssp);
				for (i=0;i<define_cnt;i++) {
					if (!strcmp(define[i].name,w)) break;
				}
				ifnest_cnt++;
 				if (ifnest_cnt>=MAXIFNEST) {
					printf("if nest over!!\n");
					break;
				}
				if (i<define_cnt) ifnest[ifnest_cnt]=0;
				else ifnest[ifnest_cnt]=1;
#ifdef DEBUG_1
printf("ifndef=%s ifnest_cnt=%d ifnest=%d\n",w,ifnest_cnt,ifnest[ifnest_cnt]);
#endif
			}
			else if (!strcmp(w1,"if")) {
				l=mygetw(buf,&ssp);
				ifnest_cnt++;
 				if (ifnest_cnt>=MAXIFNEST) {
					printf("if nest over!!\n");
					break;
				}
				if ((c=*w)>='0' && c<='9')
					ifnest[ifnest_cnt]=atoi(w);
				else {
					istack = 0;
					while (l) {
						if (!strcmp(w,"defined")) {
							l=mygetw(buf,&ssp);	/* '(' */
							l=mygetw(buf,&ssp);
/*
printf("if: w=%s\n",w);
*/
							for (i=0;i<define_cnt;i++) {
								if (!strcmp(define[i].name,w)) break;
							}
							if (i<define_cnt) v=1;
							else v=0;
							l=mygetw(buf,&ssp);	/* ')' */
							stack[istack++]=v;
							if (istack == 2) {
								if (op) v = stack[0] && stack[1];
								else    v = stack[0] || stack[1];
								ifnest[ifnest_cnt]=v;
/*
printf("if: stack[0]=%d stack[1]=%d v=%d\n",stack[0],stack[1],v);
*/
								istack=0;
							}
						}
						else {
							printf("if syntax error!! defined only\n");
							break;
						}
						if (l=mygetw(buf,&ssp)) {
							if (!strcmp(w,"||")) op = 0;
							else if (!strcmp(w,"&&")) op = 1;
							else {
								printf("if syntax error!!\n");
								break;
							}
/*
printf("if: op=%s %d\n",w,op);
*/
							l=mygetw(buf,&ssp);
						}
					}
				}
#ifdef DEBUG_1
printf("if=%s ifnest_cnt=%d ifnest=%d\n",w,ifnest_cnt,ifnest[ifnest_cnt]);
#endif
			}
			else if (!strcmp(w1,"else")) {
				if (ifnest[ifnest_cnt])ifnest[ifnest_cnt]=0;
				else ifnest[ifnest_cnt]=1;
#ifdef DEBUG_1
printf("else ifnest_cnt=%d ifnest=%d\n",ifnest_cnt,ifnest[ifnest_cnt]);
#endif
			}
			else if (!strcmp(w1,"endif")) {
				ifnest_cnt--;
#ifdef DEBUG_1
printf("endif ifnest_cnt=%d ifnest=%d\n",ifnest_cnt,ifnest[ifnest_cnt]);
#endif
			}
			ifflg=1;
			for (i=1;i<=ifnest_cnt;i++) {
				if (!ifnest[i]) {
					ifflg=0;
					break;
				}
			}
			cflg=1;
			bflg=0;
			tcnt++;
			if (!ifflg) scnt++;
			continue;
		}
		else {
			dflg=0;
			mcnt++;
		}
		cflg=1;
		bflg=0;
#ifdef DEBUG
printf("tcnt=%3d buf=%s\n",tcnt,buf);
#endif
		tcnt++;
		if (!ifflg) {
			scnt++;
			continue;
		}
		while (l=mygetw(buf,&ssp)) {
#ifdef DEBUG_1
printf("SP=%3d L=%3d W=%s\n",ssp.sp,l,w);
printf("nest=%d fflg=%d fvflg=%d\n",nest,fflg,fvflg);
#endif
			if (*w != '\n')
				bflg++;
			if (l<0) {
				switch (*w) {
				case '{':
					if (nest++ == 0 && fflg==2) {
						printf("%3d %s",mnum+1,name);
						if ((v=NMTAB-strlen(name)) > 0)
							for (i=0;i<v;i++) printf(".");
					/*	mcnt=1;	*/
						fflg=3;
						fvflg=0;
					}
					break;
				case '}':
					if (--nest == 0 && fflg==3) {
						fflg=0;
						printf("%5d\n",mcnt);
						mnum++;
						tmcnt+=mcnt;
					}
					break;
				case '(':
					if (p_nest++ == 0 && nest==0 && dflg==0 &&
					    (fflg==0 || (fflg==2 && fvflg==0))) {
						fflg=1;
						fvflg=0;
						strcpy(name,ww);
						strcat(name,"(");
						mcnt=1;
					}
					break;
				case ')':
					if (--p_nest == 0 && fflg==1) fflg=2;
					break;
				case '\'':
				case '"':
					q_skip(buf,&ssp,*w);
					break;
				case ';':
				case '=':
					if (fflg==2 && fvflg==0) fflg=0;
					break;
				case '/':
					if ((c=buf[ssp.sp])=='*') {
						if (cflg)
							cflg=2;
						c_skip(buf,&ssp,&cflg);
					}
					else if (c=='/') {
						if (cflg)
							cflg=2;
						buf[ssp.sp]='\0';
					}
					break;
				default:
					break;
				}
			}
			else {
				cflg=0;
				strcpy(ww,w);
				if (fflg==2) fvflg=1;
			}
		}
		if (cflg==2)
			ccnt++;
		if (!bflg)
			bcnt++;
	}
	printf("\ntotal module step = %4d\n",tmcnt);
	printf("module number = %4d\n",mnum);
	printf("\ncomment step  = %4d\n",ccnt);
	printf("blank   step  = %4d\n",bcnt);
	printf("#xxxxxx step  = %4d\n",dcnt);
	printf("skip    step  = %4d\n",scnt);
	printf("total   step  = %4d\n",tcnt);
}
