/****************************************************************
 *								*
 * lf.c - list functions in a c source file		V1.1	*
 *								*
 * (c) 1989 Jeff Bevis						*
 *								*
 ****************************************************************
 *								*
 * Command line options						*
 *								*
 * -s	Suppress line number printing.				*
 * -c	Format output for C function declarations		*
 * -n	Force normal formatting					*
 * 								*
 ****************************************************************/
 

#include <stdio.h>

FILE *s;
char c,buf[400],cget();
int mode,col,linecount;
char	c_flag,s_flag,nofile;

main(argc,argv)
int argc;
char **argv;
{
 int t;

 if(argc>1)
  {
   for(t=1;t<argc;t++)
    {
     if(*argv[t]=='-')
      {
       int s;

       for(s=1;s<strlen(argv[t]);s++)
	{
	 switch(*(argv[t]+s))
	  {
	   case 's':	s_flag++; break;
	   case 'c':	c_flag++; break;
	   case 'n':	s_flag=0;
			c_flag=0; break;
	   default:	if(!c_flag) printf("Unrecognized option: %c\n",*(argv[t]+s));
	  }
	}
       continue;
      }
     s=fopen(argv[t],"r");
     if(s)
      {
       if(c_flag) printf("/*\n * Functions from %s\n */\n",argv[t]);
       else printf("FILE: %s\n",argv[t]);
       find();
       fclose(s);
      }
     else
      {
       if(c_flag) printf("/* FILE: %s NOT PRESENT! */\n",argv[t]);
       else printf("Can't open file %s.\n",argv[t]);
      }
    }
  }
 else
  {
   if(c_flag) printf("/* No files specified for lf */\n");
   else printf("You must specify a C source file.\n");
   exit(10);
  };
}

find()
{
 int comlev=0,depth=0,cnt=0;

 linecount=0;
 col=0;
 c=0;

 while(c!=EOF)
  {
   c=cget(s);
   if(comlev==1 && c!='*') comlev=0;

   switch(c)
    {
     case '\n':	buf[cnt]='\0';
		think(cnt);
		cnt=0;
		break;
     case '#':	if(col==1) readtoeol();   /* skip over preprocessor lines */
		break;
     case '\\': c=cget(s);
		break;
     case '/':	comlev=1;
		break;
     case '*':	if(comlev==1) readto_eocomment();
		break;
     case '\"': readto_eoquote();
		break;
     case '\'':	readto_eochar();
		break;
     case '{':	depth++;
		break;
     case '}':	depth--;
		break;
    }
   if(depth==0 && comlev==0 && c!=EOF && c!='\n') buf[cnt++]=c;
  }
}

readtoeol()
{
 c=cget(s);
 while(c!=EOF && c!='\n') c=cget(s);
}

readto_eocomment()
{
 c=cget(s);

 while(c!=EOF)
  {
   if(c=='*')
    {
     c=cget(s);
     if(c=='/') return;
    }
   else c=cget(s);
  }
}

readto_eoquote()
{
 c=cget(s);
 while(c!=EOF && c!='\"') c=cget(s);
}

readto_eochar()
{
 c=cget(s);
 while(c!=EOF && c!='\'') c=cget(s);
}

think(cnt)
{
 int z;
 z=cnt;

 if(z>2)
  {
   z--;
   while((buf[z]==' ' || buf[z]=='\t') && z>1) z--;
   buf[z+1]='\0';
   if(buf[z]==')')
    {
     if(c_flag)
      {
       int tc,r,tspot=0,vd=1,validchar=0,checknow=0;

       for(r=z;r>0;r--)		/* find first space before function parentheses */
        {
         if(buf[r]==' ' || buf[r]=='\t')	/* if a whitespace */
	  {
	   if(validchar)	/* and we're ready to accept one */
	    {
	     tspot=r;		/* remember the tab-spot */
	     vd=0;
	     break;		/* leave loop */
	    }
	  }
	 else if(checknow) validchar=1;	  /* if first non-space before parentheses, must be function name.  OK to look for leading space now */
	 else if(buf[r]=='(') checknow=1; /* see if we left the function parentheses */
	}
       for(r=tspot;r<=z;r++)	/* find leftmost parentheses of function decl after tspot */
	{
	 if(buf[r]=='(')
	  {
	   buf[r+1]=')';
	   buf[r+2]='\0';
	   break;
	  }
	}
       if(vd) printf("void\t\t\t%s;\n",buf);
       else
	{
	 for(r=0;r<tspot;r++) putchar((int)buf[r]);
	 tc=3-(tspot>>3);		/* tab size of 8, 2^3) */
	 for(r=0;r<tc;r++) putchar('\t');
	 printf("%s;\n",buf+tspot+1);
	}
      }
     else if(s_flag) printf("%s\n",buf);	/* no line num */
     else printf("\t%4d: %s\n",linecount,buf);	/* default mode */
     return;
    }
  }
}

char cget(f)
FILE *f;
{
 char c;
 c=getc(f);
 if(c=='\n') 
  {
   linecount++;
   col=0;
  }
 else col++;
 if(c=='\\')		/* if escape slash is read, */
  {
   c=getc(f);		/* get char after escape */
   return(cget(f));	/* return next non-escape char after that */
  }
 return(c);
}
