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