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