2
library_f.c: Fortran API to library.c
3
Copyright (C) 2001 CCLRC, Charles Ballard
5
This library is free software; you can redistribute it and/or
6
modify it under the terms of the GNU Lesser General Public
7
License as published by the Free Software Foundation; either
8
version 2.1 of the License, or (at your option) any later
11
This library is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
Lesser General Public License for more details.
16
You should have received a copy of the GNU Lesser General Public
17
License along with this library; if not, write to the Free
18
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19
Boston, MA 02110-1301 USA
23
@brief FORTRAN API for library.c.
25
@author Charles Ballard
27
This file contains the wrappers for calling library.c from FORTRAN
28
and some "missing" routines.
30
System dependent names are handled in the FORTRAN_SUBR,
31
FORTRAN_FUN, FORTRAN_CALL macros defined in the header file.
32
fpstr is a typedef which masks the intricacies of FORTRAN string
37
#if defined(G95) || defined (GFORTRAN)
41
#include "ccp4_utils.h"
42
#include "ccp4_errno.h"
43
#include "ccp4_fortran.h"
45
/** Creates a null-terminated C string from an input
46
* string obtained from a Fortran call. Trailing blanks are
47
* removed. If input string is blank then return string "\0".
48
* Memory assigned by malloc, so can be freed.
49
* @param str1 pointer to string
50
* @param str1_len Fortran length of string
52
char *ccp4_FtoCString(fpstr str1, int str1_len)
56
size_t length = ccp4_utils_flength(FTN_STR(str1),str1_len);
59
str2 = (char *) ccp4_utils_malloc((length+1)*sizeof(char));
60
if(length) strncpy(str2, FTN_STR(str1), length);
66
/** Creates a Fortran string from an input C string for passing back to
67
* Fortran call. Characters after null-terminator may be junk, so pad
68
* with spaces. If input cstring is NULL, return blank string.
69
* @param str1 pointer Fortran to string
70
* @param str1_len Fortran length of string
71
* @param cstring input C string
73
void ccp4_CtoFString(fpstr str1, int str1_len, const char *cstring)
78
for (i = 0; i < str1_len; ++i)
80
} else if (str1_len > strlen(cstring)) {
81
strcpy(FTN_STR(str1),cstring);
82
for (i = strlen(cstring); i < str1_len; ++i)
85
strncpy(FTN_STR(str1),cstring,str1_len);
89
/* \section{Miscellaneous routines} */
90
/* \subsection{{\tt subroutine ustenv(\meta{string}, \meta{result})}} */
92
/* This sets an environment variable \meta{var} to \meta{val}, where the */
93
/* argument \meta{string}[[==']]\meta{var}[['//'='//']]\meta{val}[[']]. */
94
/* This is for use by the `\idx{logical name}' mechanism for specifying */
95
/* file connexions. Note that a \idx{VMS} varsion is supplied in {\tt */
96
/* vms.for} and that there is no standard way of setting and */
97
/* environment variable. In a minimal \ac{posix} system it might be */
98
/* necessary to twiddle the environment strings explicitly. */
99
/* Upon exit result contains [[0]] on Success, [[-1]] on Failure. */
102
/* <miscellaneous routines>= */
105
FORTRAN_SUBR ( USTENV, ustenv,
106
(fpstr str, int *result, int str_len),
107
(fpstr str, int *result),
108
(fpstr str, int str_len, int *result))
112
temp_name = ccp4_FtoCString(FTN_STR(str), FTN_LEN(str));
114
if (*result = ccp4_utils_setenv (temp_name))
115
ccp4_fatal("USTENV/CCP4_SETENV: Memory allocation failure");
120
#if ! defined (_MSC_VER)
121
FORTRAN_SUBR ( USTIME, ustime,
130
/* \section{Miscellaneous routines} */
131
/* \subsection{{\tt outbuf()}} */
133
/* This sets stdout to line buffering (error not fatal) */
135
/* <miscellaneous routines>= */
137
FORTRAN_SUBR ( OUTBUF, outbuf, (), (), ())
139
#if defined (__APPLE__) && defined (_CALL_SYSV)
140
char *s = "buffering=disable_preconn";
141
int s_len = strlen(s);
142
FORTRAN_CALL (SETRTEOPTS,setrteopts,(s,s_len),(s,s_len),(s,s_len));
144
if(ccp4_utils_outbuf())
145
ccp4_utils_print("OUTBUF:Can't turn off buffering");
148
/* \subsection{{\tt subroutine cunlink (\meta{filename})}} */
149
/* This unlinks \meta{filename} from the directory. It's intended for */
150
/* use with scratch files, so that they can be hidden when opened but */
151
/* still be available as long as they remain connected (see [[CCPOPN]]). */
152
/* This functionality doesn't seem to exist in \idx{VMS}\@. Failure to */
153
/* unlink isn't fatal (it's been observed, apparently spuriously). */
155
/* <miscellaneous routines>= */
156
FORTRAN_SUBR ( CUNLINK, cunlink,
157
(fpstr filename, int filename_len),
159
(fpstr filename, int filename_len))
162
return; /* can't do it */
166
temp_name = ccp4_FtoCString(FTN_STR(filename), FTN_LEN(filename));
168
if( unlink(temp_name) )
169
ccp4_utils_print("CUNLINK: Can't unlink");
174
/* \section{Dynamic memory allocation} */
175
/* It's nice to be able to determine array sizes at run time to avoid */
176
/* messy recompilation. The only way effectively to get dynamic */
177
/* allocation in Fortran77 reasonably portably is to do the allocation, */
178
/* e.g.\ in C, and invoke the Fortran routine passed as a parameter with */
179
/* pointers to the allocated memory which it will treat as arrays. If we */
180
/* want to allow more than one array, it's more tricky. */
182
/* \subsection{{\tt subroutine ccpal1 (\meta{routne}, \meta{n}. */
183
/* \meta{type}, \meta{length})}} */
184
/* Arranges to call subroutine \meta{routne} with \meta{n} array */
185
/* arguments. Each has a type indicated by \meta{type}$(i)$ and a length */
186
/* given by \meta{length}($i$). \meta{type} is an integer array with */
187
/* values 1, 2, 3, 4 inidcating {\tt */
188
/* INTEGER}, {\tt REAL}, {\tt DOUBLE PRECISION} and {\tt COMPLEX} */
190
/* It's not immediately clear what all the Fortran/C */
191
/* conventions are for passing [[CHARACTER]] arrays, so we'll arrange a */
192
/* higher-level interface and have [[types]] here just numeric. The */
193
/* Fortran ([[CCPALC]]) will also do argument validation. Also the rules */
194
/* for passing external routines as arguments aren't clear---assume */
195
/* the obvious way. */
197
/* There's a \idx{VMS} Fortran version of this, although the code here */
198
/* does work fine in VMS\@. */
200
/* NB: there's a possibility of a hook here to use memory-mapped files on */
201
/* systems with the capability and insufficient VM\@. */
203
/* Under protest, this now allocates zeroed storage for where programs */
204
/* make bad assumptions. */
206
/* <miscellaneous routines>= */
207
#ifndef VMS /* we'll use the Fortran version in VMS*/
209
FORTRAN_SUBR ( CCPAL1, ccpal1,
210
(void (* routne) (), int *n, int type[], int length[]),
211
(void (* routne) (), int *n, int type[], int length[]),
212
(void (* routne) (), int *n, int type[], int length[]))
214
static int item_sizes[] = {
215
(int) sizeof (char), /* 0: bytes */
216
(int) sizeof (short int), /* 1: (integer) half words */
217
(int) sizeof (float), /* 2: reals/words */
218
(int) sizeof (int), /* 3: `short complex' (pairs of half words).
219
NB int rather than 2*short since must fit
220
into fortran integer */
221
(int) 2*sizeof (float), /* 4: complex (pairs of words) */
222
(int) sizeof (int), /* 5: not used */
223
(int) sizeof (int) /* 6: integers */
225
int i, size, *leng[13];
228
for (i=0; i<*n; i++) {
231
size = item_sizes[6]; break; /* integer */
233
size = item_sizes[2]; break; /* real */
235
size = 2*item_sizes[2]; break; /* double */
237
size = 2*item_sizes[2]; break; /* complex */
239
size = item_sizes[1]; break; /* bytes (logical or integer *1) */
241
pointer[i+1] = calloc ((size_t) length[i], (size_t) size);
242
if (pointer[i+1] == NULL) ccp4_fatal ("CCPALC: can't allocate memory");
243
leng[i+1] = &(length[i]); /* convenience */
247
(* routne) (leng[1], pointer[1]);
250
(* routne) (leng[1], pointer[1], leng[2], pointer[2]);
253
(* routne) (leng[1], pointer[1], leng[2], pointer[2],
254
leng[3], pointer[3]);
257
(* routne) (leng[1], pointer[1], leng[2], pointer[2],
258
leng[3], pointer[3], leng[4], pointer[4]);
261
(* routne) (leng[1], pointer[1], leng[2], pointer[2],
262
leng[3], pointer[3], leng[4], pointer[4],
263
leng[5], pointer[5]);
266
(* routne) (leng[1], pointer[1], leng[2], pointer[2],
267
leng[3], pointer[3], leng[4], pointer[4],
268
leng[5], pointer[5], leng[6], pointer[6]);
271
(* routne) (leng[1], pointer[1], leng[2], pointer[2],
272
leng[3], pointer[3], leng[4], pointer[4],
273
leng[5], pointer[5], leng[6], pointer[6],
274
leng[7], pointer[7]);
277
(* routne) (leng[1], pointer[1], leng[2], pointer[2],
278
leng[3], pointer[3], leng[4], pointer[4],
279
leng[5], pointer[5], leng[6], pointer[6],
280
leng[7], pointer[7], leng[8], pointer[8]);
283
(* routne) (leng[1], pointer[1], leng[2], pointer[2],
284
leng[3], pointer[3], leng[4], pointer[4],
285
leng[5], pointer[5], leng[6], pointer[6],
286
leng[7], pointer[7], leng[8], pointer[8],
287
leng[9], pointer[9]);
290
(* routne) (leng[1], pointer[1], leng[2], pointer[2],
291
leng[3], pointer[3], leng[4], pointer[4],
292
leng[5], pointer[5], leng[6], pointer[6],
293
leng[7], pointer[7], leng[8], pointer[8],
294
leng[9], pointer[9], leng[10], pointer[10]);
297
(* routne) (leng[1], pointer[1], leng[2], pointer[2],
298
leng[3], pointer[3], leng[4], pointer[4],
299
leng[5], pointer[5], leng[6], pointer[6],
300
leng[7], pointer[7], leng[8], pointer[8],
301
leng[9], pointer[9], leng[10], pointer[10],
302
leng[11], pointer[11]);
305
(* routne) (leng[1], pointer[1], leng[2], pointer[2],
306
leng[3], pointer[3], leng[4], pointer[4],
307
leng[5], pointer[5], leng[6], pointer[6],
308
leng[7], pointer[7], leng[8], pointer[8],
309
leng[9], pointer[9], leng[10], pointer[10],
310
leng[11], pointer[11], leng[12], pointer[12]);
319
/* \section{`Magic' numbers} */
321
/* When, for instance, an $F$ is unobserved in a derivative, we might */
322
/* want to give it a special value---a `\idx{magic number}'---possibly in */
323
/* addition to a special value of the $\sigma$, like a negative one. */
324
/* Using such a number in a calculation (by mistake, through ignoring the */
325
/* value of $\sigma$, say) should not allow one to get half-sensible */
326
/* results as one might if this number was $-9999$ or some such. (There */
327
/* is non-enforced connexion between the $F$ and its $\sigma$ in the MTZ */
328
/* file, although one could think of adding extra columns to the file */
329
/* with bit-encoded flags telling whether the $F$ in a given column was */
332
/* The obvious tactic with \ac{ieee} arithmetic is to use a \idx{NaN} */
333
/* value in such situations. Things may be set up so that we either get */
334
/* an exception on using it in arithmetic or it silently propagates to all */
335
/* values using it and its presence is indicated by a NaN in the output. */
336
/* On a \idx{VAX} architecture we can't use NaN, but there is the */
337
/* possibility of using a */
338
/* `reserved operand'\index{reserved operand|see{Rop}} */
339
/* (`\idx{Rop}') value, */
340
/* which will cause an exception (by experiment: when used for */
341
/* floating-point arithmetic {\em or\/} printed, but not when assigned). */
342
/* The \idx{Convex} native mode is similar, except that the Rop may be */
343
/* printed (in the form {\tt Rop0x}\meta{fraction part}). */
345
/* On, say, the \idx{IBM 370 architecture}---which we don't currently */
346
/* support---anything's a valid floating point number, and the best ploy */
347
/* is probably to use the largest representable number as the `magic' */
348
/* value. This would stand a good chance of raising an overflow */
349
/* exception if used. Anyhow, if such bad use of an undefined value is */
350
/* made in a program due to insufficient checking by the code, it should */
351
/* be spotted on the \ac{ieee} systems and the bug fixed---it's not */
352
/* strictly necessary that it should cause a fatal error on all */
355
/* We need to provide a means of setting the magic number and checking */
356
/* whether a given value is such. These are architecture-dependent */
357
/* bit-level operations, hence their presence in the C code. */
359
/* The suite doesn't currently use these routines, but should do soon. */
360
/* \subsection{Setting a value: {\tt subroutine qnan(value)}} */
362
/* [[qnan]] was originally a \ft{} [[real function]] returning the value */
363
/* (and actually done in 2 stages) with a subroutine implementation like */
364
/* this called by the \ft{} function to avoid problems under \idx{VMS} */
365
/* and native \idx{Convex}. However, the \idx{f2c} calling convention */
366
/* for a function loses in that case since it assumes a [[double]] value */
367
/* returned which is cast to [[float]] with a SIGFPE, sigh. */
369
/* <magic numbers>= */
370
FORTRAN_SUBR ( QNAN, qnan,
371
(union float_uint_uchar *realnum),
372
(union float_uint_uchar *realnum),
373
(union float_uint_uchar *realnum))
375
*realnum = ccp4_nan ();
377
/* \subsection{Testing a value: {\tt int qisnan(\meta{real})}} */
379
/* We want a \ft{} logical function [[qisnan]] to test whether its argument */
380
/* is a \idx{NaN} or \idx{Rop}. We have to do this by writing a C */
381
/* [[int]]-valued procedure and testing the returned value in the \ft{} */
382
/* so that we don't have to assume how it represents logical values. The */
383
/* {\tt diskio}\index{diskio} library module provides the */
384
/* trivial interface [[QISNAN]]. */
386
/* <magic numbers>= */
387
FORTRAN_FUN (int, QISNAN, qisnan,
388
(union float_uint_uchar *realnum),
389
(union float_uint_uchar *realnum),
390
(union float_uint_uchar *realnum))
392
return (_BTOLV(ccp4_utils_isnan (realnum)));
395
/* \subsection{Absent data test for {\tt mtzlib}: {\tt subroutine */
396
/* ccpbml (\meta{ncols}, \meta{cols})}} */
397
/* In {\tt mtzlib} there's a fudge for \idx{BIOMOL}-convention absence */
398
/* flags, which are re-written to zeroes. To do the real number */
399
/* comparison, though, it's necessary to do a [[qnan]]-type test first. */
400
/* We don't want to call [[qnan]] (which calls [[cisnan]]) on every */
401
/* number in the data file, so the tests are amortised in this routine */
402
/* which deals with a whole array \meta{cols} of length \meta{ncols}. */
404
/* <magic numbers>= */
405
FORTRAN_SUBR ( CCPBML, ccpbml,
406
(int *ncols, union float_uint_uchar cols[]),
407
(int *ncols, union float_uint_uchar cols[]),
408
(int *ncols, union float_uint_uchar cols[]))
410
ccp4_utils_bml (*ncols, cols) ;
413
/* \subsection{Updating MTZ column ranges: {\tt subroutine ccpwrg */
414
/* (\meta{ncols}, \meta{rcols}, \meta{wmin}, \meta{wmax})}} */
415
/* This is a similar fudge to [[ccpbml]] to avoid [[QISNAN]] calls in */
416
/* updating the MTZ column ranges in {\tt mtzlib}. Note that [[wminmax]] */
417
/* actually indexes a 3-D Fortran array with the first */
418
/* dimension range of 2, indicating minimum and maximum values respectively. */
420
/* <magic numbers>= */
421
FORTRAN_SUBR ( CCPWRG, ccpwrg,
422
(int *ncols, union float_uint_uchar cols[], float wminmax[]),
423
(int *ncols, union float_uint_uchar cols[], float wminmax[]),
424
(int *ncols, union float_uint_uchar cols[], float wminmax[]))
426
ccp4_utils_wrg (*ncols, cols, wminmax) ;
429
/* \subsection{Routines for Data Harvesting: {\tt subroutine hgetlimits}} */
430
/* Returns largest int and largest float as defined in <limits.h> and */
432
FORTRAN_SUBR ( HGETLIMITS, hgetlimits,
433
(int *IValueNotDet, float *ValueNotDet),
434
(int *IValueNotDet, float *ValueNotDet),
435
(int *IValueNotDet, float *ValueNotDet))
437
ccp4_utils_hgetlimits (IValueNotDet, ValueNotDet);
440
/* Wrap-around for mkdir function. Returns 0 if successful, 1 if directory */
441
/* already exists, and -1 if other error. */
442
FORTRAN_SUBR ( CMKDIR, cmkdir,
443
(const fpstr path, const fpstr cmode, int *result, int path_len, int cmode_len),
444
(const fpstr path, const fpstr cmode, int *result),
445
(const fpstr path, int path_len, const fpstr cmode, int cmode_len, int *result))
447
char *temp_path, *temp_cmode;
449
temp_path = ccp4_FtoCString(FTN_STR(path), FTN_LEN(path));
450
temp_cmode = ccp4_FtoCString(FTN_STR(cmode), FTN_LEN(cmode));
452
*result = ccp4_utils_mkdir (temp_path, temp_cmode);
457
/* Wrap-around for mkdir function. Returns 0 if successful, 1 if directory */
458
/* already exists, and -1 if other error. */
459
FORTRAN_SUBR ( CCHMOD, cchmod,
460
(const fpstr path, const fpstr cmode, int *result, int path_len, int cmode_len),
461
(const fpstr path, const fpstr cmode, int *result),
462
(const fpstr path, int path_len, const fpstr cmode, int cmode_len, int *result))
464
char *temp_path, *temp_cmode;
466
temp_path = ccp4_FtoCString(FTN_STR(path), FTN_LEN(path));
467
temp_cmode = ccp4_FtoCString(FTN_STR(cmode), FTN_LEN(cmode));
469
*result = ccp4_utils_chmod (temp_path, temp_cmode);
474
/* isatty doesnt seem to be in Mircrosoft Visual Studio so this is a fudge */
475
#if defined (CALL_LIKE_MVS)
476
# if CALL_LIKE_MVS == 1
477
int __stdcall ISATTY (int *lunit)
483
/* erfc doesnt seem to be in Mircrosoft Visual Studdio so this is a fudge */
484
float __stdcall ERFC(float *value)
486
return (float) ccp4_erfc( (double) *value);
491
int isatty_ (int *lunit)
497
float erfc_ (float *value)
499
return (float) ccp4_erfc( (double) *value);
511
f_exit (); /* may or may not be registered with
512
exit, depending on the C libraries
513
capabilities, but is idempotent */
519
return (int) time (NULL);
524
return (int) getpid ();
527
/* following are from libI77/fio.h */
530
{ FILE *ufd; /*0=unconnected*/
534
int url; /*0=sequential*/
535
flag useek; /*true=can backspace, use dir, ...*/
540
flag uwrt; /*last io was write*/
543
extern unit f__units[];
546
#define err(f,m,s) {if(f) errno= m; else f__fatal(m,s); return(m);}
547
/* end of fio.h extract */
552
if (*lunit>=MXUNIT || *lunit<0)
554
/* f__units is a table of descriptions for the unit numbers (defined
555
in io.h) with file descriptors rather than streams */
556
return (isatty(fileno((f__units[*lunit]).ufd)) ? TRUE_ : FALSE_);
559
/* FORTRAN gerror intrinsic */
560
int gerror_ (str, Lstr)
566
if (errno == 0) { /* Avoid `Error 0' or some such message */
570
(void) strncpy (str, strerror (errno), Lstr);
571
for (i = strlen (str); i < Lstr; i++) str[i] = ' '; /* pad with spaces */
576
/* FORTRAN IErrNo intrinsic */
587
lt = localtime(&tim);
588
array[0] = lt->tm_hour; array[1] = lt->tm_min; array[2] = lt->tm_sec;
590
/* These ought to be intrinsic, but they should only be applied to */
591
/* [[INTEGER]] arguments. The types [[integer]] and [[logical]] are both */
592
/* assumed to be [[int]]. */
595
int /* integer */ ibset_ (a, b)
596
int /* integer */ *a, *b;
598
return (*a) | 1<<(*b);
601
int /* integer */ ibclr_ (a, b)
602
int /* integer */ *a, *b;
604
return (*a) & ~(1<<(*b));
607
int /* logical */ btest_ (a, b)
608
int /* integer */ *a, *b;
610
return ((((unsigned long) *a)>>(*b)))&1 ? TRUE_ : FALSE_;
612
#endif /* F2C support */
615
#if defined (__hpux) || defined (_AIX)
616
/* <AIX and HPUX support>= */
619
int isatty_ (int *fd) {
624
void gerror (str, Lstr)
630
if (errno == 0) { /* Avoid `Error 0' or some such message */
634
(void) strncpy (str, strerror (errno), Lstr);
635
for (i = strlen (str); i < Lstr; i++) str[i] = ' '; /* pad with spaces */
637
} /* End of gerror (str, Lstr) */
643
#endif /* HPUX and AIX support */
647
#if ( defined (__APPLE__) && !defined (__GNUC__) )
649
/* apple xlf support */
650
void gerror_ (str, Lstr)
656
if (errno == 0) { /* Avoid `Error 0' or some such message */
660
(void) strncpy (str, strerror (errno), Lstr);
661
for (i = strlen (str); i < Lstr; i++) str[i] = ' '; /* pad with spaces */
663
} /* End of gerror (str, Lstr) */
665
int isatty_(int *iunit)
667
return isatty(*iunit);
670
#endif /* end of apple xlf support */
674
#if ( defined (__linux__) && defined (_CALL_SYSV) )
675
/* linuxppc xlf support */
677
void gerror_ (str, Lstr)
683
if (errno == 0) { /* Avoid `Error 0' or some such message */
687
(void) strncpy (str, strerror (errno), Lstr);
688
for (i = strlen (str); i < Lstr; i++) str[i] = ' '; /* pad with spaces */
690
} /* End of gerror (str, Lstr) */
692
int isatty_(int *iunit)
694
return isatty(*iunit);
699
#elif defined(G95) || defined (GFORTRAN)
700
/* G95 and GFORTRAN support */
702
int isatty_(int *iunit)
704
return isatty(*iunit);
707
/* FORTRAN gerror intrinsic */
708
int gerror_(str, Lstr)
714
if (errno == 0) { /* Avoid `Error 0' or some such message */
718
(void) strncpy (str, strerror (errno), Lstr);
719
for (i = strlen (str); i < Lstr; i++) str[i] = ' '; /* pad with spaces */
729
int isatty_(int *iunit)
731
return isatty(*iunit);
736
#if defined(G95) || defined (GFORTRAN)
737
/* FORTRAN IErrNo intrinsic */
742
void ltime_(int *stime, int tarray[9])
747
if (localtime_r((const time_t *) stime, &ldatim) != NULL) {
748
tarray[0] = ldatim.tm_sec;
749
tarray[1] = ldatim.tm_min;
750
tarray[2] = ldatim.tm_hour;
751
tarray[3] = ldatim.tm_mday;
752
tarray[4] = ldatim.tm_mon;
753
tarray[5] = ldatim.tm_year;
754
tarray[6] = ldatim.tm_wday;
755
tarray[7] = ldatim.tm_yday;
756
tarray[8] = ldatim.tm_isdst;
764
void idate_ (int *day, int *month, int *year)
769
lt = localtime(&tim);
771
*month = lt->tm_mon+1; /* need range 1-12 */
772
*year = lt->tm_year + 1900;
775
void gmtime_(int *stime, int gmarray[9])
780
if (gmtime_r((const time_t *) stime, &udatim) != NULL) {
781
gmarray[0] = udatim.tm_sec;
782
gmarray[1] = udatim.tm_min;
783
gmarray[2] = udatim.tm_hour;
784
gmarray[3] = udatim.tm_mday;
785
gmarray[4] = udatim.tm_mon;
786
gmarray[5] = udatim.tm_year;
787
gmarray[6] = udatim.tm_wday;
788
gmarray[7] = udatim.tm_yday;
789
gmarray[8] = udatim.tm_isdst;
797
void system_(int *status, char *cmd, int cmd_len)
799
char *str = calloc( cmd_len+1, sizeof(char));
800
str = strncpy( str, cmd, cmd_len);
802
if ( (*status = system( str)) == -1 )
803
printf(" Forked command %s failed\n",cmd);
823
#endif /* G95 support */