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