[comp.os.minix] V

wtoomey@gara.une.oz (Warren Toomey) (06/06/89)

Here's a piece of source code that I find indispensible. It's called V,
and it works as a front-end to vi. It allows you to quickly edit a
specific function in a list of C programs. Great for altering functions
when you've forgotten which file thay're in!

The source is only one file, compile it with	cc -o v v.c, and also
do a	chmem =20000 v. Also included is a man page in nroff format.

This source HAS been tested :-)

BTW, about Nroff, does anybody know of/have a public-domain Nroff that
works under Minix. Even just man macros for Minix Roff would be great!

						Warren Toomey
						(wtoomey@gara.une.oz)

------------------------------ mangle here ----------------------------

# This is a shell archive.  Remove anything before this line, then
# unpack it by saving it in a file and typing "sh file".  (Files
# unpacked will be owned by you and have default permissions.)
#
# This archive contains:
# v.c v.1

echo x - v.c
cat > "v.c" << '//E*O*F v.c//'
#define MINIX

#include <stdio.h>
#ifndef MINIX
# include <sys/wait.h>
#endif


/*			V - Edit/show C functions

	This program was written by Anthony Wesley on Sat Oct 15, 1988.
	It may be copied, but not sold without the express permission
        of the owner.
*/
	
#define LENGTH 100
#define APPEND -1
/*
	Currently the editor used is vi, with the system command line
	looking like
		vi +23 file.c
	or alternatively
		EDITOR OFFSET file
	where file is a string in this source. To port this to another
	editor, you will probably need to alter the EDITOR and OFFSET
	defines
*/
		
#define EDITOR "vi"
#define OFFSET "+%d"

help_v()
	{
	printf("Usage: v [-m -p[h] -f ] function(s)/program(s)\n");
	exit(0);
	}

char *fname(line,pos)
  char *line;
  int pos;
	{
	int fp,k,i,bcount=0,st,fn,nlen;
	char name[LENGTH],buf[LENGTH];

#ifdef DEBUG
printf("Found one in :%s:  ->",line);
#endif
	for (k=pos-1; k>=0 && line[k]!='('; --k);

	for (i=k-1,bcount=0; i>=0; --i) 
		{
		if (line[i-1]=='(') ++bcount;
		if (line[i-1]==')') --bcount;
		if (!bcount && i>0 && line[i-1]==' ' || line[i-1]=='\t' ) 
			{ --i; break;}
		}

	nlen=k-i-1;
	strncpy(buf,&line[i+1],nlen); buf[nlen]='\0';
#ifdef DEBUG
	printf("%s\n",name);
#endif
	/* now check if it was a fn pointer and remove () */
	for (i=fp=0; i<nlen; ++i) if (buf[i]=='(' ) fp=1;
	if (fp)
		{
		for (st=0; st<nlen && buf[st]!='('; ++st);
		for (fn=st+1; fn<nlen && buf[fn]!='(' && buf[fn]!=')' ; ++fn);
		strncpy(name,&buf[st+1],fn-st-2);
		}
	else strcpy(name,buf);
	return(name);
	}

make_functions(argc,argv)
   int argc;
   char *argv[];
	{
	FILE *z,*f;
	int i,l;
	int cbracket=0;
	int squote=0,quotes=0,comment=0,cr=0,h=0,h1=0;
	int bslash=0,fslash=0,asterisk=0,bracket=0,lincount=0,alert=0;
	char buf[1000],line[1000],c=0;

	if (argc==APPEND) { f=fopen(".functions","a"); argc=1; }
	else f=fopen(".functions","w");
	if (!f) { printf("Cannot open .functions for writing!\n"); return(0);}

	for (i=0; i<argc; ++i)
		{
		z = fopen(argv[i],"r");
		if (z==NULL) { printf("%s not found\n",argv[i]); continue; }
		fprintf(f,">%s\n",argv[i]);

		lincount=1;
		cbracket=squote=quotes=comment=cr=h=h1=bslash=fslash=asterisk=0;
		bracket=alert=0;
		while(!feof(z))
		  {
		  do 
		     {
		     c = getc(z); 
		     line[h++]=c; 
		     if (h==1000)
			{
			printf("Line %d too long\n",lincount);
			return(0);
			}
		     } 
		  while (c==' ' || c=='\t');

#ifdef DEBUG
putchar(c);
#endif
		  switch(c)
			{
			case '#': if (!cr) break;
				  if (comment) break;
				  do c=getc(z); while(c!='\n');
				  h=0; ++lincount;
				  break;

			case '\\': if (comment) break;
				   bslash= 1-bslash; break;

			case '{': if (squote || bslash || comment || quotes) break;
				   if (alert)
				   fprintf(f,"	%d %s\n",l,fname(buf,h1));
				   alert=0;
				  ++cbracket; break;

			case '}': if (squote || bslash || comment || quotes) break;
				  --cbracket; break;

			case '/': if (squote || bslash || quotes) break;
				  if (asterisk && comment) 
					{
#ifdef DEBUG
					printf("endcomment\n");
#endif
					comment=0;
					}
				  else 
					{
					fslash=1;
				   	if (alert)
				   	fprintf(f,"	%d %s\n",l,fname(buf,h1));
				   	alert=0;
					}
				  break;

			case '*': if (squote || bslash || quotes) break;
				  alert=0;
				  if (fslash) 
					{
#ifdef DEBUG
					printf("start comment\n");
#endif
					comment=1; fslash=0;
					}
				  asterisk=1;
				  break;

			case '\'': if (bslash || comment || quotes) break;
				   squote = 1-squote;
#ifdef DEBUG
				  if (squote) printf("STARTSINGLE\n");
				  else printf("ENDSINGLE\n");
#endif
				   break;
				   
			case '"': if (squote || bslash || comment) break;
				  quotes = 1-quotes;
#ifdef DEBUG
				  if (quotes) printf("STARTQUOTES\n");
				  else printf("ENDQUOTES\n");
#endif
				  break;

			case '\n': if (squote || quotes || bslash)
				   break;
				   ++lincount; cr=1; 
				   h=0; 
#ifdef DEBUG
				   printf("newline (%d)\n",lincount);
#endif
				   break;

			case '(': if (squote || bslash || comment || quotes) break;
				  ++bracket; alert=0;break;

			case ')': if (squote || bslash || quotes || comment) break;
				  --bracket;
				  if (!bracket && !cbracket) 
					{ 
					l=lincount; 
					strncpy(buf,line,h); buf[h]='\0';
					h1=h;
					alert=1;
#ifdef DEBUG
					printf("on alert\n");
#endif
					}
				  else alert=0;
				  break;

			default: if (alert)
				   if (in(c)) fprintf(f,"	%d %s\n",
						              l,fname(buf,h1));
				 asterisk=alert=cr=fslash=bslash=0;
				 break;
			}
		   if (bslash) bslash = (bslash+1) %3;
		   }
		fclose(z);
		}
	fclose(f);
	return(0);
	}
		
in(c)
  char c;
	{
	if (c!='*' && c!='=' && c!=';' && c!='(' && c!=',' && c!=')') return(1);
	return(0);
	}

edit_function(fname)
  char *fname;
	{
	FILE *z;
	char func[1000],mod[100][LENGTH],module[100],buf[1000];
	char file[100][LENGTH];
	int i,count=0,opt,line;

	z = fopen(".functions","r");
	if (z==NULL) { printf("No .functions file\n"); return(0); }

	for (i=0; i<LENGTH; ++i) mod[i][0]=0;
	while(!feof(z))
		{
		fgets(buf,1000,z); if (feof(z)) break;
		buf[strlen(buf)-1]='\0';
		if (buf[0]=='>') 
			{ 
			strcpy(module,&buf[1]); 
			strcpy(mod[count],module);
			continue; 
			}
		sscanf(buf,"\t%d %s",&line,func);
		if (instr(fname,func)) 
			copy(file[count++],buf);

		if (count>99) break;
		}
	fclose(z);
	if (!count) {printf("No functions called \"%s\" found\n",fname);
			return(0);
		    }
	if (count==1) 
		{ vi(mod[0],file[0]); return(0); }
	else
	printf("\nFunctions to Choose from\n");
	printf("--------------------------\n\n");
	for (i=0; i<count; ++i)
		{
		printf("%d) %s",i,&file[i][1]);
		if (mod[i][0]) printf("	(%s)",mod[i]); 
		putchar('\n');
		}
	printf("\n");
	printf("%d) Exit\n",count);
	do { printf("\nSelect (0 - %d): ",count); scanf("%d",&opt); }
	while(opt<0 || opt>count);
	if (opt==count) return(0);

	for (i=opt; i && !mod[i][0]; --i);
	vi(mod[i],file[opt]);
	return(0);
	}

vi(file,buf)
  char *file,*buf;
	{
	FILE *z;
	int line;
	char func[LENGTH],cmdln[LENGTH];
	char lbuf[100],fline[1000][50];
	int nlines=0,skip,i;
#ifdef MINIX
	int wstat;
#else
	union wait wstat;
#endif

	sscanf(buf,"\t%d %s",&line,func);
	sprintf(cmdln,OFFSET,line);
	if (!fork()) execlp(EDITOR,EDITOR,cmdln,file,0); 

	/* This is the child process from here on, update .functions */
	z = fopen(".functions","r");
	nlines=0;
	while(!feof(z)) 
		{
		fgets(lbuf,50,z); lbuf[strlen(lbuf)-1]='\0';
		strcpy(fline[nlines++],lbuf);
		}
	--nlines;
	
	freopen(".functions","w",z);
	for (i=skip=0; i<nlines; ++i)
		{
		if (fline[i][0]=='>')
		  { if (!strcmp(file,&fline[i][1])) skip=1; else skip=0; }

		if (!skip) fprintf(z,"%s\n",fline[i]);
		}
	fclose(z);
#ifdef MINIX
	wait(wstat);
#else
	wait(&wstat);  /* wait for editing session to finish */
#endif
	if (fork()) return(0); /* give them their cursor back */

	/* run this bit in the background to update the edited file */
	make_functions(APPEND,&file);
	return(0);
	}


instr(s1,s2)
  char *s1,*s2;
	{
	/* return true if s1 is a substring of s2 */
	int i;
	int ls1 = strlen(s1);
	int l=strlen(s2) - ls1;

	for (i=0; i<=l; ++i) 
	   if (!strncmp(s1,&s2[i],ls1)) return(1);
	return(0);
	}

copy(s1,s2)
  char *s1,*s2;
	{
	int i,l=strlen(s2);

	for (i=0; i<=l; ++i) s1[i]=s2[i];
	}

output_header(name)
   char *name;
	{
	int i,l = 36-strlen(name)/2;

	printf("/******************************************************************************\n");
	printf("\n");
	for (i=0; i<l; ++i) putchar(' '); 
	printf("MODULE: %s\n",name);
	printf("\n");
	printf("******************************************************************************/\n");
	return(0);
	}

show(file,start,finish,header)
   char *file;
   int start,finish,header;
	{
	FILE *z;
	char buf[1000];
	int i;
	
	z=fopen(file,"r");
	if (z==NULL) { printf("file %s not found\n",file); return(0); }

	if (header) output_header(file);
	for (i=0; i<start; ++i) fgets(buf,1000,z);
	
	printf("\n");
	while(1)
		{
		printf("%s",buf);
		fgets(buf,1000,z); if (feof(z)) break;
		if (finish && ++i == finish) break;
		}
	fclose(z);
	return(0);
	}


print_function(fname,header)
  char *fname;
  int header;
	{
	FILE *z;
	char buf[100],func[100],file[100];
	int start=0,finish=0,line=0,i=0,min=0,max=0;

	z = fopen(".functions","r");
	if (!z) { printf(".functions not found\n"); return(0); }

	while(!feof(z))
		{
		fgets(buf,100,z); 
		if (feof(z)) 
			{
			if (start) {finish=0; show(file,start,finish,header); }
			break; 
			}
		buf[strlen(buf)-1]=0;

		if (buf[0]=='>') 
			{
			if (start) {finish=0; show(file,start,finish,header); }
			strcpy(file,&buf[1]);
			start=0;
			}
		else
			{
			sscanf(buf,"\t%d %s",&line,func);
			if (start) 
			   { 
			   finish=line; 
			   show(file,start,finish,header);
			   start=0;
			   }
			if (instr(fname,func)) start=line;
			}
		}
	fclose(z);
	return(0);
	}

show_all()
	{
	FILE *z = fopen(".functions","r");
	char line[30];
	char buf[100],name[100];
	int i,j,n,count;

	if (!z) { printf("ERROR: \".functions\" not defined\n"); return(0); }
	count=0;
	while(1)
		{
		fgets(buf,100,z); if (feof(z)) break;
		if (buf[0]=='>')
		   {
		   putchar('\n');
		   putchar('\n');
		   printf("		FILE: %s",&buf[1]);
		   count=0;
		   }
		else
		   {
		   sscanf(buf,"\t%d %s",&j,line);
		   n = strlen(line); if (n>15) n=15;
		   for (i=n; i<20; ++i) line[i]=' '; line[20]=0;
		   printf("%s",line);
		   ++count; if (count==4) { count=0; putchar('\n'); }
		   }
		}
	fclose(z);
	putchar('\n');
	return(0);
	}

main(argc,argv)
   int argc;
   char *argv[];
	{
	int i,header,start;
	char arglist[100][100];

	if (argc<2) help_v();

	start=1;

	if (argv[1][0]== '-')
	switch(argv[1][1])
		{
		case 'm': make_functions(argc-2,&argv[2]);
			  exit(0);

		case 'p': if (strlen(argv[1])>2 && argv[1][2]=='h') header=1;
			  else header=0;
			  print_function(argv[2],header);
			  exit(0);

		case 'f': show_all(); exit(0);

		default: printf(" option '%s' not supported\n",argv[1]);
			 help_v();
			 exit(0);
		}

	edit_function(argv[1]);
	exit(0);
	}

//E*O*F v.c//

echo x - v.1
cat > "v.1" << '//E*O*F v.1//'
.T1 v 1
.SH NAME
v \- edit/list C functions
.SH SYNTAX
v [ -m -p[h] -f ] function(s)/program(s)
.SH OPTIONS
.TP 8
.B \-m   
Create a file called
.I .functions
which holds the name & position of all the C functions in the named programs.
.TP
.B -p[h]
Print out the given C function, with an optional header.
.TP
.B -f
List the names of the functions known by
.I v.
.SH DESCRIPTION
.I V
is a front end to vi (or possibly another editor), which allows you
to find and edit C functions quickly. It can also print a specific
function for you.
.PP
To use
.I v,
you must first make a file describing your functions. For example, doing
.PP
.B v -m *.c
.PP
will create a
.I .functions
file with a list of all the C functions in your files. To see the list
of functions, do
.PP
.B v -f
.PP
To edit a specific functions, for example
.B foobar(),
do
.PP
.B v foobar
.PP
and you will be taken to the top line of
.B foobar
in whatever file
.B foobar
happens to be in.
.I V
will quite happily look for functions that start with the given command line
argument, so if you do
.PP
.B v foo
.PP
then
.I v
will either take you to the only function that starts with
.B foo,
or give a list of functions that start with
.B foo
; you may then choose which one you want to edit.
.PP
Finally,
.I v
allows you to print a selected function on the standard output, by using
the
.B -p
option. If you use
.B -ph
instead, a header giving the name of the function, and the file it came from
will be output before the function listing.
.SH FILES
 ./.functions		List of functions known by 
.B v.
.SH SEE ALSO
 vi(1)
//E*O*F v.1//

exit 0