This is parsers.c in view mode; [Download] [Up]
/*
docgen Objective C Document Generator
Copyright (C) 1995 Bill Bereza.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Email:
berezaw@river.it.gvsu.edu
S-mail:
Bill Bereza
9526 Judson Rd.
Ravenna, MI 49451-9427
*/
/* docgen Objective C Document Generator
* Copyright (c) 1994 Bill Bereza
*
* $Log: parsers.c,v $
* Revision 1.39 96/01/07 01:30:27 berezaw
* additions for 0.3.2
*
* Revision 1.38 95/07/26 18:56:08 berezaw
* *** empty log message ***
*
* Revision 1.37 95/07/26 17:50:28 berezaw
* got before and after comments parsing to work
*
* added findrealchr() function
*
* Revision 1.36 95/07/26 16:17:32 berezaw
* 0.3.1
*
* Revision 1.35 95/07/21 21:40:17 berezaw
* *** empty log message ***
*
* Revision 1.34 95/07/16 19:19:55 berezaw
*
* bug fix found by pburka
*
*
* Revision 1.33.1 95/04/26 13:34:00 pburka
* added an input check to make sure there's something
* in the file.
*
*
* Revision 1.33 95/03/02 18:20:50 berezaw
* added gathermethod() to get each method as a block
* create COMMINTERN macro to do the check and printing
* of comments for a method
* created GETNEWLINE macro for getting a new line
* of text from the queue
*
* Revision 1.32 95/03/02 03:44:47 berezaw
* using GNU regex library
* rewrote recmp() as docgen_recmp()
* added GPL stuff to each file
* increase rev. to 0.1.9
*
* Revision 1.31 95/02/14 12:36:44 berezaw
*
* fixed new line getting in parsemethods
*
* Revision 1.30 95/02/13 19:05:34 berezaw
*
* will now skip to next line on end of comments
*
* Revision 1.29 95/02/02 18:32:14 berezaw
* 0.1.7, fixed problems with skipping lines
* in odd classes
*
* Revision 1.28 95/02/02 17:57:38 berezaw
* didn't skip spaces often enough
*
* Revision 1.27 95/02/02 15:21:59 berezaw
* 0.1.6
*
* Revision 1.26 95/02/01 18:49:59 berezaw
*
* 0.1.6
*
* Revision 1.25 95/02/01 16:41:36 berezaw
* better parsing for i-vars in parseivars
*
* Revision 1.24 95/01/31 18:28:40 berezaw
*
* added 0.1.5 stuff
*
* Revision 1.23 95/01/30 14:11:20 berezaw
* fixed fancy text
*
* Revision 1.22 95/01/30 13:39:47 berezaw
* *** empty log message ***
*
* Revision 1.21 95/01/30 13:32:23 berezaw
* added loop to check for nested fancy text
*
* Revision 1.20 95/01/29 02:52:44 berezaw
* (parsecomments) started support for word decorations
*
* Revision 1.19 95/01/29 01:52:52 berezaw
* reused code from parsemethods to create general
* comment printing function to handle italicizing
* variable names, and to eventually handle fancy
* text
*
* Revision 1.18 95/01/27 00:59:35 berezaw
* *** empty log message ***
*
* Revision 1.17 95/01/27 00:31:46 berezaw
* added '-x' option to hide methods beginning with '_'
*
* Revision 1.16 95/01/26 15:32:56 berezaw
* added BSD, SYSV and HPUX checks
*
* Revision 1.15 95/01/26 15:27:35 berezaw
* now checks for comments for method types
*
* Revision 1.14 95/01/26 05:35:22 berezaw
* major fixing in parseivars and parsemethodtypes
* added dcmp()
* changed parsemethods to handle multiple classes,
* to use a list that can be sorted,
* and to handle method declarations better
*
* Revision 1.13 94/11/28 12:08:35 berezaw
* *** empty log message ***
*
*
* $Id: parsers.c,v 1.39 96/01/07 01:30:27 berezaw Exp $
*/
#include "parsers.h"
int docgen_recmp(char *expr, char *line)
{
static struct re_pattern_buffer expbuf;
static bool set=no;
int matret;
if(!set) {
set=yes;
re_syntax_options=0;
re_syntax_options=DOCGEN_SYNTAX;
expbuf.buffer=(char *)malloc(DOCGEN_REBUF);
expbuf.allocated=DOCGEN_REBUF;
expbuf.translate=NULL;
}
if(re_compile_pattern(expr, strlen(expr), &expbuf)) {
fprintf(stderr, "docgen_recmp:error compiling expression\n");
return -1;
}
switch((matret=re_match(&expbuf, line, strlen(line), 0, 0)))
{
case -1:
return 1;
default:
return 0;
}
}
#define DYNLINESEP "||--||"
int parseivars(FILE *RTFf, FILE *Hf, char *FQh)
{
char *hline, *stringptr, *idescstr, *as;
DSTRING *dynstring;
#ifndef NODEBUG
if(V_USELESS)
fprintf(stderr,"parseivars(FILE, FILE, %s)\n", FQh);
#endif
#ifdef OBJC
[myForm putIHeader];
#else
fputihead(RTFf); /* Setup margins, font and header for I-Vars */
#endif
hline=fgetdline(Hf);
/* initialize it now, so that we know we can safely free it later */
dynstring=initdstr();
/* parse through each ivar line */
while(docgen_recmp(IVAREND, hline) && !feof(Hf)) {
if(!strchr(hline, ';')) {
free(hline);
hline=fgetdline(Hf);
continue;
}
idescstr=strstr(hline,"//");
if(!idescstr)
idescstr=strstr(hline,"/*");
if(idescstr)
idescstr++;
stringptr=strtok(hline, IVTOK); /* split line up into tokens
* seperated by IVTOK
*/
#ifndef NODEBUG
if(V_USELESS)
fprintf(stderr,"%s\n\n",stringptr);
#endif
/* parse through each ivar on a line */
while((stringptr!=NULL) && docgen_recmp(WHITEXP, stringptr)) {
char *varp=&stringptr[strlen(stringptr)-1];
char *stopper=stringptr;
SKIPSPACE(stringptr);
if(*stringptr == IDESCCHAR)
break;
while(isspace(*varp) && (varp!=stopper))
varp--;
if((*varp!='{') && (*varp!='}')) {
while(*varp) {
while(isspace(*varp) && (varp!=stopper))
varp--;
while(!isspace(*varp) && (varp!=stopper))
varp--;
while(isspace(*varp) && (varp!=stopper))
varp--;
if(((*varp==',') || (*varp==':')) && (varp!=stopper))
varp--;
else {
varp++; *varp='\0';
}
}
varp++;
}
else if(*varp!='}') {
*(varp+1)='\0';
varp=stringptr;
}
if(!strchr(stringptr,'{') && !strchr(stringptr,'}')) {
while(*stringptr) {
fputc(*stringptr++, RTFf);
}
fputc('\t', RTFf);
}
stringptr=varp; varp=&stringptr[strlen(stringptr)-1];
SKIPSPACE(stringptr);
if((*varp!='{') && (*varp!='}')) {
#ifdef OBJC
[myForm makeBold];
fprintf(RTFf, "%s", stringptr);
[myForm unBold];
[myForm putLine:";"];
#else
fputbold(RTFf, stringptr);
fputline(RTFf, ";");
#endif
}
else
#ifdef OBJC
[myForm putLine:" "];
#else
fputline(RTFf, " ");
#endif
if(*stringptr=='*')
stringptr++;
if((*varp!='{') && (*varp!='}')) {
// daddchar(dynstring, IFEOL);
// daddchar(dynstring, '\n');
// dstrarrcat(dynstring, IFSIZE);
dstrarrcat(dynstring, stringptr);
daddchar(dynstring, '\t');
if(idescstr != NULL) {
++idescstr;
SKIPSPACE(idescstr);
as=strstr(idescstr,"*/");
if(as)
*as='\0';
dstrarrcat(dynstring, idescstr);
}
else
dstrarrcat(dynstring, "No Description");
dstrarrcat(dynstring,DYNLINESEP);
// daddchar(dynstring, IFEOL);
// daddchar(dynstring, '\n');
while(*stringptr) {
SKIPSPACE(stringptr);
daddchar(GLOB_istring, '#');
while(!isspace(*stringptr) && (*stringptr != ',') && *stringptr) {
daddchar(GLOB_istring, *stringptr++);
}
daddchar(GLOB_istring, '#');
if(*stringptr)
stringptr++;
}
}
stringptr=strtok(NULL, IVTOK);
}
free(hline);
hline=fgetdline(Hf);
}
/* print out the ivar description lines */
#ifdef OBJC
[myForm putIVarDescription];
[myForm putLine:" "];
[myForm changeFontSize:28];
#else
fputivardesc(RTFf);
fputline(" ");
fchfontsize(RTFf,28);
#endif
stringptr=arrdstr(dynstring);
{
char *zptr=strtok(stringptr, DYNLINESEP);
while(zptr) {
#ifdef OBJC
[myForm putLine:" "];
[myForm putLine:zptr];
#else
fputline(RTFf," ");
fputline(RTFf, zptr);
#endif
zptr=strtok(NULL,DYNLINESEP);
}
}
// fprintf(RTFf,"%s",stringptr);
if(!strlen(stringptr))
#ifdef OBJC
[myForm putLine:"No additional instance variables declared."];
#else
fputline(RTFf, "No additional instance variables declared.");
#endif
freedstr(dynstring);
free(stringptr);
if(feof(Hf)) {
free(hline);
if(V_ERR)
fprintf(stderr,"Unexpected end of file in %s\n", FQh);
return -1;
}
free(hline);
#ifndef NODEBUG
if(V_USELESS)
fprintf(stderr, "parseivars: returning\n");
#endif
return 0;
}
void parsemethodtype(FILE *Hf, FILE *RTFf, char *hline)
{
char *stringptr, *descstr, *as;
#ifndef NODEBUG
if(V_USELESS)
fprintf(stderr, "parsemethodtype(FILE *, FILE *)\n");
#endif
descstr=NULL;
as=NULL;
/* parse method types until we get to a line
* matching DONINT expression
*/
while(docgen_recmp(DONEINT, hline) && !feof(Hf)) {
#ifndef NODEBUG
if(V_USELESS)
fprintf(stderr, "%s\n", hline);
#endif
if((!strncmp(hline,"/*",2)) || (!strncmp(hline, "//",2))) {
descstr=hline+2;
as=strstr(descstr,"*/");
if(as)
*as='\0';
#ifdef OBJC
[myForm putLine:" "];
[myForm putLine:descstr];
#else
fputline(RTFf,"\n");
fputline(RTFf,descstr);
#endif
fprintf(RTFf,"\t");
}
if(!docgen_recmp(METHEXP, hline) && (GLOB_undoc ? docgen_recmp(UNDOC, hline) : 1)) { /* If this is a method expression */
stringptr=hline;
SKIPSPACE(stringptr);
if(*stringptr) {
#ifdef OBJC
[myForm putFont:1 Char:stringptr[0]];
#else
fputfchar(RTFf, 1, stringptr[0]); /* put the + or - char */
#endif
stringptr++;
}
SKIPSPACE(stringptr);
if(*stringptr =='(') { /* Skip past the type */
SKIPPARENS(stringptr);
}
#ifdef OBJC
[myForm changeFont:0];
#else
fchangefont(RTFf, 0);
#endif
SKIPSPACE(stringptr);
while(*stringptr != ':' && !isspace(*stringptr) && *stringptr != ';' && *stringptr)
fputc(*stringptr++, RTFf);
if(*stringptr && *stringptr!=';') {
fputc(*stringptr++, RTFf);
}
while(*stringptr != ';' && *stringptr) {
SKIPSPACE(stringptr);
if(*stringptr=='(') { /* And not all argyments have a type */
/* And we don't need the
* type for the list of
* arguments
*/
SKIPPARENS(stringptr);
}
SKIPSPACE(stringptr);
while(!isspace(*stringptr) && *stringptr && *stringptr!=';' && (*stringptr!=':'))
stringptr++;
SKIPSPACE(stringptr);
while(*stringptr != ':' && *stringptr && *stringptr != ';')
fputc(*stringptr++, RTFf);
if(*stringptr && *stringptr != ';')
fputc(*stringptr++, RTFf);
/* fputc(' ', RTFf); */
}
#ifdef OBJC
[myForm putLine:" "];
#else
fputline(RTFf," ");
#endif
fprintf(RTFf, "\t");
} /* if */
free(hline);
hline=fgetdline(Hf);
} /* while */
free(hline);
#ifndef NODEBUG
if(V_USELESS)
fprintf(stderr, "parsemethodtype: returning\n");
#endif
}
int dcmp(void *a, void *b)
{
char *ca=(*(char **)a);
char *cb=(*(char **)b);
SKIPSPACE(ca);
SKIPSPACE(cb);
if(*ca!=*cb)
return *ca-*cb;
if(*ca)
ca++;
if(*cb)
cb++;
SKIPSPACE(ca);
SKIPSPACE(cb);
if(*ca=='(') {
SKIPPARENS(ca);
}
if(*cb=='(') {
SKIPPARENS(cb);
}
SKIPSPACE(ca);
SKIPSPACE(cb);
return strcmp(ca, cb);
}
void parsecomments(FILE *RTFf, char *mline, DSTRING *dynstr)
{
char blank[]="#";
char punchar[3], tline[255];
char *hline, *stringptr, *opstrptr=NULL;
stringptr=arrdstr(GLOB_istring);
if(dynstr)
opstrptr=arrdstr(dynstr);
else
opstrptr=blank;
#ifndef NODEBUG
if(V_USELESS)
fprintf(stderr,"\n\n%s\n\n", stringptr);
#endif
{
char *z=strstr(mline, "*/");
if(z) {
z[0]=' ';
z[1]=' ';
}
if(!docgen_recmp("^ *\\* *", mline)) {
z=strstr(mline, "*");
if(z) {
z[0]=' ';
}
}
}
hline=strtok(mline, DESCRIPTOK);
while(hline!=NULL) {
if(strrchr(PUNCS,hline[strlen(hline)-1]) != NULL) {
punchar[0]=hline[strlen(hline)-1];
punchar[1]=' ';
punchar[2]='\0';
hline[strlen(hline)-1]='\0';
#ifndef NODEBUG
if(V_USELESS)
fprintf(stderr,"%s\n", hline);
#endif
}
else {
punchar[0]=' ';
punchar[1]='\0';
}
strcpy(tline, "#");
strcat(tline, hline);
strcat(tline, "#");
if(!strstr(stringptr, tline) && !strstr(opstrptr, tline)) {
bool bolded=no;
bool italicized=no;
bool underlined=no;
bool fancyd=no;
if(GLOB_fancy) {
while(!fancyd) {
#ifndef NODEBUG
if(V_USELESS)
printf("%s\n", hline);
#endif
switch(*hline) {
case '*':
if((hline[strlen(hline)-1]=='*') && (strlen(hline)>1)) {
#ifdef OBJC
[myForm makeBold];
#else
fmakebold(RTFf);
#endif
hline++;
hline[strlen(hline)-1]='\0';
bolded=yes;
}
else
fancyd=yes;
break;
case '%':
if((hline[strlen(hline)-1]=='%') && (strlen(hline)>1)) {
#ifdef OBJC
[myForm makeItalic];
#else
fmakeitalic(RTFf);
#endif
hline++;
hline[strlen(hline)-1]='\0';
italicized=yes;
}
else
fancyd=yes;
break;
case '_':
if((hline[strlen(hline)-1]=='_') && (strlen(hline)>1)) {
#ifdef OBJC
[myForm makeUnderline];
#else
fmakeul(RTFf);
#endif
hline++;
hline[strlen(hline)-1]='\0';
underlined=yes;
}
else
fancyd=yes;
break;
default:
fancyd=yes;
break;
}
}
}
fprintf(RTFf, "%s%s", hline, punchar);
if(bolded)
#ifdef OBJC
[myForm unBold];
#else
funbold(RTFf);
#endif
if(italicized)
#ifdef OBJC
[myForm unItalic];
#else
funitalic(RTFf);
#endif
if(underlined)
#ifdef OBJC
[myForm unUnderline];
#else
funul(RTFf);
#endif
}
else {
#ifdef OBJC
[myForm makeItalic];
#else
fmakeitalic(RTFf);
#endif
fprintf(RTFf, "%s%s", hline, punchar);
#ifdef OBJC
[myForm unItalic];
#else
funitalic(RTFf);
#endif
}
hline=strtok(NULL, DESCRIPTOK);
}
#ifdef OBJC
[myForm putLine:" "];
#else
fputline(RTFf, " ");
#endif
free(stringptr);
if(dynstr)
free(opstrptr);
}
static char *findrealchr(char *line, int find)
{
char *ret=line;
bool inComm=no;
while(*ret) {
if(!strncmp(ret,"//", 2)) /* The rest is all comments */
return NULL;
if(!strncmp(ret,"/*",2))
inComm=yes;
if(!strncmp(ret,"*/",2))
inComm=no;
if(*ret==find && !inComm)
return ret;
ret++;
}
return NULL;
}
static char *parseoneliner(DSTRING *methstring, char *ivarstr, char *mline)
{
char *stringptr;
/* All this just to handle one-line methods */
stringptr=findrealchr(mline,'{');
if(!docgen_recmp(METHEXP, mline) && (GLOB_autodoc || stringptr)) {
if(stringptr) {
*stringptr='\0';
stringptr++;
}
else
stringptr=strchr(mline,'\n');
if(stringptr) {
*stringptr='\0';
stringptr++;
}
else
stringptr=&mline[strlen(mline)];
dstrarrcat(methstring, mline);
daddchar(methstring, '\n');
dstrarrcat(methstring, "/*\n");
if(!docgen_recmp(SETEXP, mline)) {
char autostr[strlen(mline)];
char *endcol, *endto;
char *setstr=autostr;
strcpy(setstr, mline);
setstr=strstr(mline,"set");
setstr+=3;
endcol=strchr(setstr,':');
*endcol='\0';
endcol++;
SKIPSPACE(endcol);
if(*endcol=='(') {
SKIPPARENS(endcol);
}
SKIPSPACE(endcol);
endto=endcol;
while(!isspace(*endto) && *endto)
endto++;
*endto='\0';
/* if(strstr(ivarstr, setstr)) { */
dstrarrcat(methstring, "Sets ");
if(isupper(*setstr))
*setstr=tolower(*setstr);
dstrarrcat(methstring, setstr);
dstrarrcat(methstring, " to ");
dstrarrcat(methstring, endcol);
/* } */
}
else {
char autostr[strlen(mline)];
char *endto;
char *getstr=autostr;
strcpy(getstr, mline);
SKIPSPACE(getstr);
if(*getstr)
getstr++;
SKIPSPACE(getstr);
if(*getstr=='(') {
SKIPPARENS(getstr);
}
endto=getstr;
while(!isspace(*endto) && *endto)
endto++;
*endto='\0';
if(strstr(ivarstr, getstr)) {
dstrarrcat(methstring, "Returns ");
dstrarrcat(methstring, getstr);
}
}
dstrarrcat(methstring, "\n*/\n");
mline=stringptr;
}
return mline;
}
#define NULLPOS ((fpos_t)0)
static char *gathermethod(char *mline, FILE *Mf, fpos_t lastComment)
{
bool first=yes;
DSTRING *methstring;
char *sline;
char *ivarstr=arrdstr(GLOB_istring);
fpos_t currPos;
sline=mline;
methstring=initdstr();
while(!feof(Mf)) {
while(*sline!='/' && *sline!='{' && *sline) {
daddchar(methstring, *sline);
sline++;
}
if(GLOB_before && first && lastComment) {
char *tline;
char *zline=sline;
fgetpos(Mf, &currPos);
if(fsetpos(Mf, &lastComment)<0) {
perror("docgen:gathermethod():fsetpos->lastComment");
exit(2);
}
tline=fgetdline(Mf);
sline=tline;
while(*sline!='/' && *sline) {
sline++;
}
if(*sline == '/') {
if(!strncmp(sline, "//", 2)) {
dstrarrcat(methstring, "\n/*\n");
dstrarrcat(methstring, sline+2);
dstrarrcat(methstring, "\n*/\n");
}
else if(!strncmp(sline, "/*", 2)) {
daddchar(methstring,'\n');
while(!feof(Mf) && docgen_recmp(STOPEXP, sline)) {
dstrarrcat(methstring, sline);
daddchar(methstring,'\n');
free(tline);
tline=fgetdline(Mf);
sline=tline;
}
if(feof(Mf)) {
fprintf(stderr, "Unexpected eof\n");
exit(3);
}
sline=strstr(tline, "*/");
dstrarrcat(methstring, tline);
// daddchar(methstring,'\n');
sline+=2;
}
}
free(tline);
sline=zline;
if(fsetpos(Mf, &currPos)<0) {
perror("docgen:gathermethod():fsetpos->currPos");
exit(2);
}
}
if((*sline == '/')) {
if(!strncmp(sline, "//", 2) && GLOB_after) {
dstrarrcat(methstring, "\n/*\n");
dstrarrcat(methstring, sline+2);
dstrarrcat(methstring, "\n*/\n");
}
else if(!strncmp(sline, "/*", 2)) {
if(GLOB_after)
daddchar(methstring,'\n');
while(!feof(Mf) && docgen_recmp(STOPEXP, sline)) {
if(GLOB_after) {
dstrarrcat(methstring, sline);
daddchar(methstring,'\n');
}
free(mline);
mline=fgetdline(Mf);
sline=mline;
}
if(feof(Mf)) {
fprintf(stderr, "Unexpected eof\n");
exit(3);
}
sline=strstr(mline, "*/");
if(GLOB_after) {
dstrarrcat(methstring, mline);
// daddchar(methstring,'\n');
}
sline+=2;
continue;
}
}
else if(*sline=='{') {
if(first)
daddchar(methstring, '{');
dstrarrcat(methstring, "\n}\n");
sline=arrdstr(methstring);
freedstr(methstring);
methstring=initdstr();
mline=parseoneliner(methstring, ivarstr, sline);
dstrarrcat(methstring, mline);
dstrarrcat(methstring, "\n\n");
sline=arrdstr(methstring);
freedstr(methstring);
free(ivarstr);
return sline;
}
first=no;
daddchar(methstring,' ');
free(mline);
mline=fgetdline(Mf);
sline=mline;
}
return NULL;
}
#define GETNEWLINE \
{ mline=nextline;\
if(!mline) {\
free(qline);\
qline=dqueuesize(methlist) ? *(char **)dsdequeue(methlist) : NULL;\
\
if(!qline)\
return;\
\
mline=qline;\
}\
\
nextline=strchr(mline,'\n');\
if(nextline) {\
*nextline='\0';\
nextline++;\
} }\
/* Print description
* text as long as this
* isn't a line with a
* comment ender.
*
* But some comments
* might have text on
* the same line as the
* comment ender.
*
* Should be no problem
* since we only want
* useful comments and
* they shouldn't be on
* the same line as a
* comment ender.
*
* But this could be
* changed to a
* do-while loop to
* handle that case.
*/
#ifdef OBJC
#define PUTMETHDESC [myForm putMethodDescription]
#define PUTLINE [myForm putLine:mline]
#else
#define PUTMETHDESC fputmethdesc(RTFf)
#define PUTLINE fputline(RTFf, mline)
#endif
#define COMMINTERN \
{ mline+=2;\
\
if(GLOB_firstcomm)\
parsecomments(RTFf, mline, dynstring);\
\
GETNEWLINE;\
\
while(mline && docgen_recmp(STOPEXP, mline)) {\
if(docgen_recmp(SEEALSO, mline)) {\
/* Any line that matches the See Also\
* expression is handled differently\
* So do this only if it isn't\
* a See Also line.\
*/\
/* void parsecomments(FILE *RTFf, char *mline, DSTRING *dynstr) */\
parsecomments(RTFf, mline, dynstring);\
}\
else { /* This IS a See Also Line. */\
PUTMETHDESC; \
/* If this isn't the last line\
* of comments, then the\
* font style is gonna be\
* goofed up\
*/\
PUTLINE; \
}\
\
GETNEWLINE;\
\
} /* while(docgen_recmp(STOPEXP, mline) && !feof(Mf)); */ \
if(GLOB_firstcomm && mline) \
parsecomments(RTFf, mline, dynstring); \
}
/* do until
* this matches
* a comment ender
*/
#define COMMIES 5
void parsemethods(FILE *Mf, FILE *RTFf, char *mline, fpos_t currPos)
{
char *hline, *stringptr;
DSTRING *dynstring;
DLSTQUEUE *methlist;
DSTRING *methstring;
int descrip=0;
int aclass=0;
char *qline, *nextline;
int parencount;
char *ivarstr;
int commieloop;
bool inComments=no;
fpos_t prePos=NULLPOS, lastComment=NULLPOS;
#ifndef NODEBUG
if(V_USELESS)
fprintf(stderr, "parsemethods(FILE *, FILE *, char *\"%s\")\n", mline);
#endif
methlist=initdqueue(sizeof(char *));
prePos=currPos;
/* go to the first _uncommented_ method */
while((docgen_recmp(METHEXP, mline) || inComments) && !feof(Mf)) {
if(!docgen_recmp(STARTEXP, mline)) {
inComments=yes;
lastComment=prePos;
}
if(!inComments && strstr(mline,"//"))
lastComment=prePos;
if(!docgen_recmp(STOPEXP, mline))
inComments=no;
free(mline);
fgetpos(Mf, &prePos);
mline=fgetdline(Mf);
}
if(feof(Mf))
return;
ivarstr=arrdstr(GLOB_istring);
methstring=initdstr();
qline=gathermethod(mline, Mf, lastComment);
if(qline)
dsenqueue(methlist, &qline);
#ifndef NODEBUG
if(V_USELESS)
fprintf(stderr,mline);
#endif
lastComment=NULLPOS;
fgetpos(Mf, &prePos);
mline=fgetdline(Mf);
inComments=no;
while(!feof(Mf) && docgen_recmp(DONEINT ,mline)) {
while((docgen_recmp(METHEXP, mline) || inComments) && !feof(Mf)) {
if(!docgen_recmp(STARTEXP, mline)) {
inComments=yes;
lastComment=prePos;
}
if(!inComments && strstr(mline,"//"))
lastComment=prePos;
if(!docgen_recmp(STOPEXP, mline))
inComments=no;
free(mline);
fgetpos(Mf, &prePos);
mline=fgetdline(Mf);
}
if(feof(Mf) && docgen_recmp(DONEINT, mline))
break;
qline=gathermethod(mline, Mf, lastComment);
#ifndef NODEBUG
if(V_USELESS)
fprintf(stderr,qline);
#endif
if(qline)
dsenqueue(methlist, &qline);
lastComment=NULLPOS;
fgetpos(Mf, &prePos);
mline=fgetdline(Mf);
}
if(mline)
free(mline);
dynstring=initdstr();
dstrarrcat(dynstring, DEFITAL);
if(GLOB_sort)
dlstsort(methlist, dcmp);
qline=*(char **)dsdequeue(methlist);
if(!qline)
return;
nextline=strchr(qline, '\n');
if(!nextline)
return;
*nextline='\0';
nextline++;
mline=qline;
if(!mline)
return;
if(!docgen_recmp(CLASSMETH, mline)) {
#ifdef OBJC
[myForm putMethodHeader:"Class"];
#else
fputmethodh(RTFf, "Class"); /* Set up for Class Methods */
#endif
aclass=1;
}
else
#ifdef OBJC
[myForm putMethodHeader:"Instance"];
#else
fputmethodh(RTFf, "Instance");
#endif
/* keep parsing until we hit a line matching DONEINT */
while(mline && docgen_recmp(DONEINT, mline)) {
while(mline && docgen_recmp(DONEINT, mline) && docgen_recmp(METHEXP, mline)) {
GETNEWLINE;
}
if(GLOB_undoc ? !docgen_recmp(UNDOC, mline) : 0) {
free(qline);
qline=dqueuesize(methlist) ? *(char **)dsdequeue(methlist) : NULL;
if(!qline)
break;
nextline=strchr(qline, '\n');
if(nextline) {
*nextline='\0';
nextline++;
}
mline=qline;
continue;
}
if(!docgen_recmp(METHEXP, mline)) { /* this line, or any line found in the .m file
* matches the METHEXP pattern.
*/
if(aclass && docgen_recmp(CLASSMETH, mline)) {
#ifdef OBJC
[myForm putMethodHeader:"Instance"];
#else
fputmethodh(RTFf, "Instance");
#endif
aclass=0;
}
descrip=0; freedchars(dynstring); /* These variables are used with
* the comments, but should be reset
* for every new method.
*/
/* Everything between here and the comment beginning
* with DONE is just for printing the name of the method
* and find the arguments to the method
*/
hline=mline; /* We need to free mline
* so we must have another pointer
* that will be stepped through the string
*
* stringptr and hline are just pointers
* used for stepping
*
* It may seem pointless to use hline here
* because we just assign it to stringptr,
* but we want to reset stringptr back to
* hline's position later
*/
SKIPSPACE(hline);
stringptr=hline;
while(isspace(*stringptr) || *stringptr == '-' || *stringptr == '+')
stringptr++;
if(*stringptr == '(') { /* Right now we just want the name
* so skip the type
*/
SKIPPARENS(stringptr);
}
SKIPSPACE(stringptr);
#ifdef OBJC
[myForm putLine:" "];
[myForm putMethodL1];
#else
fputline(RTFf," "); /* Start a new line */
fputmethodl1(RTFf); /* Set up for method name */
#endif
while(*stringptr != ':' && *stringptr)
fputc(*stringptr++, RTFf);
if(*stringptr)
fputc(*stringptr++, RTFf);
while(*stringptr) { /* This while statement goes through
* the rest of the line and puts
* the name of each argument in
* the dynamic string, dynstring
*/
SKIPSPACE(stringptr);
if(*stringptr=='(') { /* And not all argyments have a type */
/* And we don't need the
* type for the list of
* arguments
*/
SKIPPARENS(stringptr);
}
SKIPSPACE(stringptr);
daddchar(dynstring, '#');
while(!isspace(*stringptr) && (*stringptr!=':') && *stringptr)
daddchar(dynstring, *stringptr++);
daddchar(dynstring, '#'); /* The '#' seperates each argument in the big
* list of names
*/
SKIPSPACE(stringptr);
while(*stringptr != ':' && *stringptr)
fputc(*stringptr++, RTFf);
if(*stringptr)
fputc(*stringptr++, RTFf);
} /* while(*stringptr) */
#ifdef OBJC
[myForm putLine:" "];
#else
fputline(RTFf, " ");
#endif
/* DONE parsing for arguments to method */
stringptr=hline; /* re-set stringptr back to hline
* which is the first non-space character
* in the line
*/
#ifdef OBJC
[myForm putMethodL2];
#else
fputmethodl2(RTFf); /* Set up for full method line */
#endif
fprintf(RTFf,"%c",stringptr[0]); /* That first character
* should be a + or -
* so print it specially
*/
#ifdef OBJC
[myForm changeFont:0];
#else
fchangefont(RTFf, 0);
#endif
stringptr++;
SKIPSPACE(stringptr);
if(*stringptr == '(') { /* Not all methods have a type */
parencount=1;
while(parencount && *stringptr) {
fputc(*stringptr++, RTFf);
if(*stringptr=='(')
parencount++;
else if(*stringptr==')')
parencount--;
}
if(*stringptr)
fputc(*stringptr++, RTFf);
}
#ifdef OBJC
[myForm makeBold];
#else
fmakebold(RTFf); /* The method name will be bold */
#endif
SKIPSPACE(stringptr);
while(*stringptr != ':' && *stringptr)
fputc(*stringptr++, RTFf);
if(*stringptr)
fputc(*stringptr++, RTFf); /* Put the ':' as bold also */
#ifdef OBJC
[myForm unBold];
#else
funbold(RTFf);
#endif
while(*stringptr) { /* Eveything else after the first ':'
* should be an argument.
*/
SKIPSPACE(stringptr);
if(*stringptr=='(') { /* If there is a type, print it unspecially */
/* Until you hit a
* closing ')'
*/
parencount=1;
while(parencount && *stringptr) {
fputc(*stringptr++, RTFf);
if(*stringptr=='(')
parencount++;
else if(*stringptr==')')
parencount--;
}
if(*stringptr)
fputc(*stringptr++, RTFf);
}
SKIPSPACE(stringptr);
#ifdef OBJC
[myForm makeItalic];
#else
fmakeitalic(RTFf); /* The argument itself is italicized */
#endif
while(!isspace(*stringptr) && (*stringptr!=':') && *stringptr)
fputc(*stringptr++, RTFf);
#ifdef OBJC
[myForm unItalic];
#else
funitalic(RTFf); /* Note: This is not a fun italic */
#endif
SKIPSPACE(stringptr);
fputc(' ', RTFf);
#ifdef OBJC
[myForm makeBold];
#else
fmakebold(RTFf);
#endif
while(*stringptr != ':' && *stringptr)
fputc(*stringptr++, RTFf);
if(*stringptr)
fputc(*stringptr++, RTFf);
#ifdef OBJC
[myForm unBold];
#else
funbold(RTFf);
#endif
} /* while(*stringptr) */
#ifdef OBJC
[myForm putLine:" "];
#else
fputline(RTFf, " ");
#endif
} /* if(!docgen_recmp(METHEXP, mline)) */
/* Handle up to COMMIES comments in a method */
for(commieloop=0;commieloop<COMMIES;commieloop++) {
GETNEWLINE;
if(!docgen_recmp(STARTEXP, mline)) { /* else this or any line that matches
* a comment beginning line will
* have it's comments printed.
* That's why this program will
* print out any comments in a
* method, even after it's already
* printed a No Description line
*/
COMMINTERN;
descrip=1;
}
else
break; /* get away from these commies! */
}
} /* while(docgen_recmp(DONEINT, mline) && !feof(Mf)) */
freedstr(dynstring);
free(ivarstr);
free(qline);
freedlist(methlist);
#ifndef NODEBUG
if(V_USELESS)
fprintf(stderr, "parsemethods: returning\n");
#endif
}
void traceinheritance(FILE *RTFf, char *hdir, char *hname)
{
char pathsep[]=":";
FILE *Hf;
char *hline, *stringptr, *FQh;
ofiletype fty;
DSTRING *dhname;
char *hpath, *honepath, *fhname;
static unsigned long of_counter=MAX_INHERIT_SEARCHES;
#ifndef NODEBUG
if(V_USELESS)
fprintf(stderr, "traceinheritance(FILE *, %s, %s)\n", hdir, hname);
#endif
dstrarrcat(GLOB_istring, hname);
daddchar(GLOB_istring, '#');
dhname=dstrarr(hdir);
hpath=arrdstr(dhname);
free(dhname);
dhname=dstrarr(hname);
dstrarrcat(dhname, ".h");
fhname=arrdstr(dhname);
free(dhname);
honepath=strtok(hpath, pathsep);
Hf=NULL;
FQh=NULL;
if(GLOB_recurs) { /* We want to recursively search for
* the file in every directory in directories
* of the search path.
*/
while(honepath!=NULL && FQh==NULL) { /* Keep looping until either
* we find a file or run out
* of directories.
*/
FQh=findfile(fhname, honepath);
honepath=strtok(NULL, pathsep);
}
if(FQh!=NULL) {
Hf=fopen(FQh,"r");
free(FQh);
}
}
else
while(honepath!=NULL && Hf==NULL) {
FQh=dirfile(honepath, fhname);
if(FQh) {
Hf=fopen(FQh, "r");
free(FQh);
}
honepath=strtok(NULL, pathsep);
}
free(fhname);
free(hpath);
if(Hf == NULL) {
if(V_STAT)
fprintf(stderr, "traceinheritance: %.200s not found in %.800s\n", hname, hdir);
return;
}
if(!--of_counter) { /* If this is true, the we must be tracing too many */
if(V_BADERR)
fprintf(stderr,"traceinheritance: We seem to have hit an infinite loop in\n%s\n",hname);
return;
}
#ifndef NODEBUG
if(V_USELESS)
fprintf(stderr, "of_counter = %ld\n", of_counter);
#endif
/* read to the @interface line in the .h file */
hline=fgetdline(Hf);
while(!feof(Hf) && docgen_recmp(INTERFACE, hline)) {
free(hline);
hline=fgetdline(Hf);
}
if(feof(Hf)) {
/* since all these eof error blocks are so
* similar I was thinking of having another
* function, but I don't like closing
* files outside of the function they were
* opened in. And a goto or macro wouldn't
* handle all the different cases
*/
free(hline);
if(V_BADERR)
fprintf(stderr,"Unexpected end of file %s\n", hname);
if(fclose(Hf) == EOF)
if(V_BADERR)
perror("I couldn't close the header file. Pray.");
of_counter++;
return;
}
/* check for wether we're dealing with a Class or
* Category
*/
if(strstr(hline, CLASSCHK) != NULL)
fty=class;
else if(strstr(hline, CATCHK) != NULL)
fty=category;
else {
free(hline);
if(fclose(Hf) == EOF)
if(V_BADERR)
perror("I couldn't close the header file. Pray.");
if(V_STAT)
fprintf(stderr,"traceinheritance: %s is neither a Class or a Category\n", hname);
of_counter++;
return;
}
/* If strtok fails on this first pass
* then exit with an error.
*/
if((stringptr=strtok(hline, INTTOK)) == NULL) {
free(hline);
if(V_ERR)
fprintf(stderr, "Improper @interface description in\n%s\n", hname);
if(fclose(Hf) == EOF)
if(V_BADERR)
perror("I couldn't close the header file. Pray.");
of_counter++;
return;
}
else
stringptr=strtok(NULL, INTTOK);
if(fty==class) {
stringptr=strtok(NULL, INTTOK);
if(stringptr != NULL) {
fprintf(RTFf, " %s %s",GLOB_sep, stringptr);
traceinheritance(RTFf, hdir, stringptr);
}
}
else {
stringptr=strtok(NULL, INTTOK);
if(stringptr!=NULL)
stringptr[strlen(stringptr)-1]='\0';
if(stringptr != NULL) {
fprintf(RTFf, " %s %s",GLOB_sep, stringptr);
traceinheritance(RTFf, hdir, stringptr);
}
}
of_counter++;
#ifndef NODEBUG
if(V_USELESS)
fprintf(stderr, "of_counter++ = %ld\n", of_counter);
#endif
if(fclose(Hf) == EOF)
if(V_BADERR)
perror("I couldn't close the header file. Pray.");
return;
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.