1 /* -*- Mode: C; c-basic-offset:4 ; -*- */
2 
3 #include <ctype.h>
4 #include "sowing.h"
5 #include "doc.h"
6 #include "patchlevel.h"
7 #ifdef STDC_HEADERS
8 #include <stdlib.h>
9 #include <string.h>
10 #endif
11 #ifdef HAVE_UNISTD_H
12 #include <unistd.h>
13 #endif
14 
15 /*
16    This is designed to work with comments in C programs.
17    It uses the standardized documentation to issue dummy routine
18    definitions to allow the creation of a Fortran to C library.
19 
20    This version of "header.c" is a modification of the file taken
21    from "~gropp/tools.n/c2fort" on 10/7/93.  Modifications have been
22    introduced so that elements of type void * in the files "nlfunc_v.h",
23    and "nlspmat_v.h", and "nlsles_v.h" are translated as pointers to
24    structures in the Fortran version (instead of the default, which is
25    no translation).  Note that pointers to void functions retain the
26    usual translation.
27 
28    An additional flag (flag2) is used in the calling sequence of
29    ProcessArgDefs() to indicate the files which require the modified
30    translation.   Also, an additional element, void_function, is added
31    to the structure ARG_LIST to distinguish pointers to void functions
32    from pointers to void structures.
33  */
34 
35 /* extern char GetSubClass(); */
36 
37 static int NoFortMsgs = 1;
38 /* NoFortWarnings turns off messages about things not being available in
39    Fortran */
40 static int NoFortWarnings = 1;
41 
42 /* when converting C type to Fortran for F90 interfaces keep any unknown ones */
43 static int useUserTypes = 1;
44 
45 /* This says to convert char **a to int*a, and cast to (char **)*a */
46 static int MultipleIndirectAreInts    = 1;
47 static int MultipleIndirectsAreNative = 0;
48 
49 /* Keep the file name to simplify finding files containing problems */
50 static char *CurrentFilename = 0;
51 
52 /* Whether to replace pointers with indices to a mapping of pointers */
53 static int MapPointers = 0;
54 static char ptrprefix[32] = "__";
55 
56 /* If this is set to true, "void *" are translated as pointers to structures */
57 static int TranslateVoidStar = 0;
58 
59 /* If this is set to true, generate an "ifdef" block for the name of the
60    Fortran interface to handle the case of no underscore and all caps
61  */
62 static int IfdefFortranName = 0;
63 
64 /* If true, add a last integer argument to int functions and return its
65    value in the last parameter */
66 static int useFerr = 0;
67 /* Defaults for these are "ierr" and "__ierr" */
68 static const char *errArgNameParm = 0;
69 static const char *errArgNameLocal = 0;
70 
71 /* Enable the MPI definitions */
72 static int isMPI = 0;
73 
74 /* Enable and use MPI-2 conversion functions */
75 static int isMPI2 = 0;
76 
77 /* Enable profiling name output */
78 static int DoProfileNames = 0;
79 
80 /* If 1, output header immediately; otherwise, defer until declarations
81    processed */
82 static int OutputImmed = 1;
83 
84 /* If 1, generate ANSI style headers instead */
85 static int AnsiHeader = 0;
86 
87 /* If 1, declarations are in ANSI prototype form */
88 static int AnsiForm = 0;
89 
90 /* If 0, do not generate the ifndef DEBUG_ALL wrapper */
91 static int AddDebugAll = 1;
92 
93 /* If 0, do not generate Fortran 9x interface module */
94 static int F90Module = 0;
95 static FILE *fmodout = 0;
96 
97 /* Catch serious problems */
98 #define MAX_ERR 100
99 static int ErrCnt = 0;
100 
101 /* Debugging for development */
102 static int Debug = 0;
103 #define DBG(a) {if (Debug) printf(a);}
104 #define DBG2(a,b) {if (Debug)printf(a,b);}
105 
106 /* Default #ifdef names for generated code */
107 static char FortranCaps[256] = "FORTRANCAPS";
108 static char FortranUscore[256] = "FORTRANUNDERSCORE";
109 static char FortranDblUscore[256] = "FORTRANDOUBLEUNDERSCORE";
110 static char Pointer64Bits[256] = "POINTER_64_BITS";
111 static char BuildProfiling[256] = "MPI_BUILD_PROFILING";
112 
113 /* Lists of type names */
114 static void *nativeList;
115 static void *nativePtrList;
116 static void *toptrList;
117 static void *parmList;
118 static SYConfigCmds configcmds[5];
119 
120 /* We also need to make some edits to the types occasionally.  First, note
121    that double indirections are often bugs */
122 #define MAX_TYPE_NAME 60    /* Maximum length of a type name */
123 #define MAX_ARGS      128   /* Maximum number of args to a function */
124 #define MAX_TYPES      64   /* Maximum number of types to a function */
125 
126 #ifndef MAX_PATH_NAME
127 #define MAX_PATH_NAME 1024
128 #endif
129 
130 typedef struct {
131     char *name;
132     int  has_star, is_char, is_native, has_array,
133 	type,              /* Index into TYPE_LIST array */
134 	is_FILE, void_function;
135     int  implied_star;
136 } ARG_LIST;
137 typedef struct {
138     int is_char, is_native, implied_star, is_FILE, type_has_star, is_void;
139     int is_mpi;
140     char type[MAX_TYPE_NAME];
141 } TYPE_LIST;
142 typedef struct {
143     char name[MAX_TYPE_NAME];
144     int  num_stars;
145 } RETURN_TYPE;
146 
147 /* Forward defs */
148 void OutputToken ( FILE *, char *, int );
149 void OutputRoutine ( FILE *, FILE *, char *, char *, char );
150 void OutputFortranToken( FILE *, int, const char *);
151 void SkipText ( FILE *, char *, char *, char );
152 int SkipToSynopsis ( FILE *, char );
153 int FindNextANToken ( FILE *, char *, int * );
154 void OutputBuf ( FILE **, char *, char *, FILE *, char * );
155 void OutputMacro ( FILE *, FILE *, char *, char * );
156 void ProcessFunctionType ( FILE *, FILE *, char *, int *,
157 				    char *, RETURN_TYPE *, int );
158 void ProcessArgList ( FILE *, FILE *, char *, int *, char *,
159 				ARG_LIST[MAX_ARGS], int *, RETURN_TYPE *,
160 				int, TYPE_LIST *, int *, int );
161 int ProcessArgDefs ( FILE *, FILE *, ARG_LIST *, int, TYPE_LIST *,
162 			       int *, int *, int, char *, int );
163 void PrintBody ( FILE *, int, char *, int, int, ARG_LIST *,
164 			   TYPE_LIST *, RETURN_TYPE * );
165 void PrintDefinition ( FILE *, int, char *, int, int, ARG_LIST *,
166 			   TYPE_LIST *, RETURN_TYPE * );
167 int NameHasUnderscore ( char * );
168 void OutputRoutineName ( char *, FILE * );
169 void OutputUniversalName ( FILE *, char * );
170 int GetTypeName ( FILE *, FILE *, TYPE_LIST *, int, int, int );
171 int GetArgName ( FILE *, FILE *, ARG_LIST *, TYPE_LIST *, int );
172 void FixupArgNames( int, ARG_LIST * );
173 void OutputBalancedString ( FILE *, FILE *, int, int );
174 char *ToCPointer ( char *, char *, int );
175 const char *ArgToFortran( const char *typeName );
176 void FreeArgs( ARG_LIST *, int );
177 int MPIU_Strncpy( char *, const char *, size_t );
178 int MPIU_Strnapp( char *, const char *, size_t );
179 void Abort( const char *, const char *, int );
180 void DoBfortHelp ( char * );
181 #define ABORT(msg) Abort(msg,__FILE__,__LINE__)
182 
183 /*D
184   bfort - program to extract short definitions for a Fortran to C interface
185 
186   Input:
187 . filenames - Names the files from which lint definitions are to be extracted
188 . -nomsgs   - Do not generate messages for routines that can not be converted
189               to Fortran.
190 . -nofort   - Generate messages for all routines/macros without a Fortran
191               counterpart.
192 . -dir name - Directory for output file
193 . -I name   - file that contains common includes
194 . -mapptr   - translate pointers to integer indices
195 . -ptrprefix - prefix for names of functions to convert to/from pointers
196               (default is __).  The macro that selects the form based on the
197               pointer size can be changed with -ptr64.
198 . -anyname   - Generate a single Fortran wrapper that works for almost all
199                systems, by adding C preprocessor names (see below).  These
200                names can be changed with -fcaps, -fuscore, and -fduscore.
201 . -ferr     - Fortran versions return the value of the routine as the last
202               argument (an integer).  This is used in MPI and is a not
203 	      uncommon approach for handling error returns.
204 . -mpi      - Handle MPI datatypes (some things are pointers by definition)
205 . -mpi2     - Handle MPI datatypes using MPI2 converstion functions
206               (some things are pointers by definition)
207 . -no_pmpi  - Do not generate PMPI names
208 . -pmpi name - Change macro used to select MPI profiling version
209 . -noprofile - Turn off the generation of the profiling version
210 . -mnative  - Multiple indirects are native datatypes (no coercion)
211 . -voidisptr - Consider "void *" as a pointer to a structure.
212 . -ansi      - C routines use ANSI prototype form rather than K&R C form
213 . -noansi    - C routines use K&R C form (no prototypes)
214 . -ansiheader - Generate ANSI-C style headers instead of Fortran interfaces
215   This will be useful for creating ANSI prototypes   without ANSI-fying the
216   code.  These use a trick to provide both ANSI and non-ANSI prototypes.
217   The declarations are wrapped in "ANSI_ARGS", the definition of which
218   should be
219 .vb
220   #ifdef ANSI_ARG
221   #undef ANSI_ARG
222   #endif
223   #ifdef __STDC__
224   #define ANSI_ARGS(a) a
225   #else
226   #define ANSI_ARGS(a) ()
227   #endif
228 .ve
229 . -nodebug  - Do not add
230 .vb
231   #ifndef DEBUG_ALL
232   #define DEBUG_ALL
233   #endif
234 .ve
235   to the wrapper file.
236 . -anyname   - Generate a single wrapper that can handle the three most common
237                cases: trailing underscore, no underscore, and all caps.  The
238                choice is based on whether
239 .vb
240      FORTRANCAPS:       Names are uppercase, no trailing underscore
241      FORTRANUNDERSCORE: Names are lowercase, trailing underscore
242               are defined.
243      FORTRANDOUBLEUNDERSCORE: Names are lowercase, with TWO trailing
244 .ve
245       underscores.  This is needed when some versions of "f2c" are
246       used to generate C for Fortran routines.  Note that f2c uses two
247       underscores ONLY when the name already contains an underscore
248       (at least on the FreeBSD system that I use that uses f2c).
249       To handle this case, the generated code contains the second
250       underscore only when the name already contains one.
251 
252      If -mapptr is also chosen, then
253 .vb
254      POINTER_64_BITS
255 .ve
256                will also be used to determine if pointers are to long to
257                fit in a 32-bit Fortran integer.  Routines that destroy
258                a pointer will need to manually insert a call to
259                __RmPointer.  The routines for managing the pointers are
260 	       in ptrcvt.c
261 
262 	       In addition, if -mpi is used and -no_pmpi is not, the MPI
263                profiling names are also generated, surrounded by
264                MPI_BUILD_PROFILING.
265 
266   Note:
267   We really need a way to specify a general type as a pointer, so that it
268   will be handled as a pointer.  The -mpi option is a kludge for a pressing
269   need.  Eventually should provide a "-ptr name" option and keep in a
270   search space when looking for known types.
271 
272   Author:
273   Bill Gropp
274 D*/
main(int argc,char ** argv)275 int main( int argc, char **argv )
276 {
277     char routine[MAX_ROUTINE_NAME];
278     char *infilename;
279     char outfilename[MAX_PATH_NAME];
280     char dirname[MAX_PATH_NAME];
281     char fname[MAX_PATH_NAME], *p;
282     FILE *fd, *fout, *incfd;
283     char kind;
284     char incfile[MAX_FILE_SIZE];
285     char incbuffer[MAX_PATH_NAME];
286     int  n_in_file;
287     int  f90mod_skip_header = 1;
288 
289     /* Initialize setup for config files */
290     SYConfigDBInit("native", &nativeList);
291     SYConfigDBInit("nativeptr", &nativePtrList);
292     SYConfigDBInit("toptr", &toptrList);
293     SYConfigDBInit("parm", &parmList);
294     configcmds[0].name     = "native";
295     configcmds[0].docmd    = SYConfigDBInsert;
296     configcmds[0].cmdextra = nativeList;
297     configcmds[1].name     = "nativeptr";
298     configcmds[1].docmd    = SYConfigDBInsert;
299     configcmds[1].cmdextra = nativePtrList;
300     configcmds[2].name     = "toptr";
301     configcmds[2].docmd    = SYConfigDBInsert;
302     configcmds[2].cmdextra = toptrList;
303     configcmds[3].name     = "parm";
304     configcmds[3].docmd    = SYConfigDBInsert;
305     configcmds[3].cmdextra = parmList;
306     configcmds[4].name     = 0;
307 
308 /* process all of the files */
309     if (MPIU_Strncpy( dirname, ".", sizeof(dirname) )) {
310 	ABORT( "Unable to set dirname to \".\"" );
311     }
312     incfile[0]  = 0;
313     SYArgGetString( &argc, argv, 1, "-dir", dirname, MAX_PATH_NAME );
314     SYArgGetString( &argc, argv, 1, "-I",   incfile, MAX_PATH_NAME );
315     NoFortMsgs		   = SYArgHasName( &argc, argv, 1, "-nomsgs" );
316     MapPointers		   = SYArgHasName( &argc, argv, 1, "-mapptr" );
317     if (MapPointers) {
318 	SYArgGetString( &argc, argv, 1, "-ptrprefix", ptrprefix, 32 );
319     }
320     useFerr		   = SYArgHasName( &argc, argv, 1, "-ferr" );
321     isMPI		   = SYArgHasName( &argc, argv, 1, "-mpi" );
322     isMPI2      	   = SYArgHasName( &argc, argv, 1, "-mpi2" );
323     if (isMPI || isMPI2) DoProfileNames = 1;
324     if (SYArgHasName( &argc, argv, 1, "-no_pmpi" ))
325 	DoProfileNames = 0;
326     TranslateVoidStar	   = SYArgHasName( &argc, argv, 1, "-voidisptr" );
327     MultipleIndirectsAreNative = SYArgHasName( &argc, argv, 1, "-mnative" );
328 
329     /* ANSI by default; read and discard -ansi for backward compatibility */
330     AnsiForm = 1;
331     if (SYArgHasName( &argc, argv, 1, "-noansi" )) {
332 	AnsiForm = 0;
333     }
334     (void) SYArgHasName( &argc, argv, 1, "-ansi" );
335     AnsiHeader		       = SYArgHasName( &argc, argv, 1, "-ansiheader" );
336     AddDebugAll                = SYArgHasName( &argc, argv, 1, "-nodebug" );
337     IfdefFortranName           = SYArgHasName( &argc, argv, 1, "-anyname" );
338 /* Get replacement names for ifdef items in generated code */
339     SYArgGetString( &argc, argv, 1, "-fcaps", FortranCaps, 256 );
340     SYArgGetString( &argc, argv, 1, "-fuscore", FortranUscore, 256 );
341     SYArgGetString( &argc, argv, 1, "-fduscore", FortranDblUscore, 256 );
342     SYArgGetString( &argc, argv, 1, "-ptr64", Pointer64Bits, 256 );
343     SYArgGetString( &argc, argv, 1, "-pmpi", BuildProfiling, 256 );
344     if (SYArgHasName( &argc, argv, 1, "-noprofile" )) DoProfileNames = 0;
345 
346     if (AnsiHeader) OutputImmed = 0;
347 
348     if (SYArgHasName( &argc, argv, 1, "-help" )) {
349 	DoBfortHelp( argv[0] );
350 	exit( 1 );
351     }
352     if (SYArgHasName( &argc, argv, 1, "-version" )) {
353 	printf( "bfort (sowing) release %d.%d.%d of %s\n",
354 		PATCHLEVEL, PATCHLEVEL_MINOR, PATCHLEVEL_SUBMINOR,
355 		PATCHLEVEL_RELEASE_DATE );
356 	exit( 1 );
357     }
358 
359     /* Read the basics, such as predefined C types */
360     if (SYGetFileFromPathEnv(BASEPATH, "BFORT_CONFIG_PATH", NULL,
361 			     "bfort-base.txt", fname, 'r')) {
362 	if (!SYReadConfigFile(fname, ' ', '#', configcmds, 4)) {
363 	    fprintf(stderr, "Unable to read configure file bfort-base.txt");
364 	    exit(1);
365 	}
366     }
367     else {
368 	fprintf(stderr, "Unable to find bfort-base.txt config file in %s\n",
369 		BASEPATH);
370 	exit(1);
371     }
372     /* Based on options such as isMPI and isMPI2, load the appropriate
373        config files */
374     if (isMPI || isMPI2) {
375 	if (SYGetFileFromPathEnv(BASEPATH, "BFORT_CONFIG_PATH", NULL,
376 				 "bfort-mpi.txt", fname, 'r')) {
377 	    if (!SYReadConfigFile(fname, ' ', '#', configcmds, 4)) {
378 		fprintf(stderr, "Unable to read configure file bfort-mpi.txt");
379 		exit(1);
380 	    }
381 	}
382 	else {
383 	    fprintf(stderr, "Uable to read MPI config file bfort-mpi.txt in %s\n",
384 		    BASEPATH);
385 	    exit(1);
386 	}
387     }
388 /*    if (isPETSc) {
389       }*/
390     /* Allow the user to override the variable name used for the error
391        parameter. */
392     if (useFerr) {
393 	if (!errArgNameParm) {
394 	    if (SYConfigDBLookup("parm", "errparm",
395 				 &errArgNameParm, parmList) != 1) {
396 		errArgNameParm = "ierr";
397 	    }
398 	}
399 	if (!errArgNameLocal) {
400 	    if (SYConfigDBLookup("parm", "errparmlocal",
401 				 &errArgNameLocal, parmList) != 1) {
402 		errArgNameLocal = "__ierr";
403 	    }
404 	}
405     }
406 
407     /* Open up the file of public includes */
408     if (incfile[0]) {
409 	incfd = fopen( incfile, "r" );
410 	if (!incfd) {
411 	    ErrCnt++;
412 	    fprintf( stderr, "Could not open file %s for -I option\n", incfile );
413 	    if (ErrCnt > MAX_ERR) ABORT( "" );
414 	}
415     }
416     else
417 	incfd = 0;
418 
419     /* See if we should create the F90 Module file. */
420     f90mod_skip_header = SYArgHasName( &argc, argv, 1, "-f90mod_skip_header" );
421     if (!f90mod_skip_header) {
422 	/* Check for the more appropriate spelling */
423 	f90mod_skip_header =
424 	    SYArgHasName( &argc, argv, 1, "-f90mod-skip-header" );
425     }
426     /* If an f90modfile argument is provided, then enable the f90module */
427     if (SYArgHasName( &argc, argv, 0, "-f90modfile" )) {
428 	F90Module = 1;
429     }
430 
431     /* If there is a f90 module file, open it now */
432     if (F90Module) {
433 	char fmodfile[MAX_FILE_SIZE];
434 	if (!SYArgGetString( &argc, argv, 1, "-f90modfile",
435 			     fmodfile, MAX_FILE_SIZE )) {
436 	    if (MPIU_Strncpy( fmodfile, "f90module.f90", sizeof(fmodfile) )) {
437 		ABORT( "Unable to set the name of the Fortran 90 module file" );
438 	    }
439 	}
440 
441 	fmodout = fopen( fmodfile, "w" );
442 	if (!fmodout) {
443 	    ErrCnt++;
444 	    fprintf( stderr, "Could not open file %s for Fortran 90 interface output\n", fmodfile );
445 	    if (ErrCnt > MAX_ERR) ABORT( "" );
446 	    F90Module = 0;
447 	}
448 	else {
449 	  if (!f90mod_skip_header) {
450 	      OutputFortranToken( fmodout, 0, "module f90header" );
451 	      OutputFortranToken( fmodout, 0,"\n" );
452 	      OutputFortranToken( fmodout, 0, "interface" );
453 	      OutputFortranToken( fmodout, 0, "\n" );
454           }
455 	}
456     }
457 
458     argc--; argv++;
459     while (argc--) {
460 	/* Input filename */
461 	infilename = *argv++;
462 	fd = fopen( infilename, "r" );
463 	if (!fd) {
464 	    ErrCnt++;
465 	    fprintf( stderr, "Could not open file %s\n", infilename );
466 	    if (ErrCnt > MAX_ERR) ABORT( "" );
467 	    continue;
468         }
469 	n_in_file = 0;
470 	/* Remember file name */
471 	CurrentFilename = infilename;
472 
473 	/* Set the output filename */
474 	SYGetRelativePath( infilename, fname, MAX_PATH_NAME );
475 	/* Strip the trailer */
476 	p = fname + strlen(fname) - 1;
477 	while (p > fname && *p != '.') p--;
478 	*p = 0;
479 	/* Add an extra h to include files */
480 	if (p[1] == 'h') {
481 	    p[0] = 'h';
482 	    p[1] = 0;
483 	}
484 	if (AnsiHeader)
485 	    sprintf( outfilename, "%s/%s.ansi", dirname, fname );
486 	else
487 	    sprintf( outfilename, "%s/%sf.c", dirname, fname );
488 	/* Don't open the filename yet (wait until we know that we'll have
489 	   some output for it) */
490 	fout = NULL;
491 
492 	/* Pass 1: Generate the name mappings.
493 	   Eventually, we could store up the routine names and generate a
494 	   single, simpler block of definitions.
495 	   */
496 	while (FoundLeader( fd, routine, &kind )) {
497 	    if (!fout) {
498 		OutputBuf( &fout, infilename, outfilename, incfd, (char*)0 );
499 	    }
500 	    if (IfdefFortranName && fout && routine[0] &&
501 		(kind == ROUTINE || kind == MACRO)) {
502 		if (GetSubClass() != 'C')
503 		    OutputUniversalName( fout, routine );
504 		SkipText( fd, routine, infilename, kind );
505 	    }
506 	    else if (kind == INCLUDE) {
507 		int guard_x = 0;
508 		if (MPIU_Strncpy( incbuffer, "#include ", sizeof(incbuffer) )) {
509 		    ABORT( "Unable to set the name of the include buffer" );
510 		}
511 		/* Grumble.  We'll have to fix this eventually */
512 		if (routine[0] != '"' && routine[0] != '<') {
513 		    p = routine + strlen(routine) - 1;
514 		    if (*p == '>') {
515 			if (MPIU_Strnapp( incbuffer, "<", sizeof(incbuffer) )){
516 			    ABORT( "Cannot add < to include buffer" );
517 			}
518 		    }
519 		    else if (*p == '"') {
520 			if (MPIU_Strnapp( incbuffer, p, sizeof(incbuffer) ) ){
521 			    ABORT( "Cannot append file name to include buffer");
522 			}
523 		    }
524 		}
525 		/* Special case */
526 		/* fprintf( stderr, "include == |%s|\n", routine ); */
527 		if (strncmp( routine, "xtools/", 7 ) == 0) {
528 		    guard_x = 1;
529 		    OutputBuf( &fout, infilename, outfilename, incfd,
530 			       "#ifndef TOOLSNOX11\n" );
531 		}
532 		if (MPIU_Strnapp( incbuffer, routine, sizeof(incbuffer) )) {
533 		    ABORT( "Cannot add routine name to include buffer" );
534 		}
535 		CopyIncludeName( fd, incbuffer + strlen(incbuffer) );
536 		if (MPIU_Strnapp( incbuffer, "\n", sizeof(incbuffer) )) {
537 		    ABORT( "Cannot add newline to include buffer" );
538 		}
539 		OutputBuf( &fout, infilename, outfilename, incfd, incbuffer );
540 		if (guard_x) {
541 		    OutputBuf( &fout, infilename, outfilename, incfd,
542 			       "#endif\n" );
543 		    if (!fout) break;
544 		}
545 	    }
546 	    else SkipText( fd, routine, infilename, kind );
547 
548 	}
549 	rewind( fd );
550 	if (fout) {
551 	    fprintf( fout, "\n\n/* Definitions of Fortran Wrapper routines */\n" );
552 /* BFS - next lines are to allow C++ code to be called from fortran */
553 	    fprintf( fout,"#if defined(__cplusplus)\n");
554 	    fprintf( fout,"extern \"C\" {\n");
555 	    fprintf( fout,"#endif\n");
556 /* BFS end of changes for C++ */
557 	    fflush( fout );
558 	}
559 
560 	/* Pass 2: Generate the actual code */
561 	while (FoundLeader( fd, routine, &kind )) {
562 	    /* We need this test first to avoid creating an empty file,
563 	       particularly for initf.c */
564 	    if ((kind == ROUTINE || kind == MACRO) && GetSubClass() == 'C') {
565 		if (!NoFortMsgs && !NoFortWarnings) {
566 		    fprintf( stderr,
567 			     "%s %s(%s) can not be translated into Fortran\n",
568 			     (kind == ROUTINE) ? "Routine" : "Macro",
569 			     routine, CurrentFilename );
570 		}
571 		SkipText( fd, routine, infilename, kind );
572 		continue;
573 	    }
574 	    if (GetIsX11Routine()) {
575 		OutputBuf( &fout, infilename, outfilename, incfd,
576 			   "#ifndef TOOLSNOX11\n" );
577 	    }
578 	    if ((kind == ROUTINE || kind == MACRO) && fout == NULL) {
579 		OutputBuf( &fout, infilename, outfilename, incfd, (char *)0 );
580 		if (!fout) break;
581 	    }
582 #ifdef FOO
583 	    if (IfdefFortranName && fout && routine[0] &&
584 		(kind == ROUTINE || kind == MACRO)) {
585 		OutputUniversalName( fout, routine );
586 	    }
587 #endif
588 	    if (kind == ROUTINE) {
589 		n_in_file++;
590 		OutputRoutine( fd, fout, routine, infilename, kind );
591 	    }
592 	    else if (kind == MACRO) {
593 		/* Eventually we can handle this by using the Synopsis to
594 		   construct an equivalent definition */
595 		n_in_file ++;
596 		OutputMacro( fd, fout, routine, infilename );
597 	    }
598 /* moved include up BS */
599 	    if (GetIsX11Routine()) {
600 		OutputBuf( &fout, infilename, outfilename, incfd,
601 			   "#endif\n" );
602 		if (!fout) break;
603 	    }
604 	}
605 	fclose( fd );
606 
607 	if (fout) {
608 /* BFS added support for calling C++ from fortran */
609 	    fprintf(fout,"#if defined(__cplusplus)\n");
610 	    fprintf(fout,"}\n");
611 	    fprintf(fout,"#endif\n");
612 	    fclose( fout );
613 	    if (n_in_file == 0) {
614 		/* If all we put into the interface file was an include, we delete
615 		   it */
616 		unlink( outfilename );
617 	    }
618 	}
619     }
620     if (F90Module && fmodout) {
621 	if (!f90mod_skip_header) {
622 	    OutputFortranToken( fmodout, 0, "end interface" );
623 	    OutputFortranToken( fmodout, 0, "\n" );
624 	    OutputFortranToken( fmodout, 0, "end module" );
625 	    OutputFortranToken( fmodout, 0, "\n" );
626         }
627 	fclose( fmodout );
628 	fmodout = 0;
629     }
630 
631     return 0;
632 }
633 
634 /*
635  * Output routines
636  */
OutputToken(FILE * fout,char * p,int nsp)637 void OutputToken( FILE *fout, char *p, int nsp )
638 {
639     int i;
640     static int outcnt = 0;
641 
642     if (OutputImmed) {
643 	for (i=0; i<nsp; i++) putc( ' ', fout );
644 	fputs( p, fout );
645 	if (Debug) {
646 	    outcnt += nsp + strlen(p);
647 	    if (outcnt > 10000) {
648 		ABORT( "Exceeded output count limit!" );
649 	    }
650 	}
651     }
652 }
653 
OutputRoutine(FILE * fin,FILE * fout,char * name,char * filename,char kind)654 void OutputRoutine( FILE *fin, FILE *fout, char *name, char *filename,
655 		    char kind )
656 {
657     int         is_function;
658     ARG_LIST    args[MAX_ARGS];
659     TYPE_LIST   types[MAX_TYPES];
660     RETURN_TYPE rt;
661     int         nargs, nstrings;
662     int         ntypes;
663     int         flag2 = 0;
664 
665     /* Check to see if this is a C-only routine */
666     if (GetSubClass() == 'C') {
667 	if (!NoFortMsgs && !NoFortWarnings) {
668 	    fprintf( stderr, "Routine %s(%s) can not be translated into Fortran\n",
669 		     name, CurrentFilename );
670 	}
671 	SkipText( fin, name, filename, kind );
672 	return;
673     }
674 
675     /* Skip to trailer */
676     SkipText( fin, name, filename, kind );
677 
678     /* Get the call to the routine, including finding the argument names */
679     SkipWhite( fin );
680     ProcessArgList( fin, fout, filename, &is_function, name,
681 		    args, &nargs, &rt, 0, types, &ntypes, flag2 );
682 
683     if (!AnsiForm) {
684 	SkipWhite( fin );
685 	ProcessArgDefs( fin, fout, args, nargs, types, &ntypes, &nstrings, 0,
686 			name, flag2 );
687     }
688 
689     PrintBody( fout, is_function, name, nstrings, nargs, args, types, &rt );
690     if (F90Module) {
691 	PrintDefinition( fmodout, is_function, name, nstrings, nargs,
692 			 args, types, &rt );
693     }
694     /* Free the created space */
695     FreeArgs( args, nargs );
696 }
697 
698 /*
699     This routine skips the text part of a text page.
700  */
SkipText(FILE * fin,char * name,char * filename,char kind)701 void SkipText( FILE *fin, char *name, char *filename, char kind )
702 {
703     int  c;
704     char lineBuffer[MAX_LINE], *lp;
705 
706     lineBuffer[0] = '+';   /* Sentinal on lineBuffer */
707     while (1) {
708 	lp = lineBuffer + 1;
709 	c  = getc( fin );
710 	if (c == EOF) break;
711 	if (c == ARGUMENT || c == VERBATIM)
712 	    SkipLine( fin );
713 	else if (c == '\n')
714 		;
715 	else {
716 	    if (isspace(c) && c != '\n')
717 		SkipWhite( fin );
718 	    else
719 		*lp++ = c;
720 	    /* Copy to end of line; do NOT include the EOL */
721 	    while ((c = getc( fin )) != EOF && c != '\n')
722 		*lp++ = c;
723 	    lp--;
724 	    while (isspace(*lp)) lp--;
725 	    lp[1] = '\0';    /* Add the trailing null */
726 	    if (lineBuffer[1] == kind && strcmp(lineBuffer+2,"*/") == 0)
727 		break;
728         }
729     }
730 }
731 
SkipToSynopsis(FILE * fin,char kind)732 int SkipToSynopsis( FILE *fin, char kind )
733 {
734     int  c;
735     char lineBuffer[MAX_LINE], *lp;
736 
737     lineBuffer[0] = '+';   /* Sentinal on lineBuffer */
738     while (1) {
739 	lp = lineBuffer + 1;
740 	c  = getc( fin );
741 	if (c == EOF) break;
742 	if (c == ARGUMENT || c == VERBATIM)
743 	    SkipLine( fin );
744 	else if (c == '\n')
745 		;
746 	else {
747 	    if (isspace(c) && c != '\n')
748 		SkipWhite( fin );
749 	    else
750 		*lp++ = c;
751 	    /* Copy to end of line; do NOT include the EOL */
752 	    while ((c = getc( fin )) != EOF && c != '\n')
753 		*lp++ = c;
754 	    lp--;
755 	    while (isspace(*lp)) lp--;
756 	    lp[1] = '\0';    /* Add the trailing null */
757 	    if (lineBuffer[1] == kind && strcmp(lineBuffer+2,"*/") == 0)
758 		break;
759 	    if (lp[0] == ':') {
760 		lp = lineBuffer + 1;
761 		while (isspace(*lp)) lp++;
762 		LowerCase( lp );
763 		if (strcmp( lp, "synopsis:" ) == 0)
764 		    return 1;
765 	    }
766         }
767     }
768     return 0;
769 }
770 
771 /* Find the next space delimited token; put the text into token.
772    The number of leading spaces is kept in nsp.
773    Alpha-numeric tokens are terminated by a non-alphanumeric character
774    (_ is allowed in alpha-numeric tokens) */
FindNextANToken(FILE * fd,char * token,int * nsp)775 int FindNextANToken( FILE *fd, char *token, int *nsp )
776 {
777     int fc, c, Nsp;
778 
779     Nsp = SkipWhite( fd );
780 
781     fc = c = getc( fd );
782     if (fc == EOF) return fc;
783     *token++ = c;
784     if (isalnum(c) || c == '_') {
785 	while ((c = getc( fd )) != EOF) {
786 	    if (c != '\n' && (isalnum(c) || c == '_')) *token++ = c;
787 	    else break;
788 	}
789 	ungetc( (char)c, fd );
790     }
791     *token++ = '\0';
792     *nsp     = Nsp;
793     return fc;
794 }
795 
OutputBuf(FILE ** fout,char * infilename,char * outfilename,FILE * incfd,char * buffer)796 void OutputBuf( FILE **fout, char *infilename, char *outfilename, FILE *incfd,
797 		char *buffer )
798 {
799     char arch[20];
800 
801     if (!*fout) {
802 	*fout = fopen( outfilename, "w" );
803 	if (!*fout) {
804 	    ErrCnt++;
805 	    fprintf( stderr, "Could not open file %s\n", outfilename );
806 	    if (ErrCnt > MAX_ERR) ABORT( "" );
807 	    return;
808 	}
809 	fprintf( *fout, "/* %s */\n", infilename );
810 	if (!AnsiHeader) {
811 	    if (!IfdefFortranName) {
812 		SYGetArchType( arch, 20 );
813 		fprintf( *fout, "/* Fortran interface file for %s */\n", arch );
814 	    }
815 	    else {
816 		fprintf( *fout, "/* Fortran interface file */\n" );
817 	    }
818 	    fprintf( *fout, "\n/*\n\
819 * This file was generated automatically by bfort from the C source\n\
820 * file.  \n */\n" );
821 	    /* Turn on the base debugging */
822 	    if (AddDebugAll)
823 		fprintf( *fout, "#ifndef DEBUG_ALL\n#define DEBUG_ALL\n#endif\n" );
824 	    if (incfd) {
825 		int c;
826 		fseek( incfd, 0L, 0 );
827 		while ((c = getc( incfd )) != EOF)
828 		    putc( (char)c, *fout );
829 	    }
830 	    if (MapPointers) {
831 /* BFS 3/5/96 code modified to support C++ on 64 bit machines */
832 		if (IfdefFortranName) {
833 		    if (AnsiHeader  || AnsiForm) {
834 			fprintf( *fout, "\n#ifdef %s\n\
835 #if defined(__cplusplus)\n\
836 extern \"C\" { \n\
837 #endif \n\
838 extern void *%sToPointer(int);\nextern int %sFromPointer(void *);\n\
839 extern void %sRmPointer(int);\n\
840 #if defined(__cplusplus)\n\
841 } \n\
842 #endif \n\
843 \n#else\n\
844 \n#define %sToPointer(a) (a)\n#define %sFromPointer(a) (int)(a)\
845 \n#define %sRmPointer(a)\n#endif\n\n",
846 				 Pointer64Bits,
847 				 ptrprefix, ptrprefix, ptrprefix,
848 				 ptrprefix, ptrprefix, ptrprefix );
849 		    }
850 		    else {
851 			fprintf( *fout, "\n#ifdef %s\n\
852 #if defined(__cplusplus)\n\
853 extern \"C\" { \n\
854 #endif \n\
855 extern void *%sToPointer();\nextern int %sFromPointer();\n\
856 extern void %sRmPointer();\n\
857 #if defined(__cplusplus)\n\
858 } \n\
859 #endif \n\
860 \n#else\n\
861 \n#define %sToPointer(a) (a)\n#define %sFromPointer(a) (int)(a)\
862 \n#define %sRmPointer(a)\n#endif\n\n",
863 				 Pointer64Bits,
864 				 ptrprefix, ptrprefix, ptrprefix,
865 				 ptrprefix, ptrprefix, ptrprefix );
866 		    }
867 		}
868 		else {
869 		    fprintf( *fout,
870 			     "extern void *%sToPointer(); extern int %sFromPointer();\n",
871 			     ptrprefix, ptrprefix );
872 		}
873 	    }
874 	}
875     }
876     if (buffer)
877 	fputs( buffer, *fout );
878 }
879 
880 
881 /*
882    There are a number of things to watch for.  One is that leading blanks are
883    considered significant; since the text is being formated, we usually dont
884    agree with that.
885  */
OutputMacro(FILE * fin,FILE * fout,char * routine_name,char * filename)886 void OutputMacro( FILE *fin, FILE *fout, char *routine_name, char *filename )
887 {
888     int         is_function;
889     ARG_LIST    args[MAX_ARGS];
890     TYPE_LIST   types[MAX_TYPES];
891     RETURN_TYPE rt;
892     int         nargs, nstrings;
893     int         ntypes;
894     int         has_synopsis;
895     int         done;
896     int         flag2 = 0;
897 
898 /* Check to see if this is a C-only macro */
899     if (GetSubClass() == 'C') {
900 	if (!NoFortMsgs && !NoFortWarnings) {
901 	    fprintf( stderr, "Macro %s(%s) can not be translated into Fortran\n",
902 		     routine_name, CurrentFilename );
903 	}
904 	SkipText( fin, routine_name, filename, MACRO );
905 	return;
906     }
907 
908 /* Skip to the synopsis in the body */
909     has_synopsis = SkipToSynopsis( fin, MACRO );
910 
911     done = 0;
912     if (has_synopsis) {
913 	/* Get the call to the routine, including finding the argument names */
914 	SkipWhite( fin );
915 	/* Process elements of type void * in the following files differently
916 	   from the default */
917 	if ((strcmp( filename, "./nonlin/nlfunc_v.h") == 0) ||
918 	    (strcmp( filename, "./nonlin/nlspmat_v.h") == 0) ||
919 	    (strcmp( filename, "./nonlin/nlsles_v.h") == 0)  ||
920 	    TranslateVoidStar)
921 	    flag2 = 1;
922 	ProcessArgList( fin, fout, filename, &is_function, routine_name,
923 			args, &nargs, &rt, 1, types, &ntypes, flag2 );
924 
925 	if (!AnsiForm) {
926 	    SkipWhite( fin );
927 	    done =
928 		ProcessArgDefs( fin, fout, args, nargs, types, &ntypes, &nstrings, 1,
929 				routine_name, flag2 );
930 	}
931 	else
932 	    done = 1;
933 	PrintBody( fout, is_function, routine_name, nstrings, nargs, args,
934 		   types, &rt );
935     }
936     else {
937 	ErrCnt++;
938 	fprintf( stderr, "%s(%s) has no synopsis section\n",
939 		 routine_name, CurrentFilename );
940 	if (ErrCnt > MAX_ERR) ABORT( "" );
941     }
942 /* finish up the section */
943     if (!done)
944 	SkipText( fin, routine_name, filename, MACRO );
945 }
946 
947 /* Read the arg list and function type */
948 
949 /*
950    This routine reads the function type and name; that is, it processes
951    things like "void *foo" and "void (*foo)()"
952  */
ProcessFunctionType(FILE * fin,FILE * fout,char * filename,int * is_function,char * name,RETURN_TYPE * rt,int flag)953 void ProcessFunctionType( FILE *fin, FILE *fout, char *filename,
954 			  int *is_function, char *name, RETURN_TYPE *rt,
955 			  int flag )
956 {
957     static char rcall[1024];
958     char *p, actname[1024];
959     int  c, i;
960     int  nsp;
961     int  leadingm;
962     int  in_args;
963     int  found_name;
964 
965     SkipWhite( fin );
966     in_args     = 0;
967     p           = rcall;
968     c           = FindNextANToken( fin, p, &nsp );
969 /*
970    We check for routines that return (functions) versus ones that don't
971    by looking for "void".  A special case is functions that return
972    pointers to void; we check for these by looking at the first character
973    of the first token after the void.
974 
975    We also want to defer generating the function type incase we need to
976    replace a pointer ref with an integer.
977    */
978     if (MPIU_Strncpy( rt->name, p, sizeof(rt->name) )) {
979 	ABORT( "Cannot copy return type name" );
980     }
981     rt->num_stars = 0;
982     *is_function          = strcmp( p, "void" );
983 
984     if (OutputImmed) {
985 	for (i=0; i<nsp; i++) putc( ' ', fout );
986     }
987 /* fputs( p, fout ); */
988     p += strlen( p );
989     *p++ = ' ';
990     leadingm = 0;    /* If a newline is encountered before this is one, AND
991 			this is a macro, insert one and exit */
992     found_name = 0;
993     actname[0] = 0;
994     while (1) {
995 	c = FindNextANToken( fin, p, &nsp );
996 	if (c == EOF) {
997 	    ErrCnt++;
998 	    fprintf( stderr, "Unexpected EOF in %s\n", filename );
999 	    if (ErrCnt > MAX_ERR) ABORT( "" );
1000 	    return;
1001 	}
1002 	if (nsp > 0) {
1003 	    if (MPIU_Strnapp( rt->name, " ", sizeof(rt->name) )) {
1004 		ABORT( "Cannot add space to return type name" );
1005 	    }
1006 	}
1007 	if (strcmp( p, name ) != 0 && p[0] != '(') {
1008 	    if (MPIU_Strnapp( rt->name, p, sizeof(rt->name) )) {
1009 		ABORT( "Cannot append name to return type" );
1010 	    }
1011 	}
1012 	if (c == '*') {
1013 	    *is_function = 1;
1014 	    rt->num_stars++;
1015 	}
1016 	if (flag && c == '\n' && leadingm == 0) {
1017 	    if (OutputImmed)
1018 		fputs( "())", fout );
1019 	    break;
1020 	}
1021 	if (c == '\n') leadingm = 1;
1022 	if (c == '(') {
1023 	    if (in_args == 0) {
1024 		/* Output function type and name */
1025 		if (rt->num_stars == 0 || !MapPointers) {
1026 		    if (useFerr && strncmp( rt->name, "int", 3 ) == 0 ) {
1027 			if (OutputImmed)
1028 			    fputs( "void ", fout );
1029 		    }
1030 		    else {
1031 			if (OutputImmed) {
1032 			    fputs( rt->name, fout );
1033 			    fputs( " ", fout );
1034 			}
1035 		    }
1036 		}
1037 		else {
1038 		    if (OutputImmed) {
1039 			fputs( "int ", fout );
1040 		    }
1041 		}
1042 		if (OutputImmed)
1043 		    OutputRoutineName( name, fout );
1044 	    }
1045 	    ungetc( '(', fin );
1046 	    break;
1047 	}
1048 	if (c == ')') {
1049 	    in_args -= 1;
1050 	    if (in_args == 0) {
1051 		break;
1052 	    }
1053 	}
1054 	if (MPIU_Strncpy( actname, p, sizeof(actname) )) {
1055 	    ABORT( "Cannot copy actual name" );
1056 	}
1057 	if (in_args == 0) {
1058 	    if (strcmp( p, name ) == 0) {
1059 		/* Convert to Fortran name.  For now, this just does the
1060 		   lowercase_ version */
1061 		found_name = 1;
1062 	    }
1063 	    /* This test should be postponed until the end (e.g.,
1064 	       struct tm *foo() */
1065 	    /*
1066 	       else {
1067 	       if (p[0] != '*') {
1068 	       Errcnt++;
1069 	       fprintf( stderr, "%s:Did not find matching name: %s != %s\n",
1070 	       filename, p, name );
1071 	       if (ErrCnt > MAX_ERR) ABORT( "" );
1072 	       }
1073 	       }
1074 	       */
1075 	}
1076     }
1077     if (!found_name) {
1078 	ErrCnt++;
1079 	fprintf( stderr, "%s:Did not find routine name (may be untyped): %s \n",
1080 		 filename, name );
1081 	if (ErrCnt > MAX_ERR) ABORT( "" );
1082     }
1083     else if (strcmp( name, actname ) != 0) {
1084 	ErrCnt++;
1085 	fprintf( stderr, "%s:Did not find matching name: %s != %s\n",
1086 		 filename, actname, name );
1087 	if (ErrCnt > MAX_ERR) ABORT( "" );
1088     }
1089 }
1090 
1091 /* We are moving to being able to suppress generating the output until the
1092    argument definitions are read.
1093    flag is 1 for C routines, 0 for macros (I think)  */
ProcessArgList(FILE * fin,FILE * fout,char * filename,int * is_function,char * name,ARG_LIST args[MAX_ARGS],int * Nargs,RETURN_TYPE * rt,int flag,TYPE_LIST * types,int * Ntypes,int flag2)1094 void ProcessArgList( FILE *fin, FILE *fout, char *filename, int *is_function,
1095 		     char *name, ARG_LIST args[MAX_ARGS], int *Nargs,
1096 		     RETURN_TYPE *rt, int flag, TYPE_LIST *types, int *Ntypes,
1097 		     int flag2 )
1098 {
1099     int             c, ntypes;
1100     char            *p;
1101     int             nsp, leadingm;
1102     static char     rcall[1024];
1103     int             nargs, in_args;
1104     TYPE_LIST       *curtype;
1105     int             outparen;
1106 
1107     ProcessFunctionType( fin, fout, filename, is_function, name, rt, flag );
1108 
1109     nargs       = 0;
1110     in_args     = 0;
1111     p           = rcall;
1112 
1113     leadingm = 0;    /* If a newline is encountered before this is one, AND
1114 			this is a macro, insert one and exit */
1115     curtype = (TYPE_LIST *)0;
1116     ntypes  = 0;
1117 /* Get the opening ( */
1118     c = FindNextANToken( fin, p, &nsp );
1119     if (c != '(') {
1120 	ErrCnt++;
1121 	fprintf( stderr, "Expected a (, found %s\n", p );
1122 	if (ErrCnt > MAX_ERR) ABORT( "" );
1123 	return;
1124     }
1125     OutputToken( fout, p, nsp );
1126     while (1) {
1127 	/* First, get the type name.  Note that there might not be one */
1128 	if (AnsiForm) {
1129 	    curtype = &types[ntypes];
1130 	    outparen = ntypes > 0;
1131 	    if ((c = GetTypeName( fin, fout, &types[ntypes], flag, flag2,
1132 			     outparen ))) {
1133 		if (ntypes == 0 && AnsiForm && c == ')') {
1134 		    fprintf( stderr,
1135 		     "Empty argument list in -ansi mode (use (void))\n");
1136 		    /* For this to work, gettypename can't output the last
1137 		       closing paren */
1138 		    if ( useFerr ) {
1139 			fprintf( fout, "int *%s ", errArgNameLocal);
1140 		    }
1141 		}
1142 		if (c != 1) {
1143 		    char cstring[2];
1144 		    cstring[0] = c; cstring[1] = 0;
1145 		    OutputToken( fout, cstring, 0 );
1146 		}
1147 		break;
1148 	    }
1149 	    ntypes++;
1150 	}
1151 	/* Now, get the variable names until the arg terminator.
1152 	   They are of the form [(\*]*name[(\*\[]*
1153 	   */
1154 	if (GetArgName( fin, fout, &args[nargs], curtype, AnsiForm )) {
1155 	    break;
1156 	}
1157 	args[nargs].type = ntypes-1;
1158 	if (curtype && curtype->type_has_star)
1159 	    args[nargs].has_star++;
1160 	if (curtype) {
1161 /* added by BS */
1162 	    if (curtype->implied_star)
1163 		args[nargs].implied_star++;
1164 	    args[nargs].is_native = curtype->is_native;
1165 	}
1166 	if (nargs >= MAX_ARGS) {
1167 	    ErrCnt++;
1168 	    fprintf( stderr, "Too many arguments to function %s\n", name );
1169 	    ABORT( "" );
1170 	}
1171 	nargs++;
1172 	/* Get between-arg character */
1173 	c = FindNextANToken( fin, p, &nsp );
1174 	if (c == '(') {
1175 	    /* Need to skip to corresponding ')' */
1176 	    OutputBalancedString( fin, fout, '(', ')' );
1177 	    c = FindNextANToken( fin, p, &nsp );
1178 	    /* This is a function */
1179 	    args[nargs-1].void_function = 1;
1180 	}
1181 	if (c == ')') {
1182 	    if (OutputImmed) {
1183 		if (useFerr) {
1184 /* added AnsiForm BS Aug 20, 1995 */
1185 		    if (AnsiForm) {
1186 			fprintf( fout, "%sint *%s ",
1187 				 (nargs > 0) ? ", " : "", errArgNameLocal );
1188 		    }
1189 		    else {
1190 			fprintf( fout, "%s%s ",
1191 				 (nargs > 0) ? ", " : "", errArgNameLocal );
1192 		    }
1193 		}
1194 		fputs( ")", fout );
1195 	    }
1196 	    break;
1197 	}
1198 	OutputToken( fout, p, nsp );
1199     }
1200 
1201 /* Handle definitions of the form "type (*Name( args, ... ))()" (this is
1202    function returns pointer to function returning type). */
1203     SkipWhite( fin );
1204     c = getc( fin );
1205     if (c == '(') {
1206 	SkipWhite( fin );
1207 	c = getc(fin);
1208 	if (c == ')')
1209 	    fputs( "()", fout );
1210 	else
1211 	    ungetc( (char)c, fin );
1212     }
1213     else
1214 	ungetc( (char)c, fin );
1215 
1216     if (AnsiForm) {
1217 	/* Handle declaration of form int foo(void) */
1218 	if (ntypes == 1 && nargs == 0 && strcmp("void",types[0].type) == 0) {
1219 	    ntypes = 0;
1220 	}
1221     }
1222     *Nargs  = nargs;
1223     *Ntypes = ntypes;
1224 /* If being called from Fortran, we need to append dummy ints for the strings
1225    passed in.  This requires that we defer to the end of the argument
1226    passing the printing of the function declaration line */
1227 /* for (i=0; i<nstrings; i++) fprintf( fout, ",d%d", i ); */
1228 
1229 }
1230 
1231 /* Read the arg list and function type */
1232 
1233 /* if flag == 1, stop on empty line rather than { */
1234 /* This needs to distinguish between pointers and values, since all
1235    parameters are passed by reference in Fortran.  Just to keep things
1236    lively, there are two ways to indicate a pointer in C:
1237      type *foo;
1238      type foo[];
1239 
1240    Needed to add a change that definitions are terminated by ;, not by \n.
1241 
1242    ANSI version has no args predefined, types separated by comma, and
1243    the same default type (int) as for K&R form.
1244 
1245    Returns 1 if it saw the end of a macro, 0 otherwise (see OutputMacro)
1246  */
ProcessArgDefs(FILE * fin,FILE * fout,ARG_LIST * args,int nargs,TYPE_LIST * types,int * Ntypes,int * Nstrings,int flag,char * name,int flag2)1247 int ProcessArgDefs( FILE *fin, FILE *fout, ARG_LIST *args, int nargs,
1248 		    TYPE_LIST *types, int *Ntypes, int *Nstrings, int flag,
1249 		    char *name, int flag2 )
1250 {
1251     int      c;
1252     char     token[1024];
1253     int      i, nsp, newline, newstmt;
1254     int      in_function;
1255     int      nstrings;
1256     int      ntypes, set_void, void_function;
1257     int      done = 0;         /* set to 1 if ate end-of-definition */
1258     TYPE_LIST *curtype;
1259     ARG_LIST  narg;
1260 
1261     newline		  = 1;
1262     newstmt		  = 1;
1263     if (flag) newline = 0;
1264     nstrings	  = 0;
1265 /* The default type is int */
1266     ntypes		  = 1;
1267     if (MPIU_Strncpy( types[0].type, "int", sizeof(types[0].type) )) {
1268 	ABORT( "Cannot set initial type to int" );
1269     }
1270     in_function	  = 0;
1271     set_void	  = 0;
1272     void_function = 0;
1273 
1274 /* This should really use a better parser.
1275    Types are
1276    [register] [const] [struct] typename [ *( ]* [restrict] varname [(*\[]*
1277    separated by , (ANSI) or ; (K&R), and terminated by
1278    ')' (ANSI) or '{' (K&R)
1279 
1280    A modification is that in K&R form, after a ',', the
1281    [register] [struct] typename is carried forward until a ';'
1282 
1283    The known typenames (and optional [register][const][struct]) are
1284    processed by GetTypeName;
1285  */
1286     while (1) {
1287 	curtype = &types[ntypes];
1288 	if ((done = GetTypeName( fin, fout, &types[ntypes++], flag, flag2, 1 )))
1289 	    break;
1290 	while (1) {
1291 	    if (GetArgName( fin, fout, &narg, curtype, 1 )) break;
1292 	    /* match arg to input argument */
1293 	    for (i=0; i<nargs; i++) {
1294 		if (strcmp( narg.name, args[i].name ) == 0) break;
1295 	    }
1296 	    if (i >= nargs) {
1297 		ErrCnt++;
1298 		fprintf( stderr, "Could not find argument %s\n", narg.name );
1299 		if (ErrCnt > MAX_ERR) ABORT( "" );
1300 	    }
1301 	    args[i]		     = narg;
1302 	    args[i].type	     = ntypes-1;
1303 	    args[i].implied_star     = curtype->implied_star;
1304 	    args[i].is_char	     = curtype->is_char;
1305 	    args[i].is_FILE	     = curtype->is_FILE;
1306 	    args[i].is_native        = curtype->is_native;
1307 	    if (curtype->type_has_star)
1308 		args[i].has_star++;
1309 	    if (args[i].is_char)
1310 		nstrings++;
1311 	    c = FindNextANToken( fin, token, &nsp );
1312 	    OutputToken( fout, token, nsp );
1313 	    if (c == ';') break;
1314 	}
1315 
1316 #ifdef FOO
1317 	/* Handle various argument features */
1318 	if (c == '*')                  has_star++;
1319 	else if (c == '(') {
1320 	    in_function = 1;
1321 	    /* If set_void is activated, set the void function indicator */
1322 	    if (set_void) {
1323 		set_void = 0;
1324 		void_function = 1;
1325             }
1326 	}
1327 	else if (c == ')' && in_function) {
1328 	    is_function = 1;
1329 	}
1330 	else if (c == '\n') {
1331 	    /* New lines have little meaning in declarations.
1332 	       However, they are necessary to handle blanks lines */
1333 	    newline = 1;
1334 	}
1335 	else if (newstmt) {
1336 #endif
1337 #ifdef FOO
1338 	    if (!has_star) {
1339 		/* This makes it look nicer */
1340 		nsp = 0;
1341 		OutputToken( fout, "*", nsp );
1342 	    }
1343 	    if (has_array) OutputToken( fout, "[]", 0 );
1344 #endif
1345 	}
1346 /* Add the final error return definition */
1347 	if (useFerr && OutputImmed) {
1348 	    fprintf(fout, "int *%s;\n", errArgNameLocal);
1349 	}
1350 	*Ntypes   = ntypes;
1351 	*Nstrings = nstrings;
1352 	return done == 2;
1353     }
1354 
1355 /*
1356     Pointer mashing.  There are two kinds of pointer mashing available.
1357     For systems for which a pointer will fit into an int, we simply
1358     use the ints to store the pointers.  In this case, a pointer is
1359     passed to a C routine by using:
1360 
1361     (type *)*(int *)varname
1362 
1363     That is, we convert the varname to an address of an int and deref it.
1364 
1365     On systems with pointers that are longer than ints, we have to do more.
1366 
1367     The first step is to convert pointers to indices on input and output
1368     from the routines.
1369 
1370     The routine __ToPointer converts an index into a pointer.
1371     The routine __FromPointer converts from a pointer to an index
1372     The routine __RmPointer   removes a pointer from the table of pointers
1373 
1374     __FromPointer always allocates a new pointer item.
1375  */
1376 char *ToCPointer( char *type, char *name, int implied_star )
1377 {
1378     static char buf[300];
1379 #if 1
1380     const char *outstr = 0;
1381     if (SYConfigDBLookup("toptr", type, &outstr, toptrList) == 1 && outstr) {
1382 	buf[0] = '\n'; buf[1] = '\t';
1383 	sprintf(&buf[2], outstr, name);
1384 	return buf;
1385     }
1386 #else
1387     if (isMPI2) {
1388 	/* If the type is an MPI type, use the MPI conversion
1389 	   function */
1390 	buf[0] = 0;
1391 	if (strcmp("MPI_Comm",type) == 0) {
1392 	    sprintf( buf, "\n\tMPI_Comm_f2c( *(%s) )", name );
1393 	}
1394 	else if (strcmp( "MPI_Request",type) == 0) {
1395 	    sprintf( buf, "\n\tMPI_Request_f2c( *(%s) )", name );
1396 	}
1397 	else if (strcmp( "MPI_Group", type) == 0) {
1398 	    sprintf( buf, "\n\tMPI_Group_f2c( *(%s) )", name );
1399 	}
1400 	else if (strcmp( "MPI_Op", type ) == 0) {
1401 	    sprintf( buf, "\n\tMPI_Op_f2c( *(%s) )", name );
1402 	}
1403 	else if (strcmp( "MPI_Datatype", type ) == 0) {
1404 	    sprintf( buf, "\n\tMPI_Type_f2c( *(%s) )", name );
1405 	}
1406 	else if (strcmp( "MPI_Win", type ) == 0) {
1407 	    sprintf( buf, "\n\tMPI_Win_f2c( *(%s) )", name );
1408 	}
1409 	else if (strcmp( "MPI_File", type ) == 0) {
1410 	    sprintf( buf, "\n\tMPI_File_f2c( *(%s) )", name );
1411 	}
1412 	if (buf[0]) return buf;
1413     }
1414 #endif
1415     if (MapPointers)
1416 	sprintf( buf, "\n\t(%s%s)%sToPointer( *(int*)(%s) )",
1417 		 type, !implied_star ? "* " : "", ptrprefix, name );
1418     else
1419 	sprintf( buf, "\n\t(%s%s)*((int*)%s)", type, !implied_star ? "* " : "",
1420 		 name );
1421 
1422     return buf;
1423 }
1424 /*
1425    A major question is whether "void *" should be considered the actual
1426    pointer or an address containing the value of the pointer (the usual "int"
1427    trick).
1428 
1429    Since "void *" is used heavily in the communications routines to refer
1430    to any one of the type double*, int*, ..., I'm going to add void * to
1431    the list of types that are not translated
1432  */
1433 void PrintBody( FILE *fout, int is_function, char *name, int nstrings,
1434 		int nargs, ARG_LIST *args, TYPE_LIST *types, RETURN_TYPE *rt )
1435 {
1436     int  i, j;
1437 
1438 /* Known bugs in ansiheader:
1439    Definitions like     void (*fcn)() fail
1440    Multiple indirection (char **argv) fail
1441    */
1442     if (!OutputImmed) {
1443 	/* Output the function definition */
1444 	if (AnsiHeader) fputs( "extern ", fout );
1445 	fputs( rt->name, fout );
1446 	fputs( " ", fout );
1447 	OutputRoutineName( name, fout );
1448 	if (AnsiHeader) fputs( " ANSI_ARGS(", fout );
1449 	fprintf( fout, "(" );
1450 	for (i=0; i<nargs-1; i++) {
1451 	    if (AnsiHeader) {
1452 		fprintf( fout, "%s", types[args[i].type].type );
1453 		if (args[i].has_star > 0) {
1454 		    for (j=0; j<args[i].has_star; j++)
1455 			fputs( "*", fout );
1456 		}
1457 		fputs( ", ", fout );
1458 	    }
1459 	    else
1460 		fprintf( fout, "%s, ", args[i].name );
1461 	}
1462 	if (nargs > 0) {
1463 	    /* Do the last arg, if any */
1464 	    if (AnsiHeader) {
1465 		fprintf( fout, "%s ", types[args[nargs-1].type].type );
1466 		if (args[nargs-1].has_star > 0) {
1467 		    for (j=0; j<args[nargs-1].has_star; j++)
1468 			fputs( "*", fout );
1469 		}
1470 	    }
1471 	    else
1472 		fprintf( fout, "%s ", args[nargs-1].name );
1473 	}
1474 	else {
1475 	    if (AnsiHeader)
1476 		/* A routine with no arguments gets a 'void' as the argument
1477 		   name */
1478 		fputs( "void", fout );
1479 	}
1480 	if (nstrings && !AnsiHeader) {
1481 	    for (i=1; i<nstrings; i++) fprintf( fout, ",d%d", i );
1482 	    /* Undefined variables are int's by default */
1483 	    /* fprintf( fout, "int d0" );
1484 	       for (i=1; i<nstrings; i++) fprintf( fout, ",d%d", i );
1485 	       fputs( ";\n", fout );
1486 	       */
1487 	}
1488 	fprintf( fout, ")" );
1489 	if (AnsiHeader) {
1490 	    /* No more to do */
1491 	    fputs( ");\n", fout );
1492 	    return;
1493 	}
1494 	else
1495 	    fputs( "\n", fout );
1496     }
1497     fputs( "{\n", fout );
1498 /* Look for special-case translations (currently, "FILE") */
1499     for (i=0; i<nargs; i++) {
1500 	if (args[i].is_FILE) {
1501 	    fprintf( fout, "FILE *_fp%d = stdout;\n", i );
1502 	}
1503     }
1504 
1505 /* Generate the routine call with the return */
1506     if (is_function) {
1507 	if (useFerr) {
1508 	    fprintf(fout, "*%s = ", errArgNameLocal);
1509 	}
1510 	else {
1511 	    fputs( "return ", fout );
1512 	    /* May have to convert type */
1513 	    if (MapPointers && rt->num_stars > 0) {
1514 		/* In this case, we return an integer */
1515 		fprintf( fout, "%sFromPointer( (void *)( ", ptrprefix );
1516 	    }
1517 	}
1518     }
1519     fputs( name, fout );
1520     fputs( "(", fout );
1521     for (i=0; i<nargs; i++) {
1522 	if (args[i].is_FILE)
1523 	    fprintf( fout, "_fp%d", i );
1524 	else if (!args[i].is_native && args[i].has_star
1525 		 && !args[i].void_function) {
1526 	    if (args[i].has_star == 1 || !MultipleIndirectAreInts)
1527 		fprintf( fout, "%s",
1528 			 ToCPointer( types[args[i].type].type, args[i].name,
1529 				     args[i].implied_star ) );
1530 	    else {
1531 		if (MultipleIndirectsAreNative) {
1532 		    fprintf( fout, "%s", args[i].name );
1533 		}
1534 		else {
1535 		    fprintf( fout, "(%s ", types[args[i].type].type );
1536 		    if (!args[i].implied_star)
1537 			for (j = 0; j<args[i].has_star; j++) fputs( "*", fout );
1538 		    fprintf( fout, ")*((int *)%s)", args[i].name );
1539 		}
1540 	    }
1541 	}
1542 	else {
1543 	    if (!args[i].has_star)
1544 		fputs( "*", fout );
1545 	    fputs( args[i].name, fout );
1546 	}
1547 	if (i < nargs-1) fputs( ",", fout );
1548     }
1549 /* fputs( rcall, fout ); */
1550 
1551     if (is_function && MapPointers && rt->num_stars > 0 && !useFerr) {
1552 	fprintf( fout, ") )" );
1553     }
1554     fputs( ");\n}\n", fout );
1555 }
1556 
1557 /*
1558  * In support for Fortran 9x/20xx, print a Fortran module interface definition.
1559  *
1560  * These definitions are of the form
1561  * {SUBROUTINE|FUNCTION} name( arg-list )
1562  * arg-decls
1563  * result-type name ! if function
1564  * end {SUBROUTINE|FUNCTION} name
1565  *
1566  * These are within an interface - end interface block, which is itself
1567  * within a module mod-name -- end module
1568  *
1569  * Note that this routine only works with ansi-style definitions
1570  */
1571 static int curCol = 0;
1572 static int maxOutputCol = 72;
1573 static int inComment = 0;
1574 void OutputFortranToken( FILE *fout, int nsp, const char *token )
1575 {
1576     int tokenLen = strlen( token );
1577     int i;
1578 
1579     if (curCol + nsp > maxOutputCol) nsp = 0;
1580     for (i=0; i<nsp; i++) putc( ' ', fout );
1581     curCol += nsp;
1582     if (curCol + tokenLen > maxOutputCol) {
1583 	while (curCol < 72) {
1584 	    putc( ' ', fout );
1585 	    curCol ++;
1586 	}
1587 	/* We continue a comment in a different way */
1588 	if (inComment) {
1589 	    putc( '\n', fout );
1590 	    putc( '!', fout );
1591 	    putc( ' ', fout );
1592 	    curCol = 2;
1593 	}
1594 	else {
1595 	    putc( '&', fout );
1596 	    putc( '\n', fout );
1597 	    for (i=0; i<5; i++) putc( ' ', fout );
1598 	    putc( '&', fout );
1599 	    curCol = 6;
1600 	}
1601     }
1602     if (curCol == 0 && (*token != 'C' || *token != 'c') ) {
1603 	/* Skip past column 6 to support free and fixed format */
1604 	for (i=0; i<6; i++) putc( ' ', fout );
1605 	curCol = 7;
1606     }
1607     fputs( token, fout );
1608     curCol += tokenLen;
1609     if (*token == '\n' ) {
1610 	curCol    = 0;
1611 	inComment = 0;
1612     }
1613     else if (*token == '!') {
1614 	inComment = 1;
1615     }
1616 }
1617 
1618 /* This routine ensures that all arguments are distinct, even when case is
1619    not considered.  Specifically, if both "m" and "M" are argument names,
1620    the "M" argument will be replaced with "M$1" */
1621 void FixupArgNames( int nargs, ARG_LIST *args )
1622 {
1623     int i, j;
1624     char tmpbuf[MAX_LINE];
1625     char *c, *cout;
1626 
1627     for (i=0; i<nargs; i++) {
1628 	int hasUpper = 0;
1629 	/* printf( "Trying to fix %s\n", args[i].name ); */
1630 	/* Produce a lower-case version of the name */
1631 	c    = args[i].name;
1632 	cout = tmpbuf;
1633 	while (*c) {
1634 	    *cout = tolower( *c );
1635 	    if (*cout != *c) hasUpper = 1;
1636 	    c++; cout++;
1637 	}
1638 	*cout = 0;
1639 	if (hasUpper) {
1640 	    /* Compare with the other arguments.  tmpbuf has the
1641 	       lower-case version of the current name. */
1642 	    /* Q: can we just use j<i? */
1643 	    for (j=0; j<nargs; j++) {
1644 		if (j == i) continue;
1645 		c = args[j].name;
1646 		cout = tmpbuf;
1647 		while (*c && *cout) {
1648 		    char mychar = tolower(*c);
1649 		    if (mychar != *cout) break;
1650 		    c++; cout++;
1651 		}
1652 		if (!*c && !*cout) {
1653 		    /* Problem - matched lower case version.  Replace
1654 		       current name with name + Upper */
1655 		    /* printf( "Matched %s to %s\n", args[i].name,
1656 		       args[j].name ); */
1657 		    cout = tmpbuf;
1658 		    while (*cout) cout++;
1659 		    if (cout - tmpbuf > MAX_LINE - 6) {
1660 			fprintf( stderr, "Argument name %s too long\n", tmpbuf );
1661 			ABORT( "" );
1662 		    }
1663 		    *cout++ = 'u';
1664 		    *cout++ = 'p';
1665 		    *cout++ = 'p';
1666 		    *cout++ = 'e';
1667 		    *cout++ = 'r';
1668 		    *cout++ = 0;
1669 		    if (args[i].name) {
1670 			FREE( args[i].name );
1671 		    }
1672 		    args[i].name = (char *)MALLOC( strlen( tmpbuf ) + 1 );
1673 		    if (MPIU_Strncpy( args[i].name, tmpbuf, strlen( tmpbuf ) + 1 )) {
1674 			ABORT( "Cannot replace argument name" );
1675 		    }
1676 		    break;
1677 		}
1678 	    }
1679 	}
1680     }
1681 }
1682 
1683 /*
1684  * Create a Fortran 90 definition (module) for a function
1685  */
1686 void PrintDefinition( FILE *fout, int is_function, char *name, int nstrings,
1687 		      int nargs, ARG_LIST *args, TYPE_LIST *types,
1688 		      RETURN_TYPE *rt )
1689 {
1690     int  i;
1691     char *token = 0;
1692 
1693     /*
1694      * Initial setup.  Fortran is case-insensitive and C is case-sensitive
1695      * Check that the case-insensitive argument names are distinct, and
1696      * if not, replace them with ones that are.  The rule is to
1697      * take a lowercase name and add "$1" to it.  We warn if a variable name
1698      * includes $1 ($ is permitted in Fortran names (check))
1699      */
1700     FixupArgNames( nargs, args );
1701     curCol = 0;
1702     /* Known bugs in ansiheader:
1703        Definitions like     void (*fcn)() fail
1704        Multiple indirection (char **argv) fail
1705     */
1706     /* Output the function definition */
1707     if (useFerr) {
1708 	token = "subroutine";
1709     } else {
1710 	token = is_function ? "function" : "subroutine";
1711     }
1712     OutputFortranToken( fout, 8, token );
1713     OutputFortranToken( fout, 1, name );
1714     OutputFortranToken( fout, 0, "(" );
1715     for (i=0; i<nargs-1; i++) {
1716 	OutputFortranToken( fout, 0, args[i].name );
1717 	OutputFortranToken( fout, 0, ", " );
1718     }
1719     if (nargs > 0) {
1720 	/* Do the last arg, if any */
1721 	OutputFortranToken( fout, 0, args[nargs-1].name );
1722 	OutputFortranToken( fout, 0, " " );
1723     }
1724     if (useFerr) {
1725 	if (nargs > 0) OutputFortranToken( fout, 0, "," );
1726 	OutputFortranToken( fout, 0, errArgNameParm );
1727     }
1728     OutputFortranToken( fout, 0, ")" );
1729     OutputFortranToken( fout, 0, "\n" );
1730 
1731     for (i=0; i<nargs; i++) {
1732 	/* Figure out the corresponding Fortran type */
1733 	if (types[args[i].type].is_mpi) {
1734 	    OutputFortranToken( fout, 7, "integer" );
1735 	}
1736 	else if (args[i].void_function) {
1737 	    OutputFortranToken( fout, 7, "external" );
1738 	}
1739 	else {
1740 	    OutputFortranToken( fout, 7,
1741 				ArgToFortran( types[args[i].type].type ) );
1742 	}
1743 	OutputFortranToken( fout, 1, args[i].name );
1744 	if (args[i].has_array && !args[i].void_function) {
1745 	    OutputFortranToken( fout, 1, "(*)" );
1746 	}
1747 	OutputFortranToken( fout, 1, "!" );
1748 	if (args[i].void_function) {
1749 	    OutputFortranToken( fout, 1, "void function pointer" );
1750 	}
1751 	else {
1752 	    OutputFortranToken( fout, 1, types[args[i].type].type );
1753 	}
1754 	OutputFortranToken( fout, 0, "\n" );
1755 # if 0
1756 	if (args[i].is_FILE) {
1757 	    OutputFortranToken( fout, 0, "integer" );
1758 	    OutputFortranToken( fout, 1, args[i].name );
1759 	}
1760 	else if (!args[i].is_native && args[i].has_star
1761 		 && !args[i].void_function) {
1762 	    if (args[i].has_star == 1 || !MultipleIndirectAreInts)
1763 		OutputFortranToken( fout, 0,
1764 			 ToCPointer( types[args[i].type].type, args[i].name,
1765 				     args[i].implied_star ) );
1766 	    else {
1767 		if (MultipleIndirectsAreNative) {
1768 		    OutputFortranToken( fout, 0, args[i].name );
1769 		}
1770 		else {
1771 		    OutputFortranToken( fout, 0, "(" );
1772 		    OutputFortranToken( fout, 0, types[args[i].type].type );
1773 		    OutputFortranToken( fout, 0, " " );
1774 		    if (!args[i].implied_star)
1775 			for (j = 0; j<args[i].has_star; j++) {
1776 			    OutputFortranToken( fout, 0, "*" );
1777 			}
1778 		    OutputFortranToken( fout, 0, ")*((int *)" );
1779 		    OutputFortranToken( fout, 0, args[i].name );
1780 		    OutputFortranToken( fout, 0, ")" );
1781 		}
1782 	    }
1783 	}
1784 	else {
1785 	    /* if args[i].has_star, the argument often has intent OUT
1786 	       or INOUT */
1787 	    OutputFortranToken( fout, 0, args[i].name );
1788 	}
1789 #endif
1790     }
1791 
1792     /* Add a "decl/result(name) for functions */
1793     if (useFerr) {
1794 	OutputFortranToken( fout, 7, "integer" );
1795 	OutputFortranToken( fout, 1, errArgNameParm);
1796     } else if (is_function) {
1797 	OutputFortranToken( fout, 7, ArgToFortran( rt->name ) );
1798 	OutputFortranToken( fout, 1, name );
1799 	OutputFortranToken( fout, 1, "!" );
1800 	OutputFortranToken( fout, 1, rt->name );
1801     }
1802     OutputFortranToken( fout, 0, "\n" );
1803     OutputFortranToken( fout, 7, "end" );
1804 
1805     if (useFerr) {
1806 	token = "subroutine";
1807     } else {
1808 	token = is_function ? "function" : "subroutine";
1809     }
1810     OutputFortranToken( fout, 1, token );
1811     OutputFortranToken( fout, 0, "\n" );
1812 }
1813 
1814 int NameHasUnderscore( char *p )
1815 {
1816     while (*p)
1817 	if (*p++ == '_') return 1;
1818     return 0;
1819 }
1820 
1821 void OutputRoutineName( char *name, FILE *fout )
1822 {
1823     char buf[256], *p;
1824     int  ln;
1825 
1826     p = buf;
1827     if (MPIU_Strncpy( buf, name, sizeof(buf) )) {
1828 	ABORT( "Cannot copy name to buf" );
1829     }
1830     if (!AnsiHeader) {
1831 	if (IfdefFortranName) {
1832 	    LowerCase( p );
1833 	    ln = strlen( p );
1834 	    p[ln] = '_';
1835 	    p[ln+1] = 0;
1836 	}
1837 	else {
1838 #if defined(FORTRANCAPS)
1839 	    UpperCase( p );
1840 #elif defined(FORTRANUNDERSCORE)
1841 	    LowerCase( p );
1842 	    ln	= strlen( p );
1843 	    p[ln]	= '_';
1844 	    p[ln+1]	= 0;
1845 #elif defined(FORTRANDOUBLEUNDERSCORE)
1846 	    LowerCase( p );
1847 	    ln	= strlen( p );
1848 	    if (NameHasUnderscore( p )) {
1849 		p[ln]	= '_';
1850 		p[ln+1]	= '_';
1851 		p[ln+2]	= 0;
1852 	    }
1853 	    else {
1854 		p[ln]	= '_';
1855 		p[ln+1]	= 0;
1856 	    }
1857 #else
1858 	    LowerCase( p );
1859 #endif
1860 	}
1861     }
1862     fputs( buf, fout );
1863 }
1864 
1865 void OutputUniversalName( FILE *fout, char *routine )
1866 {
1867     char basename[MAX_ROUTINE_NAME], capsname[MAX_ROUTINE_NAME],
1868 	nouscorename[MAX_ROUTINE_NAME];
1869     if (MPIU_Strncpy( basename, routine, sizeof(basename) )) {
1870 	ABORT( "Cannot set basename" );
1871     }
1872     LowerCase( basename );
1873     if (MPIU_Strnapp( basename, "_", sizeof(basename) )) {
1874 	ABORT( "Cannot append underscore to basename" );
1875     }
1876     if (MPIU_Strncpy( capsname, routine, sizeof(capsname) )) {
1877 	ABORT( "Cannot set capsname" );
1878     }
1879     UpperCase( capsname );
1880     if (MPIU_Strncpy( nouscorename, routine, sizeof(nouscorename) )) {
1881 	ABORT( "Cannot set nouscorename" );
1882     }
1883     LowerCase( nouscorename );
1884     if (isMPI && DoProfileNames) {
1885 	if (NameHasUnderscore(nouscorename)) {
1886 	    fprintf( fout, "\
1887 #ifdef %s\n\
1888 #ifdef %s\n\
1889 #define %s P%s\n\
1890 #elif defined(%s)\n\
1891 #define %s p%s_\n\
1892 #elif !defined(%s)\n\
1893 #define %s p%s\n\
1894 #else\n\
1895 #define %s p%s\n\
1896 #endif\n\
1897 #else\n\
1898 #ifdef %s\n\
1899 #define %s %s\n\
1900 #elif defined(%s)\n\
1901 #define %s %s_\n\
1902 #elif !defined(%s)\n\
1903 #define %s %s\n\
1904 #endif\n\
1905 #endif\n\n", BuildProfiling,
1906 	     FortranCaps, basename, capsname,
1907 	     FortranDblUscore, basename, basename,
1908 	     FortranUscore, basename, nouscorename,
1909 	     basename, basename,
1910 
1911 	     FortranCaps, basename, capsname,
1912 	     FortranDblUscore, basename, basename,
1913 	     FortranUscore, basename, nouscorename );
1914 	}
1915     else {
1916 	fprintf( fout, "\
1917 #ifdef %s\n\
1918 #ifdef %s\n\
1919 #define %s P%s\n\
1920 #elif !defined(%s) && !defined(%s)\n\
1921 #define %s p%s\n\
1922 #else\n\
1923 #define %s p%s\n\
1924 #endif\n\
1925 #else\n\
1926 #ifdef %s\n\
1927 #define %s %s\n\
1928 #elif !defined(%s) && !defined(%s)\n\
1929 #define %s %s\n\
1930 #endif\n\
1931 #endif\n\n", BuildProfiling,
1932 	     FortranCaps, basename, capsname,
1933 	     FortranUscore, FortranDblUscore, basename, nouscorename,
1934 	     basename, basename,
1935 
1936 	     FortranCaps, basename, capsname,
1937 	     FortranUscore, FortranDblUscore, basename, nouscorename );
1938 	}
1939     }
1940 else {
1941     if (NameHasUnderscore(nouscorename)) {
1942 	fprintf( fout, "\
1943 #ifdef %s\n\
1944 #define %s %s\n\
1945 #elif defined(%s)\n\
1946 #define %s %s_\n\
1947 #elif !defined(%s)\n\
1948 #define %s %s\n\
1949 #endif\n",  FortranCaps, basename, capsname,
1950 	    FortranDblUscore, basename, basename,
1951 	    FortranUscore, basename, nouscorename );
1952 	}
1953     else {
1954 	fprintf( fout, "\
1955 #ifdef %s\n\
1956 #define %s %s\n\
1957 #elif !defined(%s) && !defined(%s)\n\
1958 #define %s %s\n\
1959 #endif\n",  FortranCaps, basename, capsname,
1960 	    FortranUscore, FortranDblUscore, basename, nouscorename );
1961 	}
1962     }
1963 }
1964 
1965 /*
1966    Read the type name.  Handles the known types and user-defined types
1967 
1968    Special case (void) must not generate output IF useFerr is set.
1969 
1970    Return non-zero if a non-type name is encountered.
1971 
1972    Activate set_void only for the files specified by flag2
1973 
1974    The flag outparen is true if paren characters should be output;
1975    false otherwise.  If outparen is false, the character will be returned.
1976    Effective only if AnsiForm is true.
1977 
1978  */
1979 int GetTypeName( FILE *fin, FILE *fout, TYPE_LIST *type, int is_macro,
1980 		 int flag2, int outparen )
1981 {
1982     int             c, nsp;
1983     char            token[1024];
1984     char            *typename = type->type;
1985     int             last_was_newline = 0;
1986     int             typenamelen = sizeof(type->type);
1987 
1988     typename[0]	        = 0;
1989     type->is_char       = 0;
1990     type->is_native     = 0;
1991     type->is_FILE       = 0;
1992     type->implied_star  = 0;
1993     type->type_has_star = 0;
1994     type->is_void       = 0;
1995     type->is_mpi        = 0;
1996 
1997     DBG("Looking for type...\n");
1998     /* Skip register */
1999     SkipWhite( fin );
2000     c = FindNextANToken( fin, token, &nsp );
2001     while (c != EOF && c == '\n') {
2002 	/* Macro typedefs end with a blank line */
2003 	if (is_macro && last_was_newline) return 1;
2004 	last_was_newline = 1;
2005 	OutputToken( fout, token, nsp );
2006 	c = FindNextANToken( fin, token, &nsp );
2007     }
2008     /* Now we check for end of type definitions.  This is either a
2009        { in K&R, ) in ANSI, or M * / in a Macro defn */
2010     if (c == EOF) return 1;
2011     if (c == '{') {
2012 	/* We don't output the initial brace here (see printbody) */
2013 	return 1;
2014     }
2015     if (AnsiForm && (c == '(' || c == ')')) {
2016 	if (outparen)
2017 	    OutputToken( fout, token, nsp );
2018 	else
2019 	    return c;
2020 	return 1;
2021     }
2022     /* The macro form should stop at a newline as well */
2023     if (is_macro && c == MACRO) {
2024 	DBG("Checking for macro\n");
2025 	c = getc( fin );
2026 	if (c == '*') {
2027 	    c = getc( fin );
2028 	    if (c == '/') {
2029 		DBG("Found end of macro defn\n");
2030 		return 2;
2031 	    }
2032 	    else {
2033 		/* This won't work on all systems (some only allow 1
2034 		   pushback). */
2035 		ungetc( '*', fin );
2036 		ungetc( (char)c, fin );
2037 	    }
2038 	}
2039 	else {
2040 	    ungetc( (char)c, fin );
2041 	}
2042     }
2043 
2044     /* Ignore qualifiers register/volatile/const */
2045     if (strcmp( token, "register" ) == 0) {
2046 	c = FindNextANToken( fin, token, &nsp );
2047 	if (c == EOF || c == '{' || (AnsiForm && c == '(')) return 1;
2048     }
2049 
2050     if (strcmp( token, "volatile" ) == 0) {
2051 	c = FindNextANToken( fin, token, &nsp );
2052 	if (c == EOF || c == '{' || (AnsiForm && c == '(')) return 1;
2053     }
2054 
2055     if (strcmp( token, "const" ) == 0) {
2056 	c = FindNextANToken( fin, token, &nsp );
2057 	if (c == EOF || c == '{' || (AnsiForm && c == '(')) return 1;
2058     }
2059 
2060     /* Read type declaration: struct name or [ unsigned ] type */
2061     if (strcmp( token, "struct" ) == 0) {
2062 	if (MPIU_Strnapp( typename, token, typenamelen )) {
2063 	    ABORT( "Cannot append token to typename" );
2064 	}
2065 	if (MPIU_Strnapp( typename, " ", typenamelen) ) {
2066 	    ABORT( "Cannot append space to typename" );
2067 	}
2068 	OutputToken( fout, token, nsp );
2069 	c = FindNextANToken( fin, token, &nsp );
2070 	if (MPIU_Strnapp( typename, token, typenamelen )) {
2071 	    ABORT( "Cannot append token to typename" );
2072 	}
2073     }
2074     else {
2075 	if (strcmp( token, "unsigned" ) == 0) {
2076 	    if (MPIU_Strnapp( typename, token, typenamelen )) {
2077 		ABORT( "Cannot append unsigned to typename" );
2078 	    }
2079 	    if (MPIU_Strnapp( typename, " ", typenamelen )) {
2080 		ABORT( "Cannot append space to typename" );
2081 	    }
2082 	    OutputToken( fout, token, nsp );
2083 	    c = FindNextANToken( fin, token, &nsp );
2084 	}
2085 	if (MPIU_Strnapp( typename, token, typenamelen )) {
2086 	    ABORT( "Cannot append token to typename" );
2087 	}
2088 	/* Look for known names */
2089 	if (strcmp( token, "char" ) == 0) type->is_char = 1;
2090 	if (strcmp( token, "FILE" ) == 0) type->is_FILE = 1;
2091 	/* FIXME: We should put these names in an array, and provide
2092 	   a way to add to that array from a configuration file,
2093 	   to make it easier to customize and extend this code */
2094 	/* Note that we might want special processing for short and long */
2095 	/* Some of these are NOT C types (complex, BCArrayPart)! */
2096 #if 1
2097 	if (SYConfigDBLookup("native", token, NULL, nativeList) == 1) {
2098 	    type->is_native = 1;
2099 	}
2100 #else
2101 	if (
2102 	    strcmp( token, "double" ) == 0 ||
2103 	    strcmp( token, "int"    ) == 0 ||
2104 	    strcmp( token, "short"  ) == 0 ||
2105 	    strcmp( token, "long"   ) == 0 ||
2106 	    strcmp( token, "size_t" ) == 0 ||
2107 	    strcmp( token, "float"  ) == 0 ||
2108 	    strcmp( token, "char"   ) == 0 ||
2109 	    strcmp( token, "complex") == 0 ||
2110 	    strcmp( token, "dcomplex")== 0 ||
2111 	    strcmp( token, "MPI_Status") == 0 ||
2112 	    strcmp( token, "PetscScalar")== 0 ||
2113 	    strcmp( token, "PetscReal")  == 0 ||
2114 	    strcmp( token, "PetscTruth") == 0 ||
2115 	    strcmp( token, "PetscSizeT") == 0 ||
2116 	    strcmp( token, "MatStructure") == 0 ||
2117 	    strcmp( token, "KSPConvergedReason") == 0 ||
2118 	    strcmp( token, "BCArrayPart") == 0 ||
2119 	    strcmp( token, "PetscLogDouble") == 0 ||
2120 	    strcmp( token, "PetscInt") == 0 ||
2121 	    strcmp( token, "SNESConvergedReason") == 0 ||
2122 	    strcmp( token, "PetscMPIInt") == 0 ||
2123 	    strcmp( token, "PetscErrorCode") == 0 ||
2124 	    strcmp( token, "PetscCookie") == 0 ||
2125 	    strcmp( token, "PetscEvent") == 0 ||
2126 	    strcmp( token, "PetscBLASInt") == 0 ||
2127 	    strcmp( token, "ISColoringValue") == 0 ||
2128 	    strcmp( token, "MatReal") == 0 ||
2129 	    strcmp( token, "PetscSysInt") == 0 ||
2130 	    /* some structures - that are like arrays */
2131 	    strcmp(token,"MatInfo") == 0 ||
2132 	    strcmp(token,"MatStencil") == 0 ||
2133 	    strcmp(token,"DALocalInfo") == 0 ||
2134 	    strcmp(token,"MatFactorInfo") == 0 ||
2135 	    0)
2136 	    type->is_native = 1;
2137 #endif
2138 	/* PETSc types that are implicitly pointers are specified here */
2139 	/* This really needs to take the types from a file, so that
2140 	   it can be configured for each package.  See the search code in
2141 	   info2rtf (but do a better job of it) */
2142 #if 1
2143 	if (SYConfigDBLookup("nativeptr", token, NULL, nativePtrList) == 1) {
2144 	    type->type_has_star = 1;
2145 	    type->implied_star  = 1;
2146 	}
2147 #else
2148 	if (
2149 	    strcmp(token,"AO") == 0 ||
2150 	    strcmp(token,"AOData") == 0 ||
2151 	    strcmp(token,"AOData2dGrid") == 0 ||
2152 	    strcmp(token,"ClassPerfLog") == 0 ||
2153 	    strcmp(token,"ClassRegLog") == 0 ||
2154 	    strcmp(token,"DA") == 0 ||
2155 	    strcmp(token,"DM") == 0 ||
2156 	    strcmp(token,"DMMG") == 0 ||
2157 	    strcmp(token,"EventPerfLog") == 0 ||
2158 	    strcmp(token,"EventRegLog") == 0 ||
2159 	    strcmp(token,"IntStack") == 0 ||
2160 	    strcmp(token,"IS") == 0 ||
2161 	    strcmp(token,"ISColoring") == 0 ||
2162 	    strcmp(token,"ISLocalToGlobalMapping") == 0 ||
2163             strcmp(token,"Characteristic") == 0 ||
2164 	    strcmp(token,"KSP") == 0 ||
2165 	    strcmp(token,"Mat") == 0 ||
2166 	    strcmp(token,"MatFDColoring") == 0 ||
2167 	    strcmp(token,"MatNullSpace") == 0 ||
2168 	    strcmp(token,"MatPartitioning") == 0 ||
2169 	    strcmp(token,"MatSNESMFCtx") == 0 ||
2170 	    strcmp(token,"PC") == 0 ||
2171 	    strcmp(token,"PetscADICFunction") == 0 ||
2172 	    strcmp(token,"PetscBag") == 0 ||
2173 	    strcmp(token,"PetscBagItem") == 0 ||
2174 	    strcmp(token,"PetscDLLibraryList") == 0 ||
2175 	    strcmp(token,"PetscDraw") == 0 ||
2176 	    strcmp(token,"PetscDrawAxis") == 0 ||
2177 	    strcmp(token,"PetscDrawHG") == 0 ||
2178 	    strcmp(token,"PetscDrawLG") == 0 ||
2179 	    strcmp(token,"PetscDrawSP") == 0 ||
2180 	    strcmp(token,"PetscFList") == 0 ||
2181 	    strcmp(token,"PetscMap") == 0 ||
2182 	    strcmp(token,"PetscMatlabEngine") == 0 ||
2183 	    strcmp(token,"PetscObject") == 0 ||
2184 	    strcmp(token,"PetscContainer") == 0 ||
2185 	    strcmp(token,"PetscOList") == 0 ||
2186 	    strcmp(token,"PetscRandom") == 0 ||
2187 	    strcmp(token,"PetscTable") == 0 ||
2188 	    strcmp(token,"PetscViewer") == 0 ||
2189 	    strcmp(token,"PetscViewers") == 0 ||
2190 	    strcmp(token,"PF") == 0 ||
2191 	    strcmp(token,"SDA") == 0 ||
2192 	    strcmp(token,"SNES") == 0 ||
2193 	    strcmp(token,"StageLog") == 0 ||
2194 	    strcmp(token,"TS") == 0 ||
2195 	    strcmp(token,"Vec") == 0 ||
2196 	    strcmp(token,"VecPack") == 0 ||
2197 	    strcmp(token,"Vecs") == 0 ||
2198 	    strcmp(token,"VecScatter") == 0 ||
2199 	    /* the following are old stuff - might be requird for older versions
2200 	       of PETSc */
2201 	    strcmp(token,"PetscObjectContainer") == 0 ||
2202 	    strcmp(token,"DF") == 0 ||
2203 	    strcmp(token,"Discretization") == 0 ||
2204 	    strcmp(token,"Draw") == 0 ||
2205 	    strcmp(token,"DrawAxis") == 0 ||
2206 	    strcmp(token,"DrawLG") == 0 ||
2207 	    strcmp(token,"ElementMat") == 0 ||
2208 	    strcmp(token,"ElementVec") == 0 ||
2209 	    strcmp(token,"FieldClassMap") == 0 ||
2210 	    strcmp(token,"GMat") == 0 ||
2211 	    strcmp(token,"Grid") == 0 ||
2212 	    strcmp(token,"GSNES") == 0 ||
2213 	    strcmp(token,"GTS") == 0 ||
2214 	    strcmp(token,"GVec") == 0 ||
2215 	    strcmp(token,"Mesh") == 0 ||
2216 	    strcmp(token,"Partition") == 0 ||
2217 	    strcmp(token,"PetscDrawMesh") == 0 ||
2218 	    strcmp(token,"SLES") == 0 ||
2219 	    strcmp(token,"Stencil") == 0 ||
2220 	    strcmp(token,"VarOrdering") == 0 ||
2221 	    strcmp(token,"Viewer") == 0 ||
2222 	    strcmp(token,"XBWindow") == 0 ||
2223 	    0 )  {
2224 	    type->type_has_star = 1;
2225 	    type->implied_star  = 1;
2226 	}
2227 #endif
2228 
2229 	/* This should be an "mpi defs file" rather than just -mpi */
2230 	if (isMPI) {
2231 	    /* Some things need to be considered ints in the declarations.
2232 	       That is, these are "implicit" pointer objects; often they
2233 	       are pointers to be returned from the calling routine.
2234 	       These tests set these up as being pointer objects
2235 	       In many recent implementations, they are now ints.
2236 	       There are also the MPI-2 functions for converting, which
2237 	       we should use (actually, we should have a table that
2238 	       we can read in).
2239 	    */
2240 	    if (strcmp( token, "MPI_Comm" ) == 0       ||
2241 		strcmp( token, "MPI_Request" ) == 0    ||
2242 		strcmp( token, "MPI_Group" ) == 0      ||
2243 		strcmp( token, "MPI_Op" ) == 0         ||
2244 		strcmp( token, "MPI_Uop" ) == 0        ||
2245 		strcmp( token, "MPI_File" ) == 0       ||
2246 		strcmp( token, "MPI_Win"  ) == 0       ||
2247 		strcmp( token, "MPI_Datatype" ) == 0   ||
2248 		strcmp( token, "MPI_Errhandler" ) == 0 ||
2249 		strcmp( token, "MPI_Info" ) == 0       ||
2250 		0) {
2251 		type->is_mpi = 1;
2252 		type->type_has_star = 1;
2253 		type->implied_star  = 1;
2254 	    }
2255 #if 0
2256 	    if (strcmp( token, "MPI_Aint" ) == 0) {
2257 		/* For most systems, MPI_Aint is just long */
2258 		type->type_has_star = 0;
2259 		type->implied_star  = 0;
2260 		type->is_native     = 1;
2261 	    }
2262 	    if (strcmp( token, "MPI_Offset" ) == 0) {
2263 		/* For most systems, MPI_Offset is long long */
2264 		type->type_has_star = 0;
2265 		type->implied_star  = 0;
2266 		type->is_native     = 1;
2267 	    }
2268 #endif
2269 	}
2270 	if (strcmp( token, "void"   ) == 0) {
2271 	    /* Activate set_void only for the files specified by flag2 */
2272 	    if (!flag2) type->is_native = 1;
2273 	    else type->is_void = 1;
2274 	}
2275     }
2276     DBG2("Found type %s\n",token);
2277     if (AnsiForm && useFerr && strcmp( token, "void") == 0) {
2278 	/* Special case for (void) when we replace with an argument */
2279 	while ( (c = SYTxtGetChar( fin )) != EOF && isspace(c)) ;
2280 	ungetc( c, fin );
2281 	if (c == ')') return 0;
2282     }
2283     if (type->is_mpi && isMPI2) {
2284 	OutputToken( fout, "MPI_Fint *", nsp );
2285     }
2286     else {
2287 	OutputToken( fout, token, nsp );
2288     }
2289     return 0;
2290 }
2291 
2292 /*
2293    Read an argument.  If it is not a pointer type, add the "*" to the
2294    definition.
2295  */
2296 int GetArgName( FILE *fin, FILE *fout, ARG_LIST *arg, TYPE_LIST *type,
2297 		int has_extra_chars )
2298 {
2299     int c, nsp, nsp1, nparen, nbrack, nstar;
2300     char *p, token[1024];
2301 
2302     DBG("Looking for arg...\n")
2303 /* This should really use a better parser.
2304    Names are
2305    [ *( ]* [restrict] varname [(*\[]*
2306    separated by , (ANSI) or ; (K&R), and terminated by
2307    ')' (ANSI) or '{' (K&R)
2308 
2309    A modification is that in K&R form, after a ',', the
2310    [register] [struct] typename is carried forward until a ';'
2311 
2312    The known typenames (and optional [register][const][struct] are
2313    processed by GetTypeName;
2314 
2315    If the type is NOT a pointer, we must put a '*' in front of it (since
2316    Fortran always passes pointers).
2317    */
2318     nparen = 0;
2319     nbrack = 0;
2320     nstar  = 0;
2321 /* Many of these fields are set from the base type */
2322     arg->has_star      = 0;
2323     arg->is_char       = 0;
2324     arg->is_native     = 0;
2325     arg->has_array     = 0;
2326     arg->is_FILE       = 0;
2327     arg->void_function = 0;
2328     arg->implied_star  = 0;
2329     arg->name	       = 0;
2330 
2331     p = token;
2332     c = FindNextANToken( fin, p, &nsp );
2333     while (c != EOF && c == '\n') {
2334 	OutputToken( fout, token, nsp );
2335 	c = FindNextANToken( fin, token, &nsp );
2336     }
2337     if (c == ')') {
2338 	/* No argument to get (while reading function declaration)
2339 	   (may be (void) or () in ANSI) */
2340 	if (useFerr) {
2341 	    if (AnsiForm) {
2342 		fprintf( fout, "int *%s ", errArgNameLocal );
2343 	    }
2344 	    else {
2345 		fprintf( fout, "%s ", errArgNameLocal );
2346 	    }
2347 	}
2348 	OutputToken( fout, token, nsp );
2349 	return 1;
2350     }
2351 /* We don't want to output the token when we reach the name incase
2352    we need to generate a "*" for it */
2353     while (c != EOF) {
2354 	if (strcmp( p, "restrict" ) == 0) {
2355 	    c = FindNextANToken( fin, p, &nsp );
2356 	    continue;
2357 	}
2358 	if (c == '(')
2359 	    nparen++;
2360 	else if (c == '*')
2361 	    nstar++;
2362 	else if (c == ')')
2363 	    nparen--;
2364 	else
2365 	    break;
2366 	OutputToken( fout, p, nsp );
2367 	c = FindNextANToken( fin, p, &nsp );
2368     }
2369 
2370     /* Current token is name */
2371     arg->has_star = (nstar > 0);
2372     arg->name     = (char *)MALLOC( strlen(p) + 1 );
2373     if (MPIU_Strncpy( arg->name, p, strlen(p) + 1) ) {
2374 	ABORT( "Cannot set argument name" );
2375     }
2376 
2377     /* We can't output the name just yet, because if it is
2378        int foo[], we don't want to generate int *foo[].  As a short cut,
2379        we could eliminate the first [] if we've already output a *
2380      */
2381 /* if (type && (type->is_native && !type->is_char && !arg->has_star)) { */
2382 /*
2383    We use "type" to determine if we should generate any special "*"s,
2384    for example, in the declaration.
2385  */
2386 
2387 /* Read rest of definition if necessary.  May need to read () or [] */
2388 /* In ANSI form, it needs to skip (....) where this is part of a
2389    function declaration (ie., void (f)(int,char)).  Note that in this
2390    case, we need to peek at the next character to see if it is a (.
2391    Eventually, we'll want to use this information to generate automatic
2392    stubs for the Fortran versions of the routines.
2393 
2394    Note that the next token should be a single character except when scanning
2395    tokens that we want to process (that is, any token to be pushed back
2396    should be a single character).
2397    */
2398     /* Peak at the next character */
2399     c = FindNextANToken( fin, p, &nsp1 );
2400 
2401     if (type && !arg->has_star && !type->implied_star &&
2402 	!type->is_mpi && c != '[') {
2403 	if (nsp == 0) nsp++;
2404 	OutputToken( fout, "*", nsp );
2405 	nsp = 0;
2406     }
2407     if (nstar > 0) {
2408 	if (!NoFortMsgs && /* !is_function &&  */
2409 	    nstar > type->implied_star + 1) {
2410 	    fprintf( stderr,
2411 		     "%s(%s) has multiple indirection for %s\n",
2412 		     "routine"/*name*/, CurrentFilename, arg->name );
2413 	}
2414 	if (!MultipleIndirectsAreNative) arg->is_native = 0;
2415     }
2416 
2417     /* Here we output the variable name, which has been saved in arg->name */
2418     OutputToken( fout, arg->name, nsp );
2419 
2420     /* Now, get the value from the peak above */
2421     nsp = nsp1;
2422     while (has_extra_chars && (c == '(' || (nparen > 0 && c == ')') || c == '[')) {
2423 	OutputToken( fout, p, nsp );
2424 	if (c == '(') { OutputBalancedString( fin, fout, '(', ')' );
2425 	arg->void_function = 1; }
2426 	else if (c == ')') nparen--;
2427 	else if (c == '[') { OutputBalancedString( fin, fout, '[', ']' );
2428 	arg->has_array = 1; arg->has_star++; }
2429 	else if (c == ']') nbrack--;
2430 	else if (c == '*') ;
2431 	else
2432 	    break;
2433 	c = FindNextANToken( fin, p, &nsp );
2434     }
2435     DBG2("Found arg %s\n",arg->name)
2436 /* Really need to unget entire token */
2437 	if (strlen(p) > 1) {
2438 	    ErrCnt++;
2439 	    fprintf( stderr, "Unexpected token (%s) while reading argument name\n",p);
2440 	    if (ErrCnt > MAX_ERR) ABORT( "" );
2441 	}
2442     ungetc( (char)c, fin );
2443     return 0;
2444 }
2445 
2446 /* Output a balanced string.  The first character (cs) has been read */
2447 void OutputBalancedString( FILE *fin, FILE *fout, int cs, int ce )
2448 {
2449     int c, bcount;
2450     bcount = 1;
2451     while (bcount) {
2452 	c = getc( fin );
2453 	if (c == cs) bcount++;
2454 	else if (c == ce) bcount--;
2455 	putc( (char)c, fout );
2456     }
2457 }
2458 
2459 void DoBfortHelp( char *pgm )
2460 {
2461 fprintf( stderr, "%s - write a Fortran interface to C routines with\n",
2462 	 pgm );
2463 fprintf( stderr, "routines documented in the `doctext' format\n" );
2464 fprintf( stderr, "Optional arguments:\n" );
2465 fprintf( stderr, "\
2466 filenames - Names the files from which lint definitions are to be extracted\n\
2467 -nomsgs   - Do not generate messages for routines that can not be converted\n\
2468             to Fortran.\n\
2469 -nofort   - Generate messages for all routines/macros without a Fortran\n\
2470             counterpart.\n\
2471 -dir name - Directory for output file\n\
2472 -I name   - file that contains common includes\n\
2473 -mapptr   - translate pointers to integer indices\n\
2474             The macro used to determine whether pointers are 64 bits can be\n\
2475             changed with\n\
2476 \t-ptr64 name\tReplace POINTER_64_BITS\n\
2477 -ptrprefix prefix - Prepend this name to the routines to map pointers\n" );
2478 fprintf( stderr, "\
2479 -anyname  - generate Fortran names for a variety of systems\n\
2480             The macros used to select the form can be set with\n\
2481 \t-fcaps name\tReplace FORTRANCAPS\n\
2482 \t-fuscore name\tReplace FORTRANUNDERSCORE\n\
2483 \t-fduscore name\tReplace FORTRANDOUBLEUNDERSCORE\n\
2484 -ferr     - Fortran versions return the value of the routine as the last\n\
2485             argument (an integer).  This is used in MPI and is a not\n\
2486             uncommon approach for handling error returns.\n\
2487 -mpi      - Handle MPI datatypes (some things are pointers by definition)\n\
2488             The macro used to determine whether the MPI profiling version\n\
2489             is being built can be changed with\n\
2490 \t-pmpi name\tReplace MPI_BUILD_PROFILING\n\
2491 -mnative  - Multiple indirects are native datatypes (no coercion)\n\
2492 -voidisptr - Consider \"void *\" as a pointer to a structure.\n\
2493 -ansi      - Input files use ANSI-C prototype form instead of K&R\n\
2494 -ansiheader - Generate ANSI-C style headers instead of Fortran interfaces\n\
2495 This will be useful for creating ANSI prototypes without ANSI-fying the\n\
2496 code.  The output is in <filename>.ansi .\n\
2497 " );
2498 }
2499 void Abort( const char *msg, const char *file, int line )
2500 {
2501     fprintf( stderr, "bfort terminating at %d: %s\n", line, msg );
2502     exit( 1 );
2503 }
2504 
2505 /*
2506  * Mapping of types between C and Fortran.
2507  *
2508  * These routines implement a translation between C and Fortran types.
2509  * For each C type that may be used in the source code, we need to know
2510  * the following:
2511  *    What is the corresponding Fortran datatype?
2512  *    What is the C type corresponding to that Fortran datatype?
2513  *    Are special steps required in translating between the C and Fortran
2514  *       types?  Two cases are MPI handles and character strings
2515  *
2516  *
2517  */
2518 
2519 /*
2520  * This is a simple, temporary version of a routine to take a C type
2521  * (by name) and return the Fortran equivalent.
2522  */
2523 const char *ArgToFortran( const char *typeName )
2524 {
2525     const char *outName = 0;
2526     if (strcmp( typeName, "int") == 0) outName = "integer";
2527     else if (strcmp( typeName, "char" ) == 0) outName   = "character";
2528     else if (strcmp( typeName, "double" ) == 0) outName = "double precision";
2529     else if (strcmp( typeName, "float" ) == 0) outName  = "real";
2530     else if (strcmp( typeName, "short" ) == 0) outName  = "integer*2";
2531     /* The following is a temporary hack */
2532     else if (strcmp( typeName, "void" ) == 0) outName = "PetscVoid";
2533     else {
2534       if (!useUserTypes) {
2535 	outName = "integer";
2536       } else {
2537 	outName = typeName;
2538       }
2539     }
2540     return outName;
2541 }
2542 
2543 #if 0
2544 /*
2545    Define the mapping a C to Fortran types, along with properties of the
2546    C types that are needed in generating the Fortran wrappers.
2547    Because the list is static (once created), we use a simple array, sorted
2548    by type type name in C, to improve search performance
2549 */
2550 /* Properties */
2551 #define CTYPE_IS_POINTER 0x1
2552 #define CTYPE_IS_MPI_HANDLE 0x2
2553 #define CTYPE_IS_CHARACTER 0x4
2554 
2555 typedef struct {
2556     char cName[MAX_TYPE_NAME];   /* Name of the type in C */
2557     char fName[MAX_TYPE_NAME];   /* Corresponding name in Fortran */
2558     int flags;                   /* Each bit is used with a flag (CTYPE_IS_xxx)*/
2559 } TypeInfo;
2560 
2561 static TypeInfo *typeArray = 0;
2562 static int typeArrayLen = 0;
2563 
2564 /* Given a C type name, return the corresponding TypeInfo record */
2565 TypeInfo *FindCType( const char *cName )
2566 {
2567     int i=typeArrayLen/2, first = 0, last = typeArrayLen-1;
2568     int cmp;
2569 
2570     do {
2571 	i = (last + first) / 2;
2572 	cmp = strcmp( cName, typeArray[i].cName );
2573 	if (cmp == 0) return typeArray + i;
2574 	if (cmp > 0) {
2575 	    first = i+1;
2576 	}
2577 	else {
2578 	    last = i-1;
2579 	}
2580     } while (first < last);
2581 
2582     return 0;
2583 }
2584 
2585 /* Sort the typeArray so that it can be used by the find routine above */
2586 int typeCompare( const void *a, const void *b )
2587 {
2588     const char *astr = ((TypeInfo *)a)->cName;
2589     const char *bstr = ((TypeInfo *)b)->cName;
2590     return strcmp( astr, bstr );
2591 }
2592 void sortTypeArray( void )
2593 {
2594     qsort( typeArray, typeArrayLen, sizeof(TypeInfo), typeCompare );
2595 }
2596 
2597 /* Add to/from Fortran option in description? */
2598 /* MPI_Comm_f2c( *(%s) ) */
2599 { "MPI_Comm", "integer", CTYPE_IS_MPI_HANDLE }, /* Add handle to int? */
2600 { "MPI_Request", "integer", CTYPE_IS_MPI_HANDLE },
2601 { "MPI_Group", "integer", CTYPE_IS_MPI_HANDLE },
2602 { "MPI_Op", "integer", CTYPE_IS_MPI_HANDLE },
2603 { "MPI_Datatype", "integer", CTYPE_IS_MPI_HANDLE },
2604 { "MPI_Win", "integer", CTYPE_IS_MPI_HANDLE },
2605 { "MPI_File", "integer", CTYPE_IS_MPI_HANDLE },
2606 { "MPI_Info", "integer", CTYPE_IS_MPI_HANDLE },
2607 { "MPI_Errhandler", "integer", CTYPE_IS_MPI_HANDLE },
2608 /* MPI types */
2609 { "MPI_Aint", "integer (kind=MPI_ADDRESS_KIND)", 0 },
2610 { "MPI_Offset", "integer (kind=MPI_OFFSET_KIND)", 0 },
2611 
2612 #endif
2613 
2614 /*
2615    This is a better version of strncpy that does not zero out the entire
2616    array but does ensure that it is null-terminated, and returns a
2617    failure indication (value not 0) if the string did not fit.
2618 */
2619 int MPIU_Strncpy( char *dest, const char *src, size_t n )
2620 {
2621     char * restrict d_ptr = dest;
2622     const char * restrict s_ptr = src;
2623     register int i;
2624 
2625     if (n == 0) return 0;
2626 
2627     i = (int)n;
2628     while (*s_ptr && i-- > 0) {
2629 	*d_ptr++ = *s_ptr++;
2630     }
2631 
2632     if (i > 0) {
2633 	*d_ptr = 0;
2634 	return 0;
2635     }
2636     else {
2637 	/* Force a null at the end of the string (gives better safety
2638 	   in case the user fails to check the error code) */
2639 	dest[n-1] = 0;
2640 	/* We may want to force an error message here, at least in the
2641 	   debugging version */
2642 	/*printf( "failure in copying %s with length %d\n", src, n ); */
2643 	return 1;
2644     }
2645 }
2646 
2647 /* This is like strncat, but does an append and the size is the
2648    size of the dest buffer.  Return 0 on success. */
2649 int MPIU_Strnapp( char *dest, const char *src, size_t n )
2650 {
2651     char * restrict d_ptr = dest;
2652     const char * restrict s_ptr = src;
2653     register int i;
2654 
2655     /* Get to the end of dest */
2656     i = (int)n;
2657     while (i-- > 0 && *d_ptr) d_ptr++;
2658     if (i <= 0) return 1;
2659 
2660     /* Append.  d_ptr points at first null and i is remaining space. */
2661     while (*s_ptr && i-- > 0) {
2662 	*d_ptr++ = *s_ptr++;
2663     }
2664 
2665     /* We allow i >= (not just >) here because the first while decrements
2666        i by one more than there are characters, leaving room for the null */
2667     if (i >= 0) {
2668 	*d_ptr = 0;
2669 	return 0;
2670     }
2671     else {
2672 	/* Force the null at the end */
2673 	*--d_ptr = 0;
2674 
2675 	/* We may want to force an error message here, at least in the
2676 	   debugging version */
2677 	return 1;
2678     }
2679 }
2680 
2681 void FreeArgs( ARG_LIST *args, int nargs )
2682 {
2683     int i;
2684     for (i=0; i<nargs; i++) {
2685 	if (args[i].name) {
2686 	    FREE( args[i].name );
2687 	    args[i].name = 0;
2688 	}
2689     }
2690 }
2691