URL
https://opencores.org/ocsvn/openrisc/openrisc/trunk
Subversion Repositories openrisc
Compare Revisions
- This comparison shows the changes necessary to convert path
/openrisc/tags/gnu-dev/fsf-gcc-snapshot-1-mar-12/or1k-gcc/libgfortran/intrinsics
- from Rev 733 to Rev 783
- ↔ Reverse comparison
Rev 733 → Rev 783
/extends_type_of.c
0,0 → 1,58
/* Implementation of the EXTENDS_TYPE_OF intrinsic. |
Copyright (C) 2004, 2007, 2009, 2011 Free Software Foundation, Inc. |
Contributed by Janus Weil <janus@gcc.gnu.org>. |
|
This file is part of the GNU Fortran runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
|
#include "libgfortran.h" |
#include <stdlib.h> |
|
|
typedef struct vtype |
{ |
GFC_INTEGER_4 hash; |
GFC_INTEGER_4 size; |
struct vtype *extends; |
} |
vtype; |
|
|
extern GFC_LOGICAL_4 is_extension_of (struct vtype *, struct vtype *); |
export_proto(is_extension_of); |
|
|
/* This is a helper function for the F2003 intrinsic EXTENDS_TYPE_OF. |
While EXTENDS_TYPE_OF accepts CLASS or TYPE arguments, this one here gets |
passed the corresponding vtabs. Each call to EXTENDS_TYPE_OF is translated |
to a call to is_extension_of. */ |
|
GFC_LOGICAL_4 |
is_extension_of (struct vtype *v1, struct vtype *v2) |
{ |
while (v1) |
{ |
if (v1->hash == v2->hash) return 1; |
v1 = v1->extends; |
} |
return 0; |
} |
/dtime.c
0,0 → 1,87
/* Implementation of the dtime intrinsic. |
Copyright (C) 2004, 2005, 2006, 2007, 2009, 2011 Free Software |
Foundation, Inc. |
|
This file is part of the GNU Fortran runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
#include "time_1.h" |
#include <gthr.h> |
|
#ifdef __GTHREAD_MUTEX_INIT |
static __gthread_mutex_t dtime_update_lock = __GTHREAD_MUTEX_INIT; |
#else |
static __gthread_mutex_t dtime_update_lock; |
#endif |
|
extern void dtime_sub (gfc_array_r4 *t, GFC_REAL_4 *result); |
iexport_proto(dtime_sub); |
|
void |
dtime_sub (gfc_array_r4 *t, GFC_REAL_4 *result) |
{ |
GFC_REAL_4 *tp; |
long user_sec, user_usec, system_sec, system_usec; |
static long us = 0, uu = 0, ss = 0 , su = 0; |
GFC_REAL_4 tu, ts, tt; |
|
if (((GFC_DESCRIPTOR_EXTENT(t,0))) < 2) |
runtime_error ("Insufficient number of elements in TARRAY."); |
|
__gthread_mutex_lock (&dtime_update_lock); |
if (gf_cputime (&user_sec, &user_usec, &system_sec, &system_usec) == 0) |
{ |
tu = (GFC_REAL_4) ((user_sec - us) + 1.e-6 * (user_usec - uu)); |
ts = (GFC_REAL_4) ((system_sec - ss) + 1.e-6 * (system_usec - su)); |
tt = tu + ts; |
us = user_sec; |
uu = user_usec; |
ss = system_sec; |
su = system_usec; |
} |
else |
{ |
tu = -1; |
ts = -1; |
tt = -1; |
} |
|
tp = t->data; |
|
*tp = tu; |
tp += GFC_DESCRIPTOR_STRIDE(t,0); |
*tp = ts; |
*result = tt; |
__gthread_mutex_unlock (&dtime_update_lock); |
} |
iexport(dtime_sub); |
|
extern GFC_REAL_4 dtime (gfc_array_r4 *t); |
export_proto(dtime); |
|
GFC_REAL_4 |
dtime (gfc_array_r4 *t) |
{ |
GFC_REAL_4 val; |
dtime_sub (t, &val); |
return val; |
} |
/string_intrinsics_inc.c
0,0 → 1,453
/* String intrinsics helper functions. |
Copyright 2002, 2005, 2007, 2008, 2009 Free Software Foundation, Inc. |
|
This file is part of the GNU Fortran runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
|
/* Rename the functions. */ |
#define concat_string SUFFIX(concat_string) |
#define string_len_trim SUFFIX(string_len_trim) |
#define adjustl SUFFIX(adjustl) |
#define adjustr SUFFIX(adjustr) |
#define string_index SUFFIX(string_index) |
#define string_scan SUFFIX(string_scan) |
#define string_verify SUFFIX(string_verify) |
#define string_trim SUFFIX(string_trim) |
#define string_minmax SUFFIX(string_minmax) |
#define zero_length_string SUFFIX(zero_length_string) |
#define compare_string SUFFIX(compare_string) |
|
|
/* The prototypes. */ |
|
extern void concat_string (gfc_charlen_type, CHARTYPE *, |
gfc_charlen_type, const CHARTYPE *, |
gfc_charlen_type, const CHARTYPE *); |
export_proto(concat_string); |
|
extern gfc_charlen_type string_len_trim (gfc_charlen_type, const CHARTYPE *); |
export_proto(string_len_trim); |
|
extern void adjustl (CHARTYPE *, gfc_charlen_type, const CHARTYPE *); |
export_proto(adjustl); |
|
extern void adjustr (CHARTYPE *, gfc_charlen_type, const CHARTYPE *); |
export_proto(adjustr); |
|
extern gfc_charlen_type string_index (gfc_charlen_type, const CHARTYPE *, |
gfc_charlen_type, const CHARTYPE *, |
GFC_LOGICAL_4); |
export_proto(string_index); |
|
extern gfc_charlen_type string_scan (gfc_charlen_type, const CHARTYPE *, |
gfc_charlen_type, const CHARTYPE *, |
GFC_LOGICAL_4); |
export_proto(string_scan); |
|
extern gfc_charlen_type string_verify (gfc_charlen_type, const CHARTYPE *, |
gfc_charlen_type, const CHARTYPE *, |
GFC_LOGICAL_4); |
export_proto(string_verify); |
|
extern void string_trim (gfc_charlen_type *, CHARTYPE **, gfc_charlen_type, |
const CHARTYPE *); |
export_proto(string_trim); |
|
extern void string_minmax (gfc_charlen_type *, CHARTYPE **, int, int, ...); |
export_proto(string_minmax); |
|
|
/* Use for functions which can return a zero-length string. */ |
static CHARTYPE zero_length_string = 0; |
|
|
/* Strings of unequal length are extended with pad characters. */ |
|
int |
compare_string (gfc_charlen_type len1, const CHARTYPE *s1, |
gfc_charlen_type len2, const CHARTYPE *s2) |
{ |
const UCHARTYPE *s; |
gfc_charlen_type len; |
int res; |
|
res = MEMCMP (s1, s2, ((len1 < len2) ? len1 : len2)); |
if (res != 0) |
return res; |
|
if (len1 == len2) |
return 0; |
|
if (len1 < len2) |
{ |
len = len2 - len1; |
s = (UCHARTYPE *) &s2[len1]; |
res = -1; |
} |
else |
{ |
len = len1 - len2; |
s = (UCHARTYPE *) &s1[len2]; |
res = 1; |
} |
|
while (len--) |
{ |
if (*s != ' ') |
{ |
if (*s > ' ') |
return res; |
else |
return -res; |
} |
s++; |
} |
|
return 0; |
} |
iexport(compare_string); |
|
|
/* The destination and source should not overlap. */ |
|
void |
concat_string (gfc_charlen_type destlen, CHARTYPE * dest, |
gfc_charlen_type len1, const CHARTYPE * s1, |
gfc_charlen_type len2, const CHARTYPE * s2) |
{ |
if (len1 >= destlen) |
{ |
memcpy (dest, s1, destlen * sizeof (CHARTYPE)); |
return; |
} |
memcpy (dest, s1, len1 * sizeof (CHARTYPE)); |
dest += len1; |
destlen -= len1; |
|
if (len2 >= destlen) |
{ |
memcpy (dest, s2, destlen * sizeof (CHARTYPE)); |
return; |
} |
|
memcpy (dest, s2, len2 * sizeof (CHARTYPE)); |
MEMSET (&dest[len2], ' ', destlen - len2); |
} |
|
|
/* Return string with all trailing blanks removed. */ |
|
void |
string_trim (gfc_charlen_type *len, CHARTYPE **dest, gfc_charlen_type slen, |
const CHARTYPE *src) |
{ |
*len = string_len_trim (slen, src); |
|
if (*len == 0) |
*dest = &zero_length_string; |
else |
{ |
/* Allocate space for result string. */ |
*dest = internal_malloc_size (*len * sizeof (CHARTYPE)); |
|
/* Copy string if necessary. */ |
memcpy (*dest, src, *len * sizeof (CHARTYPE)); |
} |
} |
|
|
/* The length of a string not including trailing blanks. */ |
|
gfc_charlen_type |
string_len_trim (gfc_charlen_type len, const CHARTYPE *s) |
{ |
const gfc_charlen_type long_len = (gfc_charlen_type) sizeof (unsigned long); |
gfc_charlen_type i; |
|
i = len - 1; |
|
/* If we've got the standard (KIND=1) character type, we scan the string in |
long word chunks to speed it up (until a long word is hit that does not |
consist of ' 's). */ |
if (sizeof (CHARTYPE) == 1 && i >= long_len) |
{ |
int starting; |
unsigned long blank_longword; |
|
/* Handle the first characters until we're aligned on a long word |
boundary. Actually, s + i + 1 must be properly aligned, because |
s + i will be the last byte of a long word read. */ |
starting = ((unsigned long) |
#ifdef __INTPTR_TYPE__ |
(__INTPTR_TYPE__) |
#endif |
(s + i + 1)) % long_len; |
i -= starting; |
for (; starting > 0; --starting) |
if (s[i + starting] != ' ') |
return i + starting + 1; |
|
/* Handle the others in a batch until first non-blank long word is |
found. Here again, s + i is the last byte of the current chunk, |
to it starts at s + i - sizeof (long) + 1. */ |
|
#if __SIZEOF_LONG__ == 4 |
blank_longword = 0x20202020L; |
#elif __SIZEOF_LONG__ == 8 |
blank_longword = 0x2020202020202020L; |
#else |
#error Invalid size of long! |
#endif |
|
while (i >= long_len) |
{ |
i -= long_len; |
if (*((unsigned long*) (s + i + 1)) != blank_longword) |
{ |
i += long_len; |
break; |
} |
} |
|
/* Now continue for the last characters with naive approach below. */ |
assert (i >= 0); |
} |
|
/* Simply look for the first non-blank character. */ |
while (i >= 0 && s[i] == ' ') |
--i; |
return i + 1; |
} |
|
|
/* Find a substring within a string. */ |
|
gfc_charlen_type |
string_index (gfc_charlen_type slen, const CHARTYPE *str, |
gfc_charlen_type sslen, const CHARTYPE *sstr, |
GFC_LOGICAL_4 back) |
{ |
gfc_charlen_type start, last, delta, i; |
|
if (sslen == 0) |
return back ? (slen + 1) : 1; |
|
if (sslen > slen) |
return 0; |
|
if (!back) |
{ |
last = slen + 1 - sslen; |
start = 0; |
delta = 1; |
} |
else |
{ |
last = -1; |
start = slen - sslen; |
delta = -1; |
} |
|
for (; start != last; start+= delta) |
{ |
for (i = 0; i < sslen; i++) |
{ |
if (str[start + i] != sstr[i]) |
break; |
} |
if (i == sslen) |
return (start + 1); |
} |
return 0; |
} |
|
|
/* Remove leading blanks from a string, padding at end. The src and dest |
should not overlap. */ |
|
void |
adjustl (CHARTYPE *dest, gfc_charlen_type len, const CHARTYPE *src) |
{ |
gfc_charlen_type i; |
|
i = 0; |
while (i < len && src[i] == ' ') |
i++; |
|
if (i < len) |
memcpy (dest, &src[i], (len - i) * sizeof (CHARTYPE)); |
if (i > 0) |
MEMSET (&dest[len - i], ' ', i); |
} |
|
|
/* Remove trailing blanks from a string. */ |
|
void |
adjustr (CHARTYPE *dest, gfc_charlen_type len, const CHARTYPE *src) |
{ |
gfc_charlen_type i; |
|
i = len; |
while (i > 0 && src[i - 1] == ' ') |
i--; |
|
if (i < len) |
MEMSET (dest, ' ', len - i); |
memcpy (&dest[len - i], src, i * sizeof (CHARTYPE)); |
} |
|
|
/* Scan a string for any one of the characters in a set of characters. */ |
|
gfc_charlen_type |
string_scan (gfc_charlen_type slen, const CHARTYPE *str, |
gfc_charlen_type setlen, const CHARTYPE *set, GFC_LOGICAL_4 back) |
{ |
gfc_charlen_type i, j; |
|
if (slen == 0 || setlen == 0) |
return 0; |
|
if (back) |
{ |
for (i = slen - 1; i >= 0; i--) |
{ |
for (j = 0; j < setlen; j++) |
{ |
if (str[i] == set[j]) |
return (i + 1); |
} |
} |
} |
else |
{ |
for (i = 0; i < slen; i++) |
{ |
for (j = 0; j < setlen; j++) |
{ |
if (str[i] == set[j]) |
return (i + 1); |
} |
} |
} |
|
return 0; |
} |
|
|
/* Verify that a set of characters contains all the characters in a |
string by identifying the position of the first character in a |
characters that does not appear in a given set of characters. */ |
|
gfc_charlen_type |
string_verify (gfc_charlen_type slen, const CHARTYPE *str, |
gfc_charlen_type setlen, const CHARTYPE *set, |
GFC_LOGICAL_4 back) |
{ |
gfc_charlen_type start, last, delta, i; |
|
if (slen == 0) |
return 0; |
|
if (back) |
{ |
last = -1; |
start = slen - 1; |
delta = -1; |
} |
else |
{ |
last = slen; |
start = 0; |
delta = 1; |
} |
for (; start != last; start += delta) |
{ |
for (i = 0; i < setlen; i++) |
{ |
if (str[start] == set[i]) |
break; |
} |
if (i == setlen) |
return (start + 1); |
} |
|
return 0; |
} |
|
|
/* MIN and MAX intrinsics for strings. The front-end makes sure that |
nargs is at least 2. */ |
|
void |
string_minmax (gfc_charlen_type *rlen, CHARTYPE **dest, int op, int nargs, ...) |
{ |
va_list ap; |
int i; |
CHARTYPE *next, *res; |
gfc_charlen_type nextlen, reslen; |
|
va_start (ap, nargs); |
reslen = va_arg (ap, gfc_charlen_type); |
res = va_arg (ap, CHARTYPE *); |
*rlen = reslen; |
|
if (res == NULL) |
runtime_error ("First argument of '%s' intrinsic should be present", |
op > 0 ? "MAX" : "MIN"); |
|
for (i = 1; i < nargs; i++) |
{ |
nextlen = va_arg (ap, gfc_charlen_type); |
next = va_arg (ap, CHARTYPE *); |
|
if (next == NULL) |
{ |
if (i == 1) |
runtime_error ("Second argument of '%s' intrinsic should be " |
"present", op > 0 ? "MAX" : "MIN"); |
else |
continue; |
} |
|
if (nextlen > *rlen) |
*rlen = nextlen; |
|
if (op * compare_string (reslen, res, nextlen, next) < 0) |
{ |
reslen = nextlen; |
res = next; |
} |
} |
va_end (ap); |
|
if (*rlen == 0) |
*dest = &zero_length_string; |
else |
{ |
CHARTYPE *tmp = internal_malloc_size (*rlen * sizeof (CHARTYPE)); |
memcpy (tmp, res, reslen * sizeof (CHARTYPE)); |
MEMSET (&tmp[reslen], ' ', *rlen - reslen); |
*dest = tmp; |
} |
} |
/sleep.c
0,0 → 1,67
/* Implementation of the SLEEP intrinsic. |
Copyright (C) 2005, 2007, 2009 Free Software Foundation, Inc. |
Contributed by François-Xavier Coudert <coudert@clipper.ens.fr> |
|
This file is part of the GNU Fortran 95 runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
|
#include <errno.h> |
|
#ifdef HAVE_UNISTD_H |
#include <unistd.h> |
#endif |
|
#ifdef __MINGW32__ |
# include <windows.h> |
# undef sleep |
# define sleep(x) Sleep(1000*(x)) |
# define HAVE_SLEEP 1 |
#endif |
|
/* SUBROUTINE SLEEP(SECONDS) |
INTEGER, INTENT(IN) :: SECONDS |
|
A choice had to be made if SECONDS is negative. For g77, this is |
equivalent to SLEEP(0). */ |
|
#ifdef HAVE_SLEEP |
extern void sleep_i4_sub (GFC_INTEGER_4 *); |
iexport_proto(sleep_i4_sub); |
|
void |
sleep_i4_sub (GFC_INTEGER_4 *seconds) |
{ |
sleep (*seconds < 0 ? 0 : (unsigned int) *seconds); |
} |
iexport(sleep_i4_sub); |
|
extern void sleep_i8_sub (GFC_INTEGER_8 *); |
iexport_proto(sleep_i8_sub); |
|
void |
sleep_i8_sub (GFC_INTEGER_8 *seconds) |
{ |
sleep (*seconds < 0 ? 0 : (unsigned int) *seconds); |
} |
iexport(sleep_i8_sub); |
#endif |
/hostnm.c
0,0 → 1,144
/* Implementation of the HOSTNM intrinsic. |
Copyright (C) 2005, 2007, 2009 Free Software Foundation, Inc. |
Contributed by François-Xavier Coudert <coudert@clipper.ens.fr> |
|
This file is part of the GNU Fortran 95 runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
|
#include <errno.h> |
#include <string.h> |
|
#ifdef HAVE_UNISTD_H |
#include <unistd.h> |
#endif |
|
|
/* Windows32 version */ |
#if defined __MINGW32__ && !defined HAVE_GETHOSTNAME |
#define WIN32_LEAN_AND_MEAN |
#include <windows.h> |
#include <errno.h> |
|
static int |
w32_gethostname (char *name, size_t len) |
{ |
/* We could try the WinSock API gethostname, but that will |
fail if WSAStartup function has has not been called. We don't |
really need a name that will be understood by socket API, so avoid |
unnecessary dependence on WinSock libraries by using |
GetComputerName instead. */ |
|
/* On Win9x GetComputerName fails if the input size is less |
than MAX_COMPUTERNAME_LENGTH + 1. */ |
char buffer[MAX_COMPUTERNAME_LENGTH + 1]; |
DWORD size = sizeof (buffer); |
|
if (!GetComputerName (buffer, &size)) |
return -1; |
|
if ((size = strlen (buffer) + 1) > len) |
{ |
errno = EINVAL; |
/* Truncate as per POSIX spec. We do not NUL-terminate. */ |
size = len; |
} |
memcpy (name, buffer, (size_t) size); |
|
return 0; |
} |
|
#undef gethostname |
#define gethostname w32_gethostname |
#define HAVE_GETHOSTNAME 1 |
|
#endif |
|
|
/* SUBROUTINE HOSTNM(NAME, STATUS) |
CHARACTER(len=*), INTENT(OUT) :: NAME |
INTEGER, INTENT(OUT), OPTIONAL :: STATUS */ |
|
#ifdef HAVE_GETHOSTNAME |
extern void hostnm_i4_sub (char *, GFC_INTEGER_4 *, gfc_charlen_type); |
iexport_proto(hostnm_i4_sub); |
|
void |
hostnm_i4_sub (char *name, GFC_INTEGER_4 *status, gfc_charlen_type name_len) |
{ |
int val, i; |
char *p; |
|
memset (name, ' ', name_len); |
p = gfc_alloca (name_len + 1); |
|
val = gethostname (p, name_len); |
|
if (val == 0) |
{ |
i = -1; |
while (i < name_len && p[++i] != '\0') |
name[i] = p[i]; |
} |
|
if (status != NULL) |
*status = (val == 0) ? 0 : errno; |
} |
iexport(hostnm_i4_sub); |
|
extern void hostnm_i8_sub (char *, GFC_INTEGER_8 *, gfc_charlen_type); |
iexport_proto(hostnm_i8_sub); |
|
void |
hostnm_i8_sub (char *name, GFC_INTEGER_8 *status, gfc_charlen_type name_len) |
{ |
int val, i; |
char *p; |
|
memset (name, ' ', name_len); |
p = gfc_alloca (name_len + 1); |
|
val = gethostname (p, name_len); |
|
if (val == 0) |
{ |
i = -1; |
while (i < name_len && p[++i] != '\0') |
name[i] = p[i]; |
} |
|
if (status != NULL) |
*status = (val == 0) ? 0 : errno; |
} |
iexport(hostnm_i8_sub); |
|
extern GFC_INTEGER_4 hostnm (char *, gfc_charlen_type); |
export_proto(hostnm); |
|
GFC_INTEGER_4 |
hostnm (char *name, gfc_charlen_type name_len) |
{ |
GFC_INTEGER_4 val; |
hostnm_i4_sub (name, &val, name_len); |
return val; |
} |
#endif |
/perror.c
0,0 → 1,53
/* Implementation of the PERROR intrinsic. |
Copyright (C) 2005, 2007, 2009, 2011 Free Software Foundation, Inc. |
Contributed by François-Xavier Coudert <coudert@clipper.ens.fr> |
|
This file is part of the GNU Fortran runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
|
#include <errno.h> |
#include <string.h> |
|
/* SUBROUTINE PERROR(STRING) |
CHARACTER(len=*), INTENT(IN) :: STRING */ |
|
extern void perror_sub (char *, gfc_charlen_type); |
iexport_proto(perror_sub); |
|
void |
perror_sub (char *string, gfc_charlen_type string_len) |
{ |
char * str; |
|
/* Trim trailing spaces from paths. */ |
while (string_len > 0 && string[string_len - 1] == ' ') |
string_len--; |
|
/* Make a null terminated copy of the strings. */ |
str = gfc_alloca (string_len + 1); |
memcpy (str, string, string_len); |
str[string_len] = '\0'; |
|
perror (str); |
} |
iexport(perror_sub); |
/exit.c
0,0 → 1,50
/* Implementation of the EXIT intrinsic. |
Copyright (C) 2004, 2007, 2009, 2011 Free Software Foundation, Inc. |
Contributed by Steven G. Kargl <kargls@comcast.net>. |
|
This file is part of the GNU Fortran runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
|
#include "libgfortran.h" |
#include <stdlib.h> |
|
|
/* SUBROUTINE EXIT(STATUS) |
INTEGER, INTENT(IN), OPTIONAL :: STATUS */ |
|
extern void exit_i4 (GFC_INTEGER_4 *); |
export_proto(exit_i4); |
|
void |
exit_i4 (GFC_INTEGER_4 * status) |
{ |
exit (status ? *status : 0); |
} |
|
extern void exit_i8 (GFC_INTEGER_8 *); |
export_proto(exit_i8); |
|
void |
exit_i8 (GFC_INTEGER_8 * status) |
{ |
exit (status ? *status : 0); |
} |
/transpose_generic.c
0,0 → 1,151
/* Implementation of the TRANSPOSE intrinsic |
Copyright 2003, 2006, 2007, 2009 Free Software Foundation, Inc. |
|
|
This file is part of the GNU Fortran 95 runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
#include <stdlib.h> |
#include <string.h> |
#include <assert.h> |
|
extern void transpose (gfc_array_char *, gfc_array_char *); |
export_proto(transpose); |
|
static void |
transpose_internal (gfc_array_char *ret, gfc_array_char *source) |
{ |
/* r.* indicates the return array. */ |
index_type rxstride, rystride; |
char *rptr; |
/* s.* indicates the source array. */ |
index_type sxstride, systride; |
const char *sptr; |
|
index_type xcount, ycount; |
index_type x, y; |
index_type size; |
|
assert (GFC_DESCRIPTOR_RANK (source) == 2 |
&& GFC_DESCRIPTOR_RANK (ret) == 2); |
|
size = GFC_DESCRIPTOR_SIZE(ret); |
|
if (ret->data == NULL) |
{ |
assert (ret->dtype == source->dtype); |
|
GFC_DIMENSION_SET(ret->dim[0], 0, GFC_DESCRIPTOR_EXTENT(source,1) - 1, |
1); |
|
GFC_DIMENSION_SET(ret->dim[1], 0, GFC_DESCRIPTOR_EXTENT(source,0) - 1, |
GFC_DESCRIPTOR_EXTENT(source, 1)); |
|
ret->data = internal_malloc_size (size * size0 ((array_t*)ret)); |
ret->offset = 0; |
} |
else if (unlikely (compile_options.bounds_check)) |
{ |
index_type ret_extent, src_extent; |
|
ret_extent = GFC_DESCRIPTOR_EXTENT(ret,0); |
src_extent = GFC_DESCRIPTOR_EXTENT(source,1); |
|
if (src_extent != ret_extent) |
runtime_error ("Incorrect extent in return value of TRANSPOSE" |
" intrinsic in dimension 1: is %ld," |
" should be %ld", (long int) src_extent, |
(long int) ret_extent); |
|
ret_extent = GFC_DESCRIPTOR_EXTENT(ret,1); |
src_extent = GFC_DESCRIPTOR_EXTENT(source,0); |
|
if (src_extent != ret_extent) |
runtime_error ("Incorrect extent in return value of TRANSPOSE" |
" intrinsic in dimension 2: is %ld," |
" should be %ld", (long int) src_extent, |
(long int) ret_extent); |
|
} |
|
sxstride = GFC_DESCRIPTOR_STRIDE_BYTES(source,0); |
systride = GFC_DESCRIPTOR_STRIDE_BYTES(source,1); |
xcount = GFC_DESCRIPTOR_EXTENT(source,0); |
ycount = GFC_DESCRIPTOR_EXTENT(source,1); |
|
rxstride = GFC_DESCRIPTOR_STRIDE_BYTES(ret,0); |
rystride = GFC_DESCRIPTOR_STRIDE_BYTES(ret,1); |
|
rptr = ret->data; |
sptr = source->data; |
|
for (y = 0; y < ycount; y++) |
{ |
for (x = 0; x < xcount; x++) |
{ |
memcpy (rptr, sptr, size); |
|
sptr += sxstride; |
rptr += rystride; |
} |
sptr += systride - (sxstride * xcount); |
rptr += rxstride - (rystride * xcount); |
} |
} |
|
|
extern void transpose (gfc_array_char *, gfc_array_char *); |
export_proto(transpose); |
|
void |
transpose (gfc_array_char *ret, gfc_array_char *source) |
{ |
transpose_internal (ret, source); |
} |
|
|
extern void transpose_char (gfc_array_char *, GFC_INTEGER_4, |
gfc_array_char *, GFC_INTEGER_4); |
export_proto(transpose_char); |
|
void |
transpose_char (gfc_array_char *ret, |
GFC_INTEGER_4 ret_length __attribute__((unused)), |
gfc_array_char *source, |
GFC_INTEGER_4 source_length __attribute__((unused))) |
{ |
transpose_internal (ret, source); |
} |
|
|
extern void transpose_char4 (gfc_array_char *, GFC_INTEGER_4, |
gfc_array_char *, GFC_INTEGER_4); |
export_proto(transpose_char4); |
|
void |
transpose_char4 (gfc_array_char *ret, |
GFC_INTEGER_4 ret_length __attribute__((unused)), |
gfc_array_char *source, |
GFC_INTEGER_4 source_length __attribute__((unused))) |
{ |
transpose_internal (ret, source); |
} |
/pack_generic.c
0,0 → 1,643
/* Generic implementation of the PACK intrinsic |
Copyright (C) 2002, 2004, 2005, 2006, 2007, 2009, 2010 |
Free Software Foundation, Inc. |
Contributed by Paul Brook <paul@nowt.org> |
|
This file is part of the GNU Fortran 95 runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Ligbfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
#include <stdlib.h> |
#include <assert.h> |
#include <string.h> |
|
/* PACK is specified as follows: |
|
13.14.80 PACK (ARRAY, MASK, [VECTOR]) |
|
Description: Pack an array into an array of rank one under the |
control of a mask. |
|
Class: Transformational function. |
|
Arguments: |
ARRAY may be of any type. It shall not be scalar. |
MASK shall be of type LOGICAL. It shall be conformable with ARRAY. |
VECTOR (optional) shall be of the same type and type parameters |
as ARRAY. VECTOR shall have at least as many elements as |
there are true elements in MASK. If MASK is a scalar |
with the value true, VECTOR shall have at least as many |
elements as there are in ARRAY. |
|
Result Characteristics: The result is an array of rank one with the |
same type and type parameters as ARRAY. If VECTOR is present, the |
result size is that of VECTOR; otherwise, the result size is the |
number /t/ of true elements in MASK unless MASK is scalar with the |
value true, in which case the result size is the size of ARRAY. |
|
Result Value: Element /i/ of the result is the element of ARRAY |
that corresponds to the /i/th true element of MASK, taking elements |
in array element order, for /i/ = 1, 2, ..., /t/. If VECTOR is |
present and has size /n/ > /t/, element /i/ of the result has the |
value VECTOR(/i/), for /i/ = /t/ + 1, ..., /n/. |
|
Examples: The nonzero elements of an array M with the value |
| 0 0 0 | |
| 9 0 0 | may be "gathered" by the function PACK. The result of |
| 0 0 7 | |
PACK (M, MASK = M.NE.0) is [9,7] and the result of PACK (M, M.NE.0, |
VECTOR = (/ 2,4,6,8,10,12 /)) is [9,7,6,8,10,12]. |
|
There are two variants of the PACK intrinsic: one, where MASK is |
array valued, and the other one where MASK is scalar. */ |
|
static void |
pack_internal (gfc_array_char *ret, const gfc_array_char *array, |
const gfc_array_l1 *mask, const gfc_array_char *vector, |
index_type size) |
{ |
/* r.* indicates the return array. */ |
index_type rstride0; |
char * restrict rptr; |
/* s.* indicates the source array. */ |
index_type sstride[GFC_MAX_DIMENSIONS]; |
index_type sstride0; |
const char *sptr; |
/* m.* indicates the mask array. */ |
index_type mstride[GFC_MAX_DIMENSIONS]; |
index_type mstride0; |
const GFC_LOGICAL_1 *mptr; |
|
index_type count[GFC_MAX_DIMENSIONS]; |
index_type extent[GFC_MAX_DIMENSIONS]; |
index_type n; |
index_type dim; |
index_type nelem; |
index_type total; |
int mask_kind; |
|
dim = GFC_DESCRIPTOR_RANK (array); |
|
sptr = array->data; |
mptr = mask->data; |
|
/* Use the same loop for all logical types, by using GFC_LOGICAL_1 |
and using shifting to address size and endian issues. */ |
|
mask_kind = GFC_DESCRIPTOR_SIZE (mask); |
|
if (mask_kind == 1 || mask_kind == 2 || mask_kind == 4 || mask_kind == 8 |
#ifdef HAVE_GFC_LOGICAL_16 |
|| mask_kind == 16 |
#endif |
) |
{ |
/* Don't convert a NULL pointer as we use test for NULL below. */ |
if (mptr) |
mptr = GFOR_POINTER_TO_L1 (mptr, mask_kind); |
} |
else |
runtime_error ("Funny sized logical array"); |
|
for (n = 0; n < dim; n++) |
{ |
count[n] = 0; |
extent[n] = GFC_DESCRIPTOR_EXTENT(array,n); |
sstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(array,n); |
mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask,n); |
} |
if (sstride[0] == 0) |
sstride[0] = size; |
if (mstride[0] == 0) |
mstride[0] = mask_kind; |
|
if (ret->data == NULL || unlikely (compile_options.bounds_check)) |
{ |
/* Count the elements, either for allocating memory or |
for bounds checking. */ |
|
if (vector != NULL) |
{ |
/* The return array will have as many |
elements as there are in VECTOR. */ |
total = GFC_DESCRIPTOR_EXTENT(vector,0); |
} |
else |
{ |
/* We have to count the true elements in MASK. */ |
|
total = count_0 (mask); |
} |
|
if (ret->data == NULL) |
{ |
/* Setup the array descriptor. */ |
GFC_DIMENSION_SET(ret->dim[0], 0, total-1, 1); |
|
ret->offset = 0; |
/* internal_malloc_size allocates a single byte for zero size. */ |
ret->data = internal_malloc_size (size * total); |
|
if (total == 0) |
return; /* In this case, nothing remains to be done. */ |
} |
else |
{ |
/* We come here because of range checking. */ |
index_type ret_extent; |
|
ret_extent = GFC_DESCRIPTOR_EXTENT(ret,0); |
if (total != ret_extent) |
runtime_error ("Incorrect extent in return value of PACK intrinsic;" |
" is %ld, should be %ld", (long int) total, |
(long int) ret_extent); |
} |
} |
|
rstride0 = GFC_DESCRIPTOR_STRIDE_BYTES(ret,0); |
if (rstride0 == 0) |
rstride0 = size; |
sstride0 = sstride[0]; |
mstride0 = mstride[0]; |
rptr = ret->data; |
|
while (sptr && mptr) |
{ |
/* Test this element. */ |
if (*mptr) |
{ |
/* Add it. */ |
memcpy (rptr, sptr, size); |
rptr += rstride0; |
} |
/* Advance to the next element. */ |
sptr += sstride0; |
mptr += mstride0; |
count[0]++; |
n = 0; |
while (count[n] == extent[n]) |
{ |
/* When we get to the end of a dimension, reset it and increment |
the next dimension. */ |
count[n] = 0; |
/* We could precalculate these products, but this is a less |
frequently used path so probably not worth it. */ |
sptr -= sstride[n] * extent[n]; |
mptr -= mstride[n] * extent[n]; |
n++; |
if (n >= dim) |
{ |
/* Break out of the loop. */ |
sptr = NULL; |
break; |
} |
else |
{ |
count[n]++; |
sptr += sstride[n]; |
mptr += mstride[n]; |
} |
} |
} |
|
/* Add any remaining elements from VECTOR. */ |
if (vector) |
{ |
n = GFC_DESCRIPTOR_EXTENT(vector,0); |
nelem = ((rptr - ret->data) / rstride0); |
if (n > nelem) |
{ |
sstride0 = GFC_DESCRIPTOR_STRIDE_BYTES(vector,0); |
if (sstride0 == 0) |
sstride0 = size; |
|
sptr = vector->data + sstride0 * nelem; |
n -= nelem; |
while (n--) |
{ |
memcpy (rptr, sptr, size); |
rptr += rstride0; |
sptr += sstride0; |
} |
} |
} |
} |
|
extern void pack (gfc_array_char *, const gfc_array_char *, |
const gfc_array_l1 *, const gfc_array_char *); |
export_proto(pack); |
|
void |
pack (gfc_array_char *ret, const gfc_array_char *array, |
const gfc_array_l1 *mask, const gfc_array_char *vector) |
{ |
index_type type_size; |
index_type size; |
|
type_size = GFC_DTYPE_TYPE_SIZE(array); |
|
switch(type_size) |
{ |
case GFC_DTYPE_LOGICAL_1: |
case GFC_DTYPE_INTEGER_1: |
case GFC_DTYPE_DERIVED_1: |
pack_i1 ((gfc_array_i1 *) ret, (gfc_array_i1 *) array, |
(gfc_array_l1 *) mask, (gfc_array_i1 *) vector); |
return; |
|
case GFC_DTYPE_LOGICAL_2: |
case GFC_DTYPE_INTEGER_2: |
pack_i2 ((gfc_array_i2 *) ret, (gfc_array_i2 *) array, |
(gfc_array_l1 *) mask, (gfc_array_i2 *) vector); |
return; |
|
case GFC_DTYPE_LOGICAL_4: |
case GFC_DTYPE_INTEGER_4: |
pack_i4 ((gfc_array_i4 *) ret, (gfc_array_i4 *) array, |
(gfc_array_l1 *) mask, (gfc_array_i4 *) vector); |
return; |
|
case GFC_DTYPE_LOGICAL_8: |
case GFC_DTYPE_INTEGER_8: |
pack_i8 ((gfc_array_i8 *) ret, (gfc_array_i8 *) array, |
(gfc_array_l1 *) mask, (gfc_array_i8 *) vector); |
return; |
|
#ifdef HAVE_GFC_INTEGER_16 |
case GFC_DTYPE_LOGICAL_16: |
case GFC_DTYPE_INTEGER_16: |
pack_i16 ((gfc_array_i16 *) ret, (gfc_array_i16 *) array, |
(gfc_array_l1 *) mask, (gfc_array_i16 *) vector); |
return; |
#endif |
|
case GFC_DTYPE_REAL_4: |
pack_r4 ((gfc_array_r4 *) ret, (gfc_array_r4 *) array, |
(gfc_array_l1 *) mask, (gfc_array_r4 *) vector); |
return; |
|
case GFC_DTYPE_REAL_8: |
pack_r8 ((gfc_array_r8 *) ret, (gfc_array_r8 *) array, |
(gfc_array_l1 *) mask, (gfc_array_r8 *) vector); |
return; |
|
/* FIXME: This here is a hack, which will have to be removed when |
the array descriptor is reworked. Currently, we don't store the |
kind value for the type, but only the size. Because on targets with |
__float128, we have sizeof(logn double) == sizeof(__float128), |
we cannot discriminate here and have to fall back to the generic |
handling (which is suboptimal). */ |
#if !defined(GFC_REAL_16_IS_FLOAT128) |
# ifdef HAVE_GFC_REAL_10 |
case GFC_DTYPE_REAL_10: |
pack_r10 ((gfc_array_r10 *) ret, (gfc_array_r10 *) array, |
(gfc_array_l1 *) mask, (gfc_array_r10 *) vector); |
return; |
# endif |
|
# ifdef HAVE_GFC_REAL_16 |
case GFC_DTYPE_REAL_16: |
pack_r16 ((gfc_array_r16 *) ret, (gfc_array_r16 *) array, |
(gfc_array_l1 *) mask, (gfc_array_r16 *) vector); |
return; |
# endif |
#endif |
|
case GFC_DTYPE_COMPLEX_4: |
pack_c4 ((gfc_array_c4 *) ret, (gfc_array_c4 *) array, |
(gfc_array_l1 *) mask, (gfc_array_c4 *) vector); |
return; |
|
case GFC_DTYPE_COMPLEX_8: |
pack_c8 ((gfc_array_c8 *) ret, (gfc_array_c8 *) array, |
(gfc_array_l1 *) mask, (gfc_array_c8 *) vector); |
return; |
|
/* FIXME: This here is a hack, which will have to be removed when |
the array descriptor is reworked. Currently, we don't store the |
kind value for the type, but only the size. Because on targets with |
__float128, we have sizeof(logn double) == sizeof(__float128), |
we cannot discriminate here and have to fall back to the generic |
handling (which is suboptimal). */ |
#if !defined(GFC_REAL_16_IS_FLOAT128) |
# ifdef HAVE_GFC_COMPLEX_10 |
case GFC_DTYPE_COMPLEX_10: |
pack_c10 ((gfc_array_c10 *) ret, (gfc_array_c10 *) array, |
(gfc_array_l1 *) mask, (gfc_array_c10 *) vector); |
return; |
# endif |
|
# ifdef HAVE_GFC_COMPLEX_16 |
case GFC_DTYPE_COMPLEX_16: |
pack_c16 ((gfc_array_c16 *) ret, (gfc_array_c16 *) array, |
(gfc_array_l1 *) mask, (gfc_array_c16 *) vector); |
return; |
# endif |
#endif |
|
/* For derived types, let's check the actual alignment of the |
data pointers. If they are aligned, we can safely call |
the unpack functions. */ |
|
case GFC_DTYPE_DERIVED_2: |
if (GFC_UNALIGNED_2(ret->data) || GFC_UNALIGNED_2(array->data) |
|| (vector && GFC_UNALIGNED_2(vector->data))) |
break; |
else |
{ |
pack_i2 ((gfc_array_i2 *) ret, (gfc_array_i2 *) array, |
(gfc_array_l1 *) mask, (gfc_array_i2 *) vector); |
return; |
} |
|
case GFC_DTYPE_DERIVED_4: |
if (GFC_UNALIGNED_4(ret->data) || GFC_UNALIGNED_4(array->data) |
|| (vector && GFC_UNALIGNED_4(vector->data))) |
break; |
else |
{ |
pack_i4 ((gfc_array_i4 *) ret, (gfc_array_i4 *) array, |
(gfc_array_l1 *) mask, (gfc_array_i4 *) vector); |
return; |
} |
|
case GFC_DTYPE_DERIVED_8: |
if (GFC_UNALIGNED_8(ret->data) || GFC_UNALIGNED_8(array->data) |
|| (vector && GFC_UNALIGNED_8(vector->data))) |
break; |
else |
{ |
pack_i8 ((gfc_array_i8 *) ret, (gfc_array_i8 *) array, |
(gfc_array_l1 *) mask, (gfc_array_i8 *) vector); |
return; |
} |
|
#ifdef HAVE_GFC_INTEGER_16 |
case GFC_DTYPE_DERIVED_16: |
if (GFC_UNALIGNED_16(ret->data) || GFC_UNALIGNED_16(array->data) |
|| (vector && GFC_UNALIGNED_16(vector->data))) |
break; |
else |
{ |
pack_i16 ((gfc_array_i16 *) ret, (gfc_array_i16 *) array, |
(gfc_array_l1 *) mask, (gfc_array_i16 *) vector); |
return; |
} |
#endif |
|
} |
|
size = GFC_DESCRIPTOR_SIZE (array); |
pack_internal (ret, array, mask, vector, size); |
} |
|
|
extern void pack_char (gfc_array_char *, GFC_INTEGER_4, const gfc_array_char *, |
const gfc_array_l1 *, const gfc_array_char *, |
GFC_INTEGER_4, GFC_INTEGER_4); |
export_proto(pack_char); |
|
void |
pack_char (gfc_array_char *ret, |
GFC_INTEGER_4 ret_length __attribute__((unused)), |
const gfc_array_char *array, const gfc_array_l1 *mask, |
const gfc_array_char *vector, GFC_INTEGER_4 array_length, |
GFC_INTEGER_4 vector_length __attribute__((unused))) |
{ |
pack_internal (ret, array, mask, vector, array_length); |
} |
|
|
extern void pack_char4 (gfc_array_char *, GFC_INTEGER_4, const gfc_array_char *, |
const gfc_array_l1 *, const gfc_array_char *, |
GFC_INTEGER_4, GFC_INTEGER_4); |
export_proto(pack_char4); |
|
void |
pack_char4 (gfc_array_char *ret, |
GFC_INTEGER_4 ret_length __attribute__((unused)), |
const gfc_array_char *array, const gfc_array_l1 *mask, |
const gfc_array_char *vector, GFC_INTEGER_4 array_length, |
GFC_INTEGER_4 vector_length __attribute__((unused))) |
{ |
pack_internal (ret, array, mask, vector, array_length * sizeof (gfc_char4_t)); |
} |
|
|
static void |
pack_s_internal (gfc_array_char *ret, const gfc_array_char *array, |
const GFC_LOGICAL_4 *mask, const gfc_array_char *vector, |
index_type size) |
{ |
/* r.* indicates the return array. */ |
index_type rstride0; |
char *rptr; |
/* s.* indicates the source array. */ |
index_type sstride[GFC_MAX_DIMENSIONS]; |
index_type sstride0; |
const char *sptr; |
|
index_type count[GFC_MAX_DIMENSIONS]; |
index_type extent[GFC_MAX_DIMENSIONS]; |
index_type n; |
index_type dim; |
index_type ssize; |
index_type nelem; |
index_type total; |
|
dim = GFC_DESCRIPTOR_RANK (array); |
ssize = 1; |
for (n = 0; n < dim; n++) |
{ |
count[n] = 0; |
extent[n] = GFC_DESCRIPTOR_EXTENT(array,n); |
if (extent[n] < 0) |
extent[n] = 0; |
|
sstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(array,n); |
ssize *= extent[n]; |
} |
if (sstride[0] == 0) |
sstride[0] = size; |
|
sstride0 = sstride[0]; |
|
if (ssize != 0) |
sptr = array->data; |
else |
sptr = NULL; |
|
if (ret->data == NULL) |
{ |
/* Allocate the memory for the result. */ |
|
if (vector != NULL) |
{ |
/* The return array will have as many elements as there are |
in vector. */ |
total = GFC_DESCRIPTOR_EXTENT(vector,0); |
if (total <= 0) |
{ |
total = 0; |
vector = NULL; |
} |
} |
else |
{ |
if (*mask) |
{ |
/* The result array will have as many elements as the input |
array. */ |
total = extent[0]; |
for (n = 1; n < dim; n++) |
total *= extent[n]; |
} |
else |
/* The result array will be empty. */ |
total = 0; |
} |
|
/* Setup the array descriptor. */ |
GFC_DIMENSION_SET(ret->dim[0],0,total-1,1); |
|
ret->offset = 0; |
|
ret->data = internal_malloc_size (size * total); |
|
if (total == 0) |
return; |
} |
|
rstride0 = GFC_DESCRIPTOR_STRIDE_BYTES(ret,0); |
if (rstride0 == 0) |
rstride0 = size; |
rptr = ret->data; |
|
/* The remaining possibilities are now: |
If MASK is .TRUE., we have to copy the source array into the |
result array. We then have to fill it up with elements from VECTOR. |
If MASK is .FALSE., we have to copy VECTOR into the result |
array. If VECTOR were not present we would have already returned. */ |
|
if (*mask && ssize != 0) |
{ |
while (sptr) |
{ |
/* Add this element. */ |
memcpy (rptr, sptr, size); |
rptr += rstride0; |
|
/* Advance to the next element. */ |
sptr += sstride0; |
count[0]++; |
n = 0; |
while (count[n] == extent[n]) |
{ |
/* When we get to the end of a dimension, reset it and |
increment the next dimension. */ |
count[n] = 0; |
/* We could precalculate these products, but this is a |
less frequently used path so probably not worth it. */ |
sptr -= sstride[n] * extent[n]; |
n++; |
if (n >= dim) |
{ |
/* Break out of the loop. */ |
sptr = NULL; |
break; |
} |
else |
{ |
count[n]++; |
sptr += sstride[n]; |
} |
} |
} |
} |
|
/* Add any remaining elements from VECTOR. */ |
if (vector) |
{ |
n = GFC_DESCRIPTOR_EXTENT(vector,0); |
nelem = ((rptr - ret->data) / rstride0); |
if (n > nelem) |
{ |
sstride0 = GFC_DESCRIPTOR_STRIDE_BYTES(vector,0); |
if (sstride0 == 0) |
sstride0 = size; |
|
sptr = vector->data + sstride0 * nelem; |
n -= nelem; |
while (n--) |
{ |
memcpy (rptr, sptr, size); |
rptr += rstride0; |
sptr += sstride0; |
} |
} |
} |
} |
|
extern void pack_s (gfc_array_char *ret, const gfc_array_char *array, |
const GFC_LOGICAL_4 *, const gfc_array_char *); |
export_proto(pack_s); |
|
void |
pack_s (gfc_array_char *ret, const gfc_array_char *array, |
const GFC_LOGICAL_4 *mask, const gfc_array_char *vector) |
{ |
pack_s_internal (ret, array, mask, vector, GFC_DESCRIPTOR_SIZE (array)); |
} |
|
|
extern void pack_s_char (gfc_array_char *ret, GFC_INTEGER_4, |
const gfc_array_char *array, const GFC_LOGICAL_4 *, |
const gfc_array_char *, GFC_INTEGER_4, |
GFC_INTEGER_4); |
export_proto(pack_s_char); |
|
void |
pack_s_char (gfc_array_char *ret, |
GFC_INTEGER_4 ret_length __attribute__((unused)), |
const gfc_array_char *array, const GFC_LOGICAL_4 *mask, |
const gfc_array_char *vector, GFC_INTEGER_4 array_length, |
GFC_INTEGER_4 vector_length __attribute__((unused))) |
{ |
pack_s_internal (ret, array, mask, vector, array_length); |
} |
|
|
extern void pack_s_char4 (gfc_array_char *ret, GFC_INTEGER_4, |
const gfc_array_char *array, const GFC_LOGICAL_4 *, |
const gfc_array_char *, GFC_INTEGER_4, |
GFC_INTEGER_4); |
export_proto(pack_s_char4); |
|
void |
pack_s_char4 (gfc_array_char *ret, |
GFC_INTEGER_4 ret_length __attribute__((unused)), |
const gfc_array_char *array, const GFC_LOGICAL_4 *mask, |
const gfc_array_char *vector, GFC_INTEGER_4 array_length, |
GFC_INTEGER_4 vector_length __attribute__((unused))) |
{ |
pack_s_internal (ret, array, mask, vector, |
array_length * sizeof (gfc_char4_t)); |
} |
/string_intrinsics.c
0,0 → 1,102
/* String intrinsics helper functions. |
Copyright 2008, 2009 Free Software Foundation, Inc. |
|
This file is part of the GNU Fortran runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
|
/* Unlike what the name of this file suggests, we don't actually |
implement the Fortran intrinsics here. At least, not with the |
names they have in the standard. The functions here provide all |
the support we need for the standard string intrinsics, and the |
compiler translates the actual intrinsics calls to calls to |
functions in this file. */ |
|
#include "libgfortran.h" |
|
#include <stdlib.h> |
#include <string.h> |
#include <assert.h> |
|
|
/* Helper function to set parts of wide strings to a constant (usually |
spaces). */ |
|
static gfc_char4_t * |
memset_char4 (gfc_char4_t *b, gfc_char4_t c, size_t len) |
{ |
size_t i; |
|
for (i = 0; i < len; i++) |
b[i] = c; |
|
return b; |
} |
|
/* Compare wide character types, which are handled internally as |
unsigned 4-byte integers. */ |
int |
memcmp_char4 (const void *a, const void *b, size_t len) |
{ |
const GFC_UINTEGER_4 *pa = a; |
const GFC_UINTEGER_4 *pb = b; |
while (len-- > 0) |
{ |
if (*pa != *pb) |
return *pa < *pb ? -1 : 1; |
pa ++; |
pb ++; |
} |
return 0; |
} |
|
|
/* All other functions are defined using a few generic macros in |
string_intrinsics_inc.c, so we avoid code duplication between the |
various character type kinds. */ |
|
#undef CHARTYPE |
#define CHARTYPE char |
#undef UCHARTYPE |
#define UCHARTYPE unsigned char |
#undef SUFFIX |
#define SUFFIX(x) x |
#undef MEMSET |
#define MEMSET memset |
#undef MEMCMP |
#define MEMCMP memcmp |
|
#include "string_intrinsics_inc.c" |
|
|
#undef CHARTYPE |
#define CHARTYPE gfc_char4_t |
#undef UCHARTYPE |
#define UCHARTYPE gfc_char4_t |
#undef SUFFIX |
#define SUFFIX(x) x ## _char4 |
#undef MEMSET |
#define MEMSET memset_char4 |
#undef MEMCMP |
#define MEMCMP memcmp_char4 |
|
#include "string_intrinsics_inc.c" |
|
/move_alloc.c
0,0 → 1,66
/* Generic implementation of the MOVE_ALLOC intrinsic |
Copyright (C) 2006, 2007, 2009, 2011 Free Software Foundation, Inc. |
Contributed by Paul Thomas |
|
This file is part of the GNU Fortran runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Ligbfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
#include <stdlib.h> |
|
|
extern void move_alloc (gfc_array_char *, gfc_array_char *); |
export_proto(move_alloc); |
|
void |
move_alloc (gfc_array_char * from, gfc_array_char * to) |
{ |
int i; |
|
free (to->data); |
|
for (i = 0; i < GFC_DESCRIPTOR_RANK (from); i++) |
{ |
GFC_DIMENSION_SET(to->dim[i],GFC_DESCRIPTOR_LBOUND(from,i), |
GFC_DESCRIPTOR_UBOUND(from,i), |
GFC_DESCRIPTOR_STRIDE(from,i)); |
GFC_DIMENSION_SET(from->dim[i],GFC_DESCRIPTOR_LBOUND(from,i), |
GFC_DESCRIPTOR_LBOUND(from,i), 0); |
} |
|
to->offset = from->offset; |
to->dtype = from->dtype; |
to->data = from->data; |
from->data = NULL; |
} |
|
extern void move_alloc_c (gfc_array_char *, GFC_INTEGER_4, |
gfc_array_char *, GFC_INTEGER_4); |
export_proto(move_alloc_c); |
|
void |
move_alloc_c (gfc_array_char * from, |
GFC_INTEGER_4 from_length __attribute__((unused)), |
gfc_array_char * to, |
GFC_INTEGER_4 to_length __attribute__((unused))) |
{ |
move_alloc (from, to); |
} |
/iso_c_generated_procs.c
0,0 → 1,466
/* Implementation of the ISO_C_BINDING library helper generated functions. |
Copyright (C) 2007, 2009, 2010 Free Software Foundation, Inc. |
Contributed by Christopher Rickett. |
|
This file is part of the GNU Fortran 95 runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
|
#include "libgfortran.h" |
#include "iso_c_binding.h" |
|
|
/* TODO: This file needs to be finished so that a function is provided |
for all possible type/kind combinations! */ |
|
#ifdef HAVE_GFC_INTEGER_1 |
void ISO_C_BINDING_PREFIX (c_f_pointer_i1) (void *, gfc_array_void *, |
const array_t *); |
#endif |
|
#ifdef HAVE_GFC_INTEGER_2 |
void ISO_C_BINDING_PREFIX (c_f_pointer_i2) (void *, gfc_array_void *, |
const array_t *); |
#endif |
|
#ifdef HAVE_GFC_INTEGER_4 |
void ISO_C_BINDING_PREFIX (c_f_pointer_i4) (void *, gfc_array_void *, |
const array_t *); |
#endif |
|
#ifdef HAVE_GFC_INTEGER_8 |
void ISO_C_BINDING_PREFIX (c_f_pointer_i8) (void *, gfc_array_void *, |
const array_t *); |
#endif |
|
#ifdef HAVE_GFC_INTEGER_16 |
void ISO_C_BINDING_PREFIX (c_f_pointer_i16) (void *, gfc_array_void *, |
const array_t *); |
#endif |
|
#ifdef HAVE_GFC_REAL_4 |
void ISO_C_BINDING_PREFIX (c_f_pointer_r4) (void *, gfc_array_void *, |
const array_t *); |
#endif |
|
#ifdef HAVE_GFC_REAL_8 |
void ISO_C_BINDING_PREFIX (c_f_pointer_r8) (void *, gfc_array_void *, |
const array_t *); |
#endif |
|
#ifdef HAVE_GFC_REAL_10 |
void ISO_C_BINDING_PREFIX (c_f_pointer_r10) (void *, gfc_array_void *, |
const array_t *); |
#endif |
|
#ifdef HAVE_GFC_REAL_16 |
void ISO_C_BINDING_PREFIX (c_f_pointer_r16) (void *, gfc_array_void *, |
const array_t *); |
#endif |
|
#ifdef HAVE_GFC_COMPLEX_4 |
void ISO_C_BINDING_PREFIX (c_f_pointer_c4) (void *, gfc_array_void *, |
const array_t *); |
#endif |
|
#ifdef HAVE_GFC_COMPLEX_8 |
void ISO_C_BINDING_PREFIX (c_f_pointer_c8) (void *, gfc_array_void *, |
const array_t *); |
#endif |
|
#ifdef HAVE_GFC_COMPLEX_10 |
void ISO_C_BINDING_PREFIX (c_f_pointer_c10) (void *, gfc_array_void *, |
const array_t *); |
#endif |
|
#ifdef HAVE_GFC_COMPLEX_16 |
void ISO_C_BINDING_PREFIX (c_f_pointer_c16) (void *, gfc_array_void *, |
const array_t *); |
#endif |
|
#ifdef GFC_DEFAULT_CHAR |
void ISO_C_BINDING_PREFIX (c_f_pointer_s0) (void *, gfc_array_void *, |
const array_t *); |
#endif |
|
#ifdef HAVE_GFC_LOGICAL_1 |
void ISO_C_BINDING_PREFIX (c_f_pointer_l1) (void *, gfc_array_void *, |
const array_t *); |
#endif |
|
#ifdef HAVE_GFC_LOGICAL_2 |
void ISO_C_BINDING_PREFIX (c_f_pointer_l2) (void *, gfc_array_void *, |
const array_t *); |
#endif |
|
#ifdef HAVE_GFC_LOGICAL_4 |
void ISO_C_BINDING_PREFIX (c_f_pointer_l4) (void *, gfc_array_void *, |
const array_t *); |
#endif |
|
#ifdef HAVE_GFC_LOGICAL_8 |
void ISO_C_BINDING_PREFIX (c_f_pointer_l8) (void *, gfc_array_void *, |
const array_t *); |
#endif |
|
|
#ifdef HAVE_GFC_INTEGER_1 |
/* Set the given Fortran pointer, 'f_ptr_out', to point to the given C |
address, 'c_ptr_in'. The Fortran pointer is of type integer and |
kind=1. The function c_f_pointer is used to set up the pointer |
descriptor. shape is a one-dimensional array of integers |
specifying the upper bounds of the array pointed to by the given C |
address, if applicable. 'shape' is an optional parameter in |
Fortran, so if the user does not provide it, it will come in here |
as NULL. */ |
|
void |
ISO_C_BINDING_PREFIX (c_f_pointer_i1) (void *c_ptr_in, |
gfc_array_void *f_ptr_out, |
const array_t *shape) |
{ |
/* Here we have an integer(kind=1). */ |
ISO_C_BINDING_PREFIX (c_f_pointer) (c_ptr_in, f_ptr_out, shape, |
(int) BT_INTEGER, |
(int) sizeof (GFC_INTEGER_1)); |
} |
#endif |
|
|
#ifdef HAVE_GFC_INTEGER_2 |
/* Set the given Fortran pointer, 'f_ptr_out', to point to the given C |
address, 'c_ptr_in'. The Fortran pointer is of type integer and |
kind=2. The function c_f_pointer is used to set up the pointer |
descriptor. shape is a one-dimensional array of integers |
specifying the upper bounds of the array pointed to by the given C |
address, if applicable. 'shape' is an optional parameter in |
Fortran, so if the user does not provide it, it will come in here |
as NULL. */ |
|
void |
ISO_C_BINDING_PREFIX (c_f_pointer_i2) (void *c_ptr_in, |
gfc_array_void *f_ptr_out, |
const array_t *shape) |
{ |
/* Here we have an integer(kind=2). */ |
ISO_C_BINDING_PREFIX (c_f_pointer) (c_ptr_in, f_ptr_out, shape, |
(int) BT_INTEGER, |
(int) sizeof (GFC_INTEGER_2)); |
} |
#endif |
|
|
#ifdef HAVE_GFC_INTEGER_4 |
/* Set the given Fortran pointer, f_ptr_out, to point to the given C |
address, c_ptr_in. The Fortran pointer is of type integer and |
kind=4. The function c_f_pointer is used to set up the pointer |
descriptor. */ |
|
void |
ISO_C_BINDING_PREFIX (c_f_pointer_i4) (void *c_ptr_in, |
gfc_array_void *f_ptr_out, |
const array_t *shape) |
{ |
/* Here we have an integer(kind=4). */ |
ISO_C_BINDING_PREFIX (c_f_pointer) (c_ptr_in, f_ptr_out, shape, |
(int) BT_INTEGER, |
(int) sizeof (GFC_INTEGER_4)); |
} |
#endif |
|
|
#ifdef HAVE_GFC_INTEGER_8 |
/* Set the given Fortran pointer, f_ptr_out, to point to the given C |
address, c_ptr_in. The Fortran pointer is of type integer and |
kind=8. The function c_f_pointer is used to set up the pointer |
descriptor. */ |
|
void |
ISO_C_BINDING_PREFIX (c_f_pointer_i8) (void *c_ptr_in, |
gfc_array_void *f_ptr_out, |
const array_t *shape) |
{ |
/* Here we have an integer(kind=8). */ |
ISO_C_BINDING_PREFIX (c_f_pointer) (c_ptr_in, f_ptr_out, shape, |
(int) BT_INTEGER, |
(int) sizeof (GFC_INTEGER_8)); |
} |
#endif |
|
|
#ifdef HAVE_GFC_INTEGER_16 |
/* Set the given Fortran pointer, 'f_ptr_out', to point to the given C |
address, 'c_ptr_in'. The Fortran pointer is of type integer and |
kind=16. The function c_f_pointer is used to set up the pointer |
descriptor. shape is a one-dimensional array of integers |
specifying the upper bounds of the array pointed to by the given C |
address, if applicable. 'shape' is an optional parameter in |
Fortran, so if the user does not provide it, it will come in here |
as NULL. */ |
|
void |
ISO_C_BINDING_PREFIX (c_f_pointer_i16) (void *c_ptr_in, |
gfc_array_void *f_ptr_out, |
const array_t *shape) |
{ |
/* Here we have an integer(kind=16). */ |
ISO_C_BINDING_PREFIX (c_f_pointer) (c_ptr_in, f_ptr_out, shape, |
(int) BT_INTEGER, |
(int) sizeof (GFC_INTEGER_16)); |
} |
#endif |
|
|
#ifdef HAVE_GFC_REAL_4 |
/* Set the given Fortran pointer, f_ptr_out, to point to the given C |
address, c_ptr_in. The Fortran pointer is of type real and |
kind=4. The function c_f_pointer is used to set up the pointer |
descriptor. */ |
|
void |
ISO_C_BINDING_PREFIX (c_f_pointer_r4) (void *c_ptr_in, |
gfc_array_void *f_ptr_out, |
const array_t *shape) |
{ |
/* Here we have an real(kind=4). */ |
ISO_C_BINDING_PREFIX (c_f_pointer) (c_ptr_in, f_ptr_out, shape, |
(int) BT_REAL, |
(int) sizeof (GFC_REAL_4)); |
} |
#endif |
|
|
#ifdef HAVE_GFC_REAL_8 |
/* Set the given Fortran pointer, f_ptr_out, to point to the given C |
address, c_ptr_in. The Fortran pointer is of type real and |
kind=8. The function c_f_pointer is used to set up the pointer |
descriptor. */ |
|
void |
ISO_C_BINDING_PREFIX (c_f_pointer_r8) (void *c_ptr_in, |
gfc_array_void *f_ptr_out, |
const array_t *shape) |
{ |
/* Here we have an real(kind=8). */ |
ISO_C_BINDING_PREFIX (c_f_pointer) (c_ptr_in, f_ptr_out, shape, |
(int) BT_REAL, |
(int) sizeof (GFC_REAL_8)); |
} |
#endif |
|
|
#ifdef HAVE_GFC_REAL_10 |
/* Set the given Fortran pointer, f_ptr_out, to point to the given C |
address, c_ptr_in. The Fortran pointer is of type real and |
kind=10. The function c_f_pointer is used to set up the pointer |
descriptor. */ |
|
void |
ISO_C_BINDING_PREFIX (c_f_pointer_r10) (void *c_ptr_in, |
gfc_array_void *f_ptr_out, |
const array_t *shape) |
{ |
/* Here we have an real(kind=10). */ |
ISO_C_BINDING_PREFIX (c_f_pointer) (c_ptr_in, f_ptr_out, shape, |
(int) BT_REAL, |
(int) sizeof (GFC_REAL_10)); |
} |
#endif |
|
|
#ifdef HAVE_GFC_REAL_16 |
/* Set the given Fortran pointer, f_ptr_out, to point to the given C |
address, c_ptr_in. The Fortran pointer is of type real and |
kind=16. The function c_f_pointer is used to set up the pointer |
descriptor. */ |
|
void |
ISO_C_BINDING_PREFIX (c_f_pointer_r16) (void *c_ptr_in, |
gfc_array_void *f_ptr_out, |
const array_t *shape) |
{ |
/* Here we have an real(kind=16). */ |
ISO_C_BINDING_PREFIX (c_f_pointer) (c_ptr_in, f_ptr_out, shape, |
(int) BT_REAL, |
(int) sizeof (GFC_REAL_16)); |
} |
#endif |
|
|
#ifdef HAVE_GFC_COMPLEX_4 |
/* Set the given Fortran pointer, f_ptr_out, to point to the given C |
address, c_ptr_in. The Fortran pointer is of type complex and |
kind=4. The function c_f_pointer is used to set up the pointer |
descriptor. */ |
|
void |
ISO_C_BINDING_PREFIX (c_f_pointer_c4) (void *c_ptr_in, |
gfc_array_void *f_ptr_out, |
const array_t *shape) |
{ |
/* Here we have an complex(kind=4). */ |
ISO_C_BINDING_PREFIX (c_f_pointer) (c_ptr_in, f_ptr_out, shape, |
(int) BT_COMPLEX, |
(int) sizeof (GFC_COMPLEX_4)); |
} |
#endif |
|
|
#ifdef HAVE_GFC_COMPLEX_8 |
/* Set the given Fortran pointer, f_ptr_out, to point to the given C |
address, c_ptr_in. The Fortran pointer is of type complex and |
kind=8. The function c_f_pointer is used to set up the pointer |
descriptor. */ |
|
void |
ISO_C_BINDING_PREFIX (c_f_pointer_c8) (void *c_ptr_in, |
gfc_array_void *f_ptr_out, |
const array_t *shape) |
{ |
/* Here we have an complex(kind=8). */ |
ISO_C_BINDING_PREFIX (c_f_pointer) (c_ptr_in, f_ptr_out, shape, |
(int) BT_COMPLEX, |
(int) sizeof (GFC_COMPLEX_8)); |
} |
#endif |
|
|
#ifdef HAVE_GFC_COMPLEX_10 |
/* Set the given Fortran pointer, f_ptr_out, to point to the given C |
address, c_ptr_in. The Fortran pointer is of type complex and |
kind=10. The function c_f_pointer is used to set up the pointer |
descriptor. */ |
|
void |
ISO_C_BINDING_PREFIX (c_f_pointer_c10) (void *c_ptr_in, |
gfc_array_void *f_ptr_out, |
const array_t *shape) |
{ |
/* Here we have an complex(kind=10). */ |
ISO_C_BINDING_PREFIX (c_f_pointer) (c_ptr_in, f_ptr_out, shape, |
(int) BT_COMPLEX, |
(int) sizeof (GFC_COMPLEX_10)); |
} |
#endif |
|
|
#ifdef HAVE_GFC_COMPLEX_16 |
/* Set the given Fortran pointer, f_ptr_out, to point to the given C |
address, c_ptr_in. The Fortran pointer is of type complex and |
kind=16. The function c_f_pointer is used to set up the pointer |
descriptor. */ |
|
void |
ISO_C_BINDING_PREFIX (c_f_pointer_c16) (void *c_ptr_in, |
gfc_array_void *f_ptr_out, |
const array_t *shape) |
{ |
/* Here we have an complex(kind=16). */ |
ISO_C_BINDING_PREFIX (c_f_pointer) (c_ptr_in, f_ptr_out, shape, |
(int) BT_COMPLEX, |
(int) sizeof (GFC_COMPLEX_16)); |
} |
#endif |
|
|
#ifdef GFC_DEFAULT_CHAR |
/* Set the given Fortran pointer, f_ptr_out, to point to the given C |
address, c_ptr_in. The Fortran pointer is of type character. */ |
|
void |
ISO_C_BINDING_PREFIX (c_f_pointer_s0) (void *c_ptr_in, |
gfc_array_void *f_ptr_out, |
const array_t *shape) |
{ |
/* Here we have a character string of len=1. */ |
ISO_C_BINDING_PREFIX (c_f_pointer) (c_ptr_in, f_ptr_out, shape, |
(int) BT_CHARACTER, |
(int) sizeof (char)); |
} |
#endif |
|
|
#ifdef HAVE_GFC_LOGICAL_1 |
/* Set the given Fortran pointer, f_ptr_out, to point to the given C |
address, c_ptr_in. The Fortran pointer is of type logical, kind=1. */ |
|
void |
ISO_C_BINDING_PREFIX (c_f_pointer_l1) (void *c_ptr_in, |
gfc_array_void *f_ptr_out, |
const array_t *shape) |
{ |
/* Here we have a logical of kind=1. */ |
ISO_C_BINDING_PREFIX (c_f_pointer) (c_ptr_in, f_ptr_out, shape, |
(int) BT_LOGICAL, |
(int) sizeof (GFC_LOGICAL_1)); |
} |
#endif |
|
|
#ifdef HAVE_GFC_LOGICAL_2 |
/* Set the given Fortran pointer, f_ptr_out, to point to the given C |
address, c_ptr_in. The Fortran pointer is of type logical, kind=2. */ |
|
void |
ISO_C_BINDING_PREFIX (c_f_pointer_l2) (void *c_ptr_in, |
gfc_array_void *f_ptr_out, |
const array_t *shape) |
{ |
/* Here we have a logical of kind=2. */ |
ISO_C_BINDING_PREFIX (c_f_pointer) (c_ptr_in, f_ptr_out, shape, |
(int) BT_LOGICAL, |
(int) sizeof (GFC_LOGICAL_2)); |
} |
#endif |
|
|
#ifdef HAVE_GFC_LOGICAL_4 |
/* Set the given Fortran pointer, f_ptr_out, to point to the given C |
address, c_ptr_in. The Fortran pointer is of type logical, kind=4. */ |
|
void |
ISO_C_BINDING_PREFIX (c_f_pointer_l4) (void *c_ptr_in, |
gfc_array_void *f_ptr_out, |
const array_t *shape) |
{ |
/* Here we have a logical of kind=4. */ |
ISO_C_BINDING_PREFIX (c_f_pointer) (c_ptr_in, f_ptr_out, shape, |
(int) BT_LOGICAL, |
(int) sizeof (GFC_LOGICAL_4)); |
} |
#endif |
|
|
#ifdef HAVE_GFC_LOGICAL_8 |
/* Set the given Fortran pointer, f_ptr_out, to point to the given C |
address, c_ptr_in. The Fortran pointer is of type logical, kind=8. */ |
|
void |
ISO_C_BINDING_PREFIX (c_f_pointer_l8) (void *c_ptr_in, |
gfc_array_void *f_ptr_out, |
const array_t *shape) |
{ |
/* Here we have a logical of kind=8. */ |
ISO_C_BINDING_PREFIX (c_f_pointer) (c_ptr_in, f_ptr_out, shape, |
(int) BT_LOGICAL, |
(int) sizeof (GFC_LOGICAL_8)); |
} |
#endif |
/getlog.c
0,0 → 1,122
/* Implementation of the GETLOG g77 intrinsic. |
Copyright (C) 2005, 2007, 2009, 2011 Free Software Foundation, Inc. |
Contributed by François-Xavier Coudert <coudert@clipper.ens.fr> |
|
This file is part of the GNU Fortran runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
|
#include <stdlib.h> |
#include <string.h> |
|
#ifdef HAVE_UNISTD_H |
# if defined __MINGW32__ && defined HAVE_GETLOGIN |
# define _POSIX 1 |
# endif |
#include <unistd.h> |
#endif |
#ifdef HAVE_PWD_H |
#include <pwd.h> |
#endif |
|
/* Windows32 version */ |
#if defined __MINGW32__ && !defined HAVE_GETLOGIN |
#define WIN32_LEAN_AND_MEAN |
#include <windows.h> |
#include <lmcons.h> /* for UNLEN */ |
|
static char * |
w32_getlogin (void) |
{ |
static char name [UNLEN + 1]; |
DWORD namelen = sizeof (name); |
|
GetUserName (name, &namelen); |
return (name[0] == 0 ? NULL : name); |
} |
|
#undef getlogin |
#define getlogin w32_getlogin |
#define HAVE_GETLOGIN 1 |
|
#endif |
|
|
/* GETLOG (LOGIN), g77 intrinsic for retrieving the login name for the |
process. |
CHARACTER(len=*), INTENT(OUT) :: LOGIN */ |
|
void PREFIX(getlog) (char *, gfc_charlen_type); |
export_proto_np(PREFIX(getlog)); |
|
void |
PREFIX(getlog) (char * login, gfc_charlen_type login_len) |
{ |
int p_len; |
char *p; |
|
memset (login, ' ', login_len); /* Blank the string. */ |
|
#if defined(HAVE_POSIX_GETPWUID_R) && defined(HAVE_GETEUID) |
struct passwd pwd; |
struct passwd *result; |
char *buf; |
int err; |
/* To be pedantic, buflen should be determined by |
sysconf(_SC_GETPW_R_SIZE_MAX), which is 1024 on some tested |
targets; we do something simple in case the target doesn't |
support sysconf. */ |
static const size_t buflen = 1024; |
buf = get_mem (buflen); |
err = getpwuid_r (geteuid (), &pwd, buf, buflen, &result); |
if (err != 0 || result == NULL) |
goto cleanup; |
p = pwd.pw_name; |
#elif defined(HAVE_GETPWUID) && defined(HAVE_GETEUID) |
{ |
struct passwd *pw = getpwuid (geteuid ()); |
if (pw) |
p = pw->pw_name; |
else |
return; |
} |
#elif HAVE_GETLOGIN |
p = getlogin(); |
# else |
return; |
#endif |
|
if (p == NULL) |
goto cleanup; |
|
p_len = strlen (p); |
if (login_len < p_len) |
p_len = login_len; |
memcpy (login, p, p_len); |
|
cleanup: |
#if defined (HAVE_POSIX_GETPWUID_R) && defined(HAVE_GETEUID) |
free (buf); |
#else |
; |
#endif |
} |
/selected_int_kind.f90
0,0 → 1,46
! Copyright 2003, 2004, 2009 Free Software Foundation, Inc. |
! Contributed by Kejia Zhao <kejia_zh@yahoo.com.cn> |
! |
!This file is part of the GNU Fortran 95 runtime library (libgfortran). |
! |
!Libgfortran is free software; you can redistribute it and/or |
!modify it under the terms of the GNU General Public |
!License as published by the Free Software Foundation; either |
!version 3 of the License, or (at your option) any later version. |
! |
!Libgfortran is distributed in the hope that it will be useful, |
!but WITHOUT ANY WARRANTY; without even the implied warranty of |
!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
!GNU General Public License for more details. |
! |
!Under Section 7 of GPL version 3, you are granted additional |
!permissions described in the GCC Runtime Library Exception, version |
!3.1, as published by the Free Software Foundation. |
! |
!You should have received a copy of the GNU General Public License and |
!a copy of the GCC Runtime Library Exception along with this program; |
!see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
!<http://www.gnu.org/licenses/>. |
|
function _gfortran_selected_int_kind (r) |
implicit none |
integer, intent (in) :: r |
integer :: _gfortran_selected_int_kind |
integer :: i |
! Integer kind_range table |
type :: int_info |
integer :: kind |
integer :: range |
end type int_info |
|
include "selected_int_kind.inc" |
|
do i = 1, c |
if (r <= int_infos (i) % range) then |
_gfortran_selected_int_kind = int_infos (i) % kind |
return |
end if |
end do |
_gfortran_selected_int_kind = -1 |
return |
end function |
/time.c
0,0 → 1,50
/* Implementation of the TIME and TIME8 g77 intrinsics. |
Copyright (C) 2005, 2007, 2009, 2011 Free Software Foundation, Inc. |
Contributed by François-Xavier Coudert <coudert@clipper.ens.fr> |
|
This file is part of the GNU Fortran runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
#include <time.h> |
|
|
/* INTEGER(KIND=4) FUNCTION TIME() */ |
|
extern GFC_INTEGER_4 time_func (void); |
export_proto(time_func); |
|
GFC_INTEGER_4 |
time_func (void) |
{ |
return (GFC_INTEGER_4) time (NULL); |
} |
|
/* INTEGER(KIND=8) FUNCTION TIME8() */ |
|
extern GFC_INTEGER_8 time8_func (void); |
export_proto(time8_func); |
|
GFC_INTEGER_8 |
time8_func (void) |
{ |
return (GFC_INTEGER_8) time (NULL); |
} |
/gerror.c
0,0 → 1,57
/* Implementation of the GERROR g77 intrinsic. |
Copyright (C) 2005, 2007, 2009, 2011 Free Software Foundation, Inc. |
Contributed by François-Xavier Coudert <coudert@clipper.ens.fr> |
|
This file is part of the GNU Fortran runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
|
#include <errno.h> |
#include <string.h> |
|
|
/* GERROR (MESSAGE), g77 intrinsic for retrieving the system error |
message corresponding to the last system error (C errno). |
CHARACTER(len=*), INTENT(OUT) :: MESSAGE */ |
|
void PREFIX(gerror) (char *, gfc_charlen_type); |
export_proto_np(PREFIX(gerror)); |
|
void |
PREFIX(gerror) (char * msg, gfc_charlen_type msg_len) |
{ |
int p_len; |
char *p; |
|
p = gf_strerror (errno, msg, msg_len); |
p_len = strlen (p); |
/* The returned pointer p might or might not be the same as the msg |
argument. */ |
if (p != msg) |
{ |
if (msg_len < p_len) |
p_len = msg_len; |
memcpy (msg, p, p_len); |
} |
if (msg_len > p_len) |
memset (&msg[p_len], ' ', msg_len - p_len); |
} |
/access.c
0,0 → 1,90
/* Implementation of the ACCESS intrinsic. |
Copyright (C) 2006, 2007, 2009 Free Software Foundation, Inc. |
Contributed by François-Xavier Coudert <coudert@clipper.ens.fr> |
|
This file is part of the GNU Fortran 95 runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
|
#include <errno.h> |
#include <string.h> |
|
#ifdef HAVE_UNISTD_H |
#include <unistd.h> |
#endif |
|
/* INTEGER FUNCTION ACCESS(NAME, MODE) |
CHARACTER(len=*), INTENT(IN) :: NAME, MODE */ |
|
#ifdef HAVE_ACCESS |
extern int access_func (char *, char *, gfc_charlen_type, gfc_charlen_type); |
export_proto(access_func); |
|
int |
access_func (char *name, char *mode, gfc_charlen_type name_len, |
gfc_charlen_type mode_len) |
{ |
char * file; |
gfc_charlen_type i; |
int m; |
|
/* Parse the MODE string. */ |
m = F_OK; |
for (i = 0; i < mode_len && mode[i]; i++) |
switch (mode[i]) |
{ |
case ' ': |
break; |
|
case 'r': |
case 'R': |
m |= R_OK; |
break; |
|
case 'w': |
case 'W': |
m |= W_OK; |
break; |
|
case 'x': |
case 'X': |
m |= X_OK; |
break; |
|
default: |
return -1; |
break; |
} |
|
/* Trim trailing spaces from NAME argument. */ |
while (name_len > 0 && name[name_len - 1] == ' ') |
name_len--; |
|
/* Make a null terminated copy of the string. */ |
file = gfc_alloca (name_len + 1); |
memcpy (file, name, name_len); |
file[name_len] = '\0'; |
|
/* And make the call to access(). */ |
return (access (file, m) == 0 ? 0 : errno); |
} |
#endif |
/rename.c
0,0 → 1,125
/* Implementation of the RENAME intrinsic. |
Copyright (C) 2005, 2007, 2009 Free Software Foundation, Inc. |
Contributed by François-Xavier Coudert <coudert@clipper.ens.fr> |
|
This file is part of the GNU Fortran 95 runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
|
#include <errno.h> |
#include <string.h> |
|
/* SUBROUTINE RENAME(PATH1, PATH2, STATUS) |
CHARACTER(len=*), INTENT(IN) :: PATH1, PATH2 |
INTEGER, INTENT(OUT), OPTIONAL :: STATUS */ |
|
extern void rename_i4_sub (char *, char *, GFC_INTEGER_4 *, gfc_charlen_type, |
gfc_charlen_type); |
iexport_proto(rename_i4_sub); |
|
void |
rename_i4_sub (char *path1, char *path2, GFC_INTEGER_4 *status, |
gfc_charlen_type path1_len, gfc_charlen_type path2_len) |
{ |
int val; |
char *str1, *str2; |
|
/* Trim trailing spaces from paths. */ |
while (path1_len > 0 && path1[path1_len - 1] == ' ') |
path1_len--; |
while (path2_len > 0 && path2[path2_len - 1] == ' ') |
path2_len--; |
|
/* Make a null terminated copy of the strings. */ |
str1 = gfc_alloca (path1_len + 1); |
memcpy (str1, path1, path1_len); |
str1[path1_len] = '\0'; |
|
str2 = gfc_alloca (path2_len + 1); |
memcpy (str2, path2, path2_len); |
str2[path2_len] = '\0'; |
|
val = rename (str1, str2); |
|
if (status != NULL) |
*status = (val == 0) ? 0 : errno; |
} |
iexport(rename_i4_sub); |
|
extern void rename_i8_sub (char *, char *, GFC_INTEGER_8 *, gfc_charlen_type, |
gfc_charlen_type); |
iexport_proto(rename_i8_sub); |
|
void |
rename_i8_sub (char *path1, char *path2, GFC_INTEGER_8 *status, |
gfc_charlen_type path1_len, gfc_charlen_type path2_len) |
{ |
int val; |
char *str1, *str2; |
|
/* Trim trailing spaces from paths. */ |
while (path1_len > 0 && path1[path1_len - 1] == ' ') |
path1_len--; |
while (path2_len > 0 && path2[path2_len - 1] == ' ') |
path2_len--; |
|
/* Make a null terminated copy of the strings. */ |
str1 = gfc_alloca (path1_len + 1); |
memcpy (str1, path1, path1_len); |
str1[path1_len] = '\0'; |
|
str2 = gfc_alloca (path2_len + 1); |
memcpy (str2, path2, path2_len); |
str2[path2_len] = '\0'; |
|
val = rename (str1, str2); |
|
if (status != NULL) |
*status = (val == 0) ? 0 : errno; |
} |
iexport(rename_i8_sub); |
|
extern GFC_INTEGER_4 rename_i4 (char *, char *, gfc_charlen_type, |
gfc_charlen_type); |
export_proto(rename_i4); |
|
GFC_INTEGER_4 |
rename_i4 (char *path1, char *path2, gfc_charlen_type path1_len, |
gfc_charlen_type path2_len) |
{ |
GFC_INTEGER_4 val; |
rename_i4_sub (path1, path2, &val, path1_len, path2_len); |
return val; |
} |
|
extern GFC_INTEGER_8 rename_i8 (char *, char *, gfc_charlen_type, |
gfc_charlen_type); |
export_proto(rename_i8); |
|
GFC_INTEGER_8 |
rename_i8 (char *path1, char *path2, gfc_charlen_type path1_len, |
gfc_charlen_type path2_len) |
{ |
GFC_INTEGER_8 val; |
rename_i8_sub (path1, path2, &val, path1_len, path2_len); |
return val; |
} |
/abort.c
0,0 → 1,34
/* Implementation of the ABORT intrinsic. |
Copyright (C) 2003, 2004, 2005, 2006, 2007, 2009 Free Software Foundation, Inc. |
|
This file is part of the GNU Fortran 95 runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
#include <stdlib.h> |
|
void PREFIX(abort) (void); |
export_proto_np(PREFIX(abort)); |
|
void PREFIX(abort) (void) |
{ |
sys_abort (); |
} |
/selected_real_kind.f90
0,0 → 1,95
! Copyright 2003, 2004, 2009, 2010 Free Software Foundation, Inc. |
! Contributed by Kejia Zhao <kejia_zh@yahoo.com.cn> |
! |
!This file is part of the GNU Fortran runtime library (libgfortran). |
! |
!Libgfortran is free software; you can redistribute it and/or |
!modify it under the terms of the GNU General Public |
!License as published by the Free Software Foundation; either |
!version 3 of the License, or (at your option) any later version. |
! |
!Libgfortran is distributed in the hope that it will be useful, |
!but WITHOUT ANY WARRANTY; without even the implied warranty of |
!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
!GNU General Public License for more details. |
! |
!Under Section 7 of GPL version 3, you are granted additional |
!permissions described in the GCC Runtime Library Exception, version |
!3.1, as published by the Free Software Foundation. |
! |
!You should have received a copy of the GNU General Public License and |
!a copy of the GCC Runtime Library Exception along with this program; |
!see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
!<http://www.gnu.org/licenses/>. |
|
function _gfortran_selected_real_kind2008 (p, r, rdx) |
implicit none |
integer, optional, intent (in) :: p, r, rdx |
integer :: _gfortran_selected_real_kind2008 |
integer :: i, p2, r2, radix2 |
logical :: found_p, found_r, found_radix |
! Real kind_precision_range table |
type :: real_info |
integer :: kind |
integer :: precision |
integer :: range |
integer :: radix |
end type real_info |
|
include "selected_real_kind.inc" |
|
_gfortran_selected_real_kind2008 = 0 |
p2 = 0 |
r2 = 0 |
radix2 = 0 |
found_p = .false. |
found_r = .false. |
found_radix = .false. |
|
if (present (p)) p2 = p |
if (present (r)) r2 = r |
if (present (rdx)) radix2 = rdx |
|
! Assumes each type has a greater precision and range than previous one. |
|
do i = 1, c |
if (p2 <= real_infos (i) % precision) found_p = .true. |
if (r2 <= real_infos (i) % range) found_r = .true. |
if (radix2 <= real_infos (i) % radix) found_radix = .true. |
|
if (p2 <= real_infos (i) % precision & |
.and. r2 <= real_infos (i) % range & |
.and. radix2 <= real_infos (i) % radix) then |
_gfortran_selected_real_kind2008 = real_infos (i) % kind |
return |
end if |
end do |
|
if (found_radix .and. found_r .and. .not. found_p) then |
_gfortran_selected_real_kind2008 = -1 |
elseif (found_radix .and. found_p .and. .not. found_r) then |
_gfortran_selected_real_kind2008 = -2 |
elseif (found_radix .and. .not. found_p .and. .not. found_r) then |
_gfortran_selected_real_kind2008 = -3 |
elseif (found_radix) then |
_gfortran_selected_real_kind2008 = -4 |
else |
_gfortran_selected_real_kind2008 = -5 |
end if |
end function _gfortran_selected_real_kind2008 |
|
function _gfortran_selected_real_kind (p, r) |
implicit none |
integer, optional, intent (in) :: p, r |
integer :: _gfortran_selected_real_kind |
|
interface |
function _gfortran_selected_real_kind2008 (p, r, rdx) |
implicit none |
integer, optional, intent (in) :: p, r, rdx |
integer :: _gfortran_selected_real_kind2008 |
end function _gfortran_selected_real_kind2008 |
end interface |
|
_gfortran_selected_real_kind = _gfortran_selected_real_kind2008 (p, r) |
end function |
/f2c_specifics.F90
0,0 → 1,197
! Copyright 2002, 2005, 2009 Free Software Foundation, Inc. |
! Contributed by Tobias Schl"uter |
! |
!This file is part of the GNU Fortran 95 runtime library (libgfortran). |
! |
!GNU libgfortran is free software; you can redistribute it and/or |
!modify it under the terms of the GNU General Public |
!License as published by the Free Software Foundation; either |
!version 3 of the License, or (at your option) any later version. |
! |
!GNU libgfortran is distributed in the hope that it will be useful, |
!but WITHOUT ANY WARRANTY; without even the implied warranty of |
!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
!GNU General Public License for more details. |
! |
!Under Section 7 of GPL version 3, you are granted additional |
!permissions described in the GCC Runtime Library Exception, version |
!3.1, as published by the Free Software Foundation. |
! |
!You should have received a copy of the GNU General Public License and |
!a copy of the GCC Runtime Library Exception along with this program; |
!see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
!<http://www.gnu.org/licenses/>. |
|
! Specifics for the intrinsics whose calling conventions change if |
! -ff2c is used. |
! |
! There are two annoyances WRT the preprocessor: |
! - we're using -traditional-cpp, so we can't use the ## operator. |
! - macros expand to a single line, and Fortran lines can't be wider |
! than 132 characters, therefore we use two macros to split the lines |
! |
! The cases we need to implement are functions returning default REAL |
! or COMPLEX. The former need to return DOUBLE PRECISION instead of REAL, |
! the latter become subroutines returning via a hidden first argument. |
|
! one argument functions |
#define REAL_HEAD(NAME) \ |
elemental function _gfortran_f2c_specific__/**/NAME/**/_r4 (parm) result(res); |
|
#define REAL_BODY(NAME) \ |
REAL, intent (in) :: parm; \ |
DOUBLE PRECISION :: res; \ |
res = NAME (parm); \ |
end function |
|
#define COMPLEX_HEAD(NAME) \ |
subroutine _gfortran_f2c_specific__/**/NAME/**/_c4 (res, parm); |
|
#define COMPLEX_BODY(NAME) \ |
COMPLEX, intent (in) :: parm; \ |
COMPLEX, intent (out) :: res; \ |
res = NAME (parm); \ |
end subroutine |
|
#define DCOMPLEX_HEAD(NAME) \ |
subroutine _gfortran_f2c_specific__/**/NAME/**/_c8 (res, parm); |
|
#define DCOMPLEX_BODY(NAME) \ |
DOUBLE COMPLEX, intent (in) :: parm; \ |
DOUBLE COMPLEX, intent (out) :: res; \ |
res = NAME (parm); \ |
end subroutine |
|
REAL_HEAD(abs) |
REAL_BODY(abs) |
|
! abs is special in that the result is real |
elemental function _gfortran_f2c_specific__abs_c4 (parm) result (res) |
COMPLEX, intent(in) :: parm |
DOUBLE PRECISION :: res |
res = abs(parm) |
end function |
|
|
! aimag is special in that the result is real |
elemental function _gfortran_f2c_specific__aimag_c4 (parm) |
complex(kind=4), intent(in) :: parm |
double precision :: _gfortran_f2c_specific__aimag_c4 |
_gfortran_f2c_specific__aimag_c4 = aimag(parm) |
end function |
|
elemental function _gfortran_f2c_specific__aimag_c8 (parm) |
complex(kind=8), intent(in) :: parm |
double precision :: _gfortran_f2c_specific__aimag_c8 |
_gfortran_f2c_specific__aimag_c8 = aimag(parm) |
end function |
|
|
REAL_HEAD(exp) |
REAL_BODY(exp) |
COMPLEX_HEAD(exp) |
COMPLEX_BODY(exp) |
DCOMPLEX_HEAD(exp) |
DCOMPLEX_BODY(exp) |
|
REAL_HEAD(log) |
REAL_BODY(log) |
COMPLEX_HEAD(log) |
COMPLEX_BODY(log) |
DCOMPLEX_HEAD(log) |
DCOMPLEX_BODY(log) |
|
REAL_HEAD(log10) |
REAL_BODY(log10) |
|
REAL_HEAD(sqrt) |
REAL_BODY(sqrt) |
COMPLEX_HEAD(sqrt) |
COMPLEX_BODY(sqrt) |
DCOMPLEX_HEAD(sqrt) |
DCOMPLEX_BODY(sqrt) |
|
REAL_HEAD(asin) |
REAL_BODY(asin) |
|
REAL_HEAD(acos) |
REAL_BODY(acos) |
|
REAL_HEAD(atan) |
REAL_BODY(atan) |
|
REAL_HEAD(asinh) |
REAL_BODY(asinh) |
|
REAL_HEAD(acosh) |
REAL_BODY(acosh) |
|
REAL_HEAD(atanh) |
REAL_BODY(atanh) |
|
REAL_HEAD(sin) |
REAL_BODY(sin) |
COMPLEX_HEAD(sin) |
COMPLEX_BODY(sin) |
DCOMPLEX_HEAD(sin) |
DCOMPLEX_BODY(sin) |
|
REAL_HEAD(cos) |
REAL_BODY(cos) |
COMPLEX_HEAD(cos) |
COMPLEX_BODY(cos) |
DCOMPLEX_HEAD(cos) |
DCOMPLEX_BODY(cos) |
|
REAL_HEAD(tan) |
REAL_BODY(tan) |
|
REAL_HEAD(sinh) |
REAL_BODY(sinh) |
|
REAL_HEAD(cosh) |
REAL_BODY(cosh) |
|
REAL_HEAD(tanh) |
REAL_BODY(tanh) |
|
REAL_HEAD(aint) |
REAL_BODY(aint) |
|
REAL_HEAD(anint) |
REAL_BODY(anint) |
|
! two argument functions |
#define REAL2_HEAD(NAME) \ |
elemental function _gfortran_f2c_specific__/**/NAME/**/_r4 (p1, p2) result(res); |
|
#define REAL2_BODY(NAME) \ |
REAL, intent (in) :: p1, p2; \ |
DOUBLE PRECISION :: res; \ |
res = NAME (p1, p2); \ |
end function |
|
REAL2_HEAD(sign) |
REAL2_BODY(sign) |
|
REAL2_HEAD(dim) |
REAL2_BODY(dim) |
|
REAL2_HEAD(atan2) |
REAL2_BODY(atan2) |
|
REAL2_HEAD(mod) |
REAL2_BODY(mod) |
|
! conjg is special-cased because it is not suffixed _c4 but _4 |
subroutine _gfortran_f2c_specific__conjg_4 (res, parm) |
COMPLEX, intent (in) :: parm |
COMPLEX, intent (out) :: res |
res = conjg (parm) |
end subroutine |
subroutine _gfortran_f2c_specific__conjg_8 (res, parm) |
DOUBLE COMPLEX, intent (in) :: parm |
DOUBLE COMPLEX, intent (out) :: res |
res = conjg (parm) |
end subroutine |
|
/ishftc.c
0,0 → 1,100
/* Implementation of ishftc intrinsic. |
Copyright 2002, 2004, 2009 Free Software Foundation, Inc. |
Contributed by Paul Brook <paul@nowt.org> |
|
This file is part of the GNU Fortran 95 runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
|
extern GFC_INTEGER_4 ishftc4 (GFC_INTEGER_4, GFC_INTEGER_4, GFC_INTEGER_4); |
export_proto(ishftc4); |
|
GFC_INTEGER_4 |
ishftc4 (GFC_INTEGER_4 i, GFC_INTEGER_4 shift, GFC_INTEGER_4 size) |
{ |
GFC_UINTEGER_4 mask, bits; |
|
if (shift < 0) |
shift = shift + size; |
|
if (shift == 0 || shift == size) |
return i; |
|
/* In C, the result of the shift operator is undefined if the right operand |
is greater than or equal to the number of bits in the left operand. So we |
have to special case it for fortran. */ |
mask = ~((size == 32) ? (GFC_UINTEGER_4)0 : (~(GFC_UINTEGER_4)0 << size)); |
|
bits = i & mask; |
|
return (i & ~mask) | ((bits << shift) & mask) | (bits >> (size - shift)); |
} |
|
extern GFC_INTEGER_8 ishftc8 (GFC_INTEGER_8, GFC_INTEGER_4, GFC_INTEGER_4); |
export_proto(ishftc8); |
|
GFC_INTEGER_8 |
ishftc8 (GFC_INTEGER_8 i, GFC_INTEGER_4 shift, GFC_INTEGER_4 size) |
{ |
GFC_UINTEGER_8 mask, bits; |
|
if (shift < 0) |
shift = shift + size; |
|
if (shift == 0 || shift == size) |
return i; |
|
/* In C, the result of the shift operator is undefined if the right operand |
is greater than or equal to the number of bits in the left operand. So we |
have to special case it for fortran. */ |
mask = ~((size == 64) ? (GFC_UINTEGER_8)0 : (~(GFC_UINTEGER_8)0 << size)); |
|
bits = i & mask; |
|
return (i & ~mask) | ((bits << shift) & mask) | (bits >> (size - shift)); |
} |
|
#ifdef HAVE_GFC_INTEGER_16 |
extern GFC_INTEGER_16 ishftc16 (GFC_INTEGER_16, GFC_INTEGER_4, GFC_INTEGER_4); |
export_proto(ishftc16); |
|
GFC_INTEGER_16 |
ishftc16 (GFC_INTEGER_16 i, GFC_INTEGER_4 shift, GFC_INTEGER_4 size) |
{ |
GFC_UINTEGER_16 mask, bits; |
|
if (shift < 0) |
shift = shift + size; |
|
if (shift == 0 || shift == size) |
return i; |
|
/* In C, the result of the shift operator is undefined if the right operand |
is greater than or equal to the number of bits in the left operand. So we |
have to special case it for fortran. */ |
mask = ~((size == 128) ? (GFC_UINTEGER_16)0 : (~(GFC_UINTEGER_16)0 << size)); |
|
bits = i & mask; |
|
return (i & ~mask) | ((bits << shift) & mask) | (bits >> (size - shift)); |
} |
#endif |
/umask.c
0,0 → 1,90
/* Implementation of the UMASK intrinsic. |
Copyright (C) 2004, 2007, 2009, 2011 Free Software Foundation, Inc. |
Contributed by Steven G. Kargl <kargls@comcast.net>. |
|
This file is part of the GNU Fortran runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
|
#include "libgfortran.h" |
#include <stdlib.h> |
|
#ifdef HAVE_SYS_STAT_H |
#include <sys/stat.h> |
#endif |
|
#ifdef HAVE_UNISTD_H |
#include <unistd.h> |
#endif |
|
|
/* SUBROUTINE UMASK(MASK, OLD) |
INTEGER, INTENT(IN) :: MASK |
INTEGER, INTENT(OUT), OPTIONAL :: OLD */ |
|
extern void umask_i4_sub (GFC_INTEGER_4 *, GFC_INTEGER_4 *); |
iexport_proto(umask_i4_sub); |
|
void |
umask_i4_sub (GFC_INTEGER_4 *mask, GFC_INTEGER_4 *old) |
{ |
mode_t val = umask((mode_t) *mask); |
if (old != NULL) |
*old = (GFC_INTEGER_4) val; |
} |
iexport(umask_i4_sub); |
|
extern void umask_i8_sub (GFC_INTEGER_8 *, GFC_INTEGER_8 *); |
iexport_proto(umask_i8_sub); |
|
void |
umask_i8_sub (GFC_INTEGER_8 *mask, GFC_INTEGER_8 *old) |
{ |
mode_t val = umask((mode_t) *mask); |
if (old != NULL) |
*old = (GFC_INTEGER_8) val; |
} |
iexport(umask_i8_sub); |
|
/* INTEGER FUNCTION UMASK(MASK) |
INTEGER, INTENT(IN) :: MASK */ |
|
extern GFC_INTEGER_4 umask_i4 (GFC_INTEGER_4 *); |
export_proto(umask_i4); |
|
GFC_INTEGER_4 |
umask_i4 (GFC_INTEGER_4 *mask) |
{ |
GFC_INTEGER_4 old; |
umask_i4_sub (mask, &old); |
return old; |
} |
|
extern GFC_INTEGER_8 umask_i8 (GFC_INTEGER_8 *); |
export_proto(umask_i8); |
|
GFC_INTEGER_8 |
umask_i8 (GFC_INTEGER_8 *mask) |
{ |
GFC_INTEGER_8 old; |
umask_i8_sub (mask, &old); |
return old; |
} |
/bit_intrinsics.c
0,0 → 1,138
/* Implementation of the bit intrinsics not implemented as GCC builtins. |
Copyright (C) 2009 Free Software Foundation, Inc. |
|
This file is part of the GNU Fortran runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
|
|
#ifdef HAVE_GFC_INTEGER_16 |
extern int clz128 (GFC_INTEGER_16); |
export_proto(clz128); |
|
int |
clz128 (GFC_INTEGER_16 x) |
{ |
int res = 127; |
|
// We can't write 0xFFFFFFFFFFFFFFFF0000000000000000, so we work around it |
if (x & ((__uint128_t) 0xFFFFFFFFFFFFFFFF << 64)) |
{ |
res -= 64; |
x >>= 64; |
} |
|
if (x & 0xFFFFFFFF00000000) |
{ |
res -= 32; |
x >>= 32; |
} |
|
if (x & 0xFFFF0000) |
{ |
res -= 16; |
x >>= 16; |
} |
|
if (x & 0xFF00) |
{ |
res -= 8; |
x >>= 8; |
} |
|
if (x & 0xF0) |
{ |
res -= 4; |
x >>= 4; |
} |
|
if (x & 0xC) |
{ |
res -= 2; |
x >>= 2; |
} |
|
if (x & 0x2) |
{ |
res -= 1; |
x >>= 1; |
} |
|
return res; |
} |
#endif |
|
|
#ifdef HAVE_GFC_INTEGER_16 |
extern int ctz128 (GFC_INTEGER_16); |
export_proto(ctz128); |
|
int |
ctz128 (GFC_INTEGER_16 x) |
{ |
int res = 0; |
|
if ((x & 0xFFFFFFFFFFFFFFFF) == 0) |
{ |
res += 64; |
x >>= 64; |
} |
|
if ((x & 0xFFFFFFFF) == 0) |
{ |
res += 32; |
x >>= 32; |
} |
|
if ((x & 0xFFFF) == 0) |
{ |
res += 16; |
x >>= 16; |
} |
|
if ((x & 0xFF) == 0) |
{ |
res += 8; |
x >>= 8; |
} |
|
if ((x & 0xF) == 0) |
{ |
res += 4; |
x >>= 4; |
} |
|
if ((x & 0x3) == 0) |
{ |
res += 2; |
x >>= 2; |
} |
|
if ((x & 0x1) == 0) |
{ |
res += 1; |
x >>= 1; |
} |
|
return res; |
} |
#endif |
/erfc_scaled_inc.c
0,0 → 1,193
/* Implementation of the ERFC_SCALED intrinsic, to be included by erfc_scaled.c |
Copyright (c) 2008, 2010 Free Software Foundation, Inc. |
|
This file is part of the GNU Fortran runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR a PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
/* This implementation of ERFC_SCALED is based on the netlib algorithm |
available at http://www.netlib.org/specfun/erf */ |
|
#define TYPE KIND_SUFFIX(GFC_REAL_,KIND) |
#define CONCAT(x,y) x ## y |
#define KIND_SUFFIX(x,y) CONCAT(x,y) |
|
#if (KIND == 4) |
|
# define EXP(x) expf(x) |
# define TRUNC(x) truncf(x) |
|
#elif (KIND == 8) |
|
# define EXP(x) exp(x) |
# define TRUNC(x) trunc(x) |
|
#elif (KIND == 10) || (KIND == 16 && defined(GFC_REAL_16_IS_LONG_DOUBLE)) |
|
# ifdef HAVE_EXPL |
# define EXP(x) expl(x) |
# endif |
# ifdef HAVE_TRUNCL |
# define TRUNC(x) truncl(x) |
# endif |
|
#elif (KIND == 16 && defined(GFC_REAL_16_IS_FLOAT128)) |
|
# define EXP(x) expq(x) |
# define TRUNC(x) truncq(x) |
|
#else |
|
# error "What exactly is it that you want me to do?" |
|
#endif |
|
#if defined(EXP) && defined(TRUNC) |
|
extern TYPE KIND_SUFFIX(erfc_scaled_r,KIND) (TYPE); |
export_proto(KIND_SUFFIX(erfc_scaled_r,KIND)); |
|
TYPE |
KIND_SUFFIX(erfc_scaled_r,KIND) (TYPE x) |
{ |
/* The main computation evaluates near-minimax approximations |
from "Rational Chebyshev approximations for the error function" |
by W. J. Cody, Math. Comp., 1969, PP. 631-638. This |
transportable program uses rational functions that theoretically |
approximate erf(x) and erfc(x) to at least 18 significant |
decimal digits. The accuracy achieved depends on the arithmetic |
system, the compiler, the intrinsic functions, and proper |
selection of the machine-dependent constants. */ |
|
int i; |
TYPE del, res, xden, xnum, y, ysq; |
|
#if (KIND == 4) |
static TYPE xneg = -9.382, xsmall = 5.96e-8, |
xbig = 9.194, xhuge = 2.90e+3, xmax = 4.79e+37; |
#else |
static TYPE xneg = -26.628, xsmall = 1.11e-16, |
xbig = 26.543, xhuge = 6.71e+7, xmax = 2.53e+307; |
#endif |
|
#define SQRPI ((TYPE) 0.56418958354775628695L) |
#define THRESH ((TYPE) 0.46875L) |
|
static TYPE a[5] = { 3.16112374387056560l, 113.864154151050156l, |
377.485237685302021l, 3209.37758913846947l, 0.185777706184603153l }; |
|
static TYPE b[4] = { 23.6012909523441209l, 244.024637934444173l, |
1282.61652607737228l, 2844.23683343917062l }; |
|
static TYPE c[9] = { 0.564188496988670089l, 8.88314979438837594l, |
66.1191906371416295l, 298.635138197400131l, 881.952221241769090l, |
1712.04761263407058l, 2051.07837782607147l, 1230.33935479799725l, |
2.15311535474403846e-8l }; |
|
static TYPE d[8] = { 15.7449261107098347l, 117.693950891312499l, |
537.181101862009858l, 1621.38957456669019l, 3290.79923573345963l, |
4362.61909014324716l, 3439.36767414372164l, 1230.33935480374942l }; |
|
static TYPE p[6] = { 0.305326634961232344l, 0.360344899949804439l, |
0.125781726111229246l, 0.0160837851487422766l, |
0.000658749161529837803l, 0.0163153871373020978l }; |
|
static TYPE q[5] = { 2.56852019228982242l, 1.87295284992346047l, |
0.527905102951428412l, 0.0605183413124413191l, |
0.00233520497626869185l }; |
|
y = (x > 0 ? x : -x); |
if (y <= THRESH) |
{ |
ysq = 0; |
if (y > xsmall) |
ysq = y * y; |
xnum = a[4]*ysq; |
xden = ysq; |
for (i = 0; i <= 2; i++) |
{ |
xnum = (xnum + a[i]) * ysq; |
xden = (xden + b[i]) * ysq; |
} |
res = x * (xnum + a[3]) / (xden + b[3]); |
res = 1 - res; |
res = EXP(ysq) * res; |
return res; |
} |
else if (y <= 4) |
{ |
xnum = c[8]*y; |
xden = y; |
for (i = 0; i <= 6; i++) |
{ |
xnum = (xnum + c[i]) * y; |
xden = (xden + d[i]) * y; |
} |
res = (xnum + c[7]) / (xden + d[7]); |
} |
else |
{ |
res = 0; |
if (y >= xbig) |
{ |
if (y >= xmax) |
goto finish; |
if (y >= xhuge) |
{ |
res = SQRPI / y; |
goto finish; |
} |
} |
ysq = ((TYPE) 1) / (y * y); |
xnum = p[5]*ysq; |
xden = ysq; |
for (i = 0; i <= 3; i++) |
{ |
xnum = (xnum + p[i]) * ysq; |
xden = (xden + q[i]) * ysq; |
} |
res = ysq *(xnum + p[4]) / (xden + q[4]); |
res = (SQRPI - res) / y; |
} |
|
finish: |
if (x < 0) |
{ |
if (x < xneg) |
res = __builtin_inf (); |
else |
{ |
ysq = TRUNC (x*((TYPE) 16))/((TYPE) 16); |
del = (x-ysq)*(x+ysq); |
y = EXP(ysq*ysq) * EXP(del); |
res = (y+y) - res; |
} |
} |
return res; |
} |
|
#endif |
|
#undef EXP |
#undef TRUNC |
|
#undef CONCAT |
#undef TYPE |
#undef KIND_SUFFIX |
/erfc_scaled.c
0,0 → 1,52
/* Implementation of the ERFC_SCALED intrinsic. |
Copyright (C) 2008, 2009 Free Software Foundation, Inc. |
|
This file is part of the GNU Fortran runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
|
/* This implementation of ERFC_SCALED is based on the netlib algorithm |
available at http://www.netlib.org/specfun/erf */ |
|
#ifdef HAVE_GFC_REAL_4 |
#undef KIND |
#define KIND 4 |
#include "erfc_scaled_inc.c" |
#endif |
|
#ifdef HAVE_GFC_REAL_8 |
#undef KIND |
#define KIND 8 |
#include "erfc_scaled_inc.c" |
#endif |
|
#ifdef HAVE_GFC_REAL_10 |
#undef KIND |
#define KIND 10 |
#include "erfc_scaled_inc.c" |
#endif |
|
#ifdef HAVE_GFC_REAL_16 |
#undef KIND |
#define KIND 16 |
#include "erfc_scaled_inc.c" |
#endif |
/chmod.c
0,0 → 1,525
/* Implementation of the CHMOD intrinsic. |
Copyright (C) 2006, 2007, 2009, 2012 Free Software Foundation, Inc. |
Contributed by François-Xavier Coudert <coudert@clipper.ens.fr> |
|
This file is part of the GNU Fortran runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
|
#if defined(HAVE_SYS_STAT_H) |
|
#include <stdbool.h> |
#include <string.h> /* For memcpy. */ |
#include <sys/stat.h> /* For stat, chmod and umask. */ |
|
|
/* INTEGER FUNCTION CHMOD (NAME, MODE) |
CHARACTER(len=*), INTENT(IN) :: NAME, MODE |
|
Sets the file permission "chmod" using a mode string. |
|
For MinGW, only _S_IWRITE and _S_IREAD are supported. To set those, |
only the user attributes are used. |
|
The mode string allows for the same arguments as POSIX's chmod utility. |
a) string containing an octal number. |
b) Comma separated list of clauses of the form: |
[<who-list>]<op>[<perm-list>|<permcopy>][<op>[<perm-list>|<permcopy>],...] |
<who> - 'u', 'g', 'o', 'a' |
<op> - '+', '-', '=' |
<perm> - 'r', 'w', 'x', 'X', 's', t' |
If <op> is not followed by a perm-list or permcopy, '-' and '+' do not |
change the mode while '=' clears all file mode bits. 'u' stands for the |
user permissions, 'g' for the group and 'o' for the permissions for others. |
'a' is equivalent to 'ugo'. '+' sets the given permission in addition to |
the ones of the file, '-' unsets the given permissions of the file, while |
'=' sets the file to that mode. 'r' sets the read, 'w' the write, and |
'x' the execute mode. 'X' sets the execute bit if the file is a directory |
or if the user, group or other executable bit is set. 't' sets the sticky |
bit, 's' (un)sets the and/or S_ISUID/S_ISGID bit. |
|
Note that if <who> is omitted, the permissions are filtered by the umask. |
|
A return value of 0 indicates success, -1 an error of chmod() while 1 |
indicates a mode parsing error. */ |
|
extern int chmod_func (char *, char *, gfc_charlen_type, gfc_charlen_type); |
export_proto(chmod_func); |
|
int |
chmod_func (char *name, char *mode, gfc_charlen_type name_len, |
gfc_charlen_type mode_len) |
{ |
char * file; |
int i; |
bool ugo[3]; |
bool rwxXstugo[9]; |
int set_mode, part; |
bool is_dir, honor_umask, continue_clause = false; |
mode_t mode_mask, file_mode, new_mode; |
struct stat stat_buf; |
|
/* Trim trailing spaces of the file name. */ |
while (name_len > 0 && name[name_len - 1] == ' ') |
name_len--; |
|
/* Make a null terminated copy of the file name. */ |
file = gfc_alloca (name_len + 1); |
memcpy (file, name, name_len); |
file[name_len] = '\0'; |
|
if (mode_len == 0) |
return 1; |
|
if (mode[0] >= '0' && mode[0] <= '9') |
{ |
#ifdef __MINGW32__ |
unsigned mode; |
if (sscanf (mode, "%o", &mode) != 1) |
return 1; |
file_mode = (mode_t) mode; |
#else |
if (sscanf (mode, "%o", &file_mode) != 1) |
return 1; |
#endif |
return chmod (file, file_mode); |
} |
|
/* Read the current file mode. */ |
if (stat (file, &stat_buf)) |
return 1; |
|
file_mode = stat_buf.st_mode & ~S_IFMT; |
is_dir = stat_buf.st_mode & S_IFDIR; |
|
#ifdef HAVE_UMASK |
/* Obtain the umask without distroying the setting. */ |
mode_mask = 0; |
mode_mask = umask (mode_mask); |
(void) umask (mode_mask); |
#else |
honor_umask = false; |
#endif |
|
for (i = 0; i < mode_len; i++) |
{ |
if (!continue_clause) |
{ |
ugo[0] = false; |
ugo[1] = false; |
ugo[2] = false; |
#ifdef HAVE_UMASK |
honor_umask = true; |
#endif |
} |
continue_clause = false; |
rwxXstugo[0] = false; |
rwxXstugo[1] = false; |
rwxXstugo[2] = false; |
rwxXstugo[3] = false; |
rwxXstugo[4] = false; |
rwxXstugo[5] = false; |
rwxXstugo[6] = false; |
rwxXstugo[7] = false; |
rwxXstugo[8] = false; |
rwxXstugo[9] = false; |
part = 0; |
set_mode = -1; |
for (; i < mode_len; i++) |
{ |
switch (mode[i]) |
{ |
/* User setting: a[ll]/u[ser]/g[roup]/o[ther]. */ |
case 'a': |
if (part > 1) |
return 1; |
ugo[0] = true; |
ugo[1] = true; |
ugo[2] = true; |
part = 1; |
#ifdef HAVE_UMASK |
honor_umask = false; |
#endif |
break; |
case 'u': |
if (part == 2) |
{ |
rwxXstugo[6] = true; |
part = 4; |
break; |
} |
if (part > 1) |
return 1; |
ugo[0] = true; |
part = 1; |
#ifdef HAVE_UMASK |
honor_umask = false; |
#endif |
break; |
case 'g': |
if (part == 2) |
{ |
rwxXstugo[7] = true; |
part = 4; |
break; |
} |
if (part > 1) |
return 1; |
ugo[1] = true; |
part = 1; |
#ifdef HAVE_UMASK |
honor_umask = false; |
#endif |
break; |
case 'o': |
if (part == 2) |
{ |
rwxXstugo[8] = true; |
part = 4; |
break; |
} |
if (part > 1) |
return 1; |
ugo[2] = true; |
part = 1; |
#ifdef HAVE_UMASK |
honor_umask = false; |
#endif |
break; |
|
/* Mode setting: =+-. */ |
case '=': |
if (part > 2) |
{ |
continue_clause = true; |
i--; |
part = 2; |
goto clause_done; |
} |
set_mode = 1; |
part = 2; |
break; |
|
case '-': |
if (part > 2) |
{ |
continue_clause = true; |
i--; |
part = 2; |
goto clause_done; |
} |
set_mode = 2; |
part = 2; |
break; |
|
case '+': |
if (part > 2) |
{ |
continue_clause = true; |
i--; |
part = 2; |
goto clause_done; |
} |
set_mode = 3; |
part = 2; |
break; |
|
/* Permissions: rwxXst - for ugo see above. */ |
case 'r': |
if (part != 2 && part != 3) |
return 1; |
rwxXstugo[0] = true; |
part = 3; |
break; |
|
case 'w': |
if (part != 2 && part != 3) |
return 1; |
rwxXstugo[1] = true; |
part = 3; |
break; |
|
case 'x': |
if (part != 2 && part != 3) |
return 1; |
rwxXstugo[2] = true; |
part = 3; |
break; |
|
case 'X': |
if (part != 2 && part != 3) |
return 1; |
rwxXstugo[3] = true; |
part = 3; |
break; |
|
case 's': |
if (part != 2 && part != 3) |
return 1; |
rwxXstugo[4] = true; |
part = 3; |
break; |
|
case 't': |
if (part != 2 && part != 3) |
return 1; |
rwxXstugo[5] = true; |
part = 3; |
break; |
|
/* Tailing blanks are valid in Fortran. */ |
case ' ': |
for (i++; i < mode_len; i++) |
if (mode[i] != ' ') |
break; |
if (i != mode_len) |
return 1; |
goto clause_done; |
|
case ',': |
goto clause_done; |
|
default: |
return 1; |
} |
} |
|
clause_done: |
if (part < 2) |
return 1; |
|
new_mode = 0; |
|
#ifdef __MINGW32__ |
|
/* Read. */ |
if (rwxXstugo[0] && (ugo[0] || honor_umask)) |
new_mode |= _S_IREAD; |
|
/* Write. */ |
if (rwxXstugo[1] && (ugo[0] || honor_umask)) |
new_mode |= _S_IWRITE; |
|
#else |
|
/* Read. */ |
if (rwxXstugo[0]) |
{ |
if (ugo[0] || honor_umask) |
new_mode |= S_IRUSR; |
if (ugo[1] || honor_umask) |
new_mode |= S_IRGRP; |
if (ugo[2] || honor_umask) |
new_mode |= S_IROTH; |
} |
|
/* Write. */ |
if (rwxXstugo[1]) |
{ |
if (ugo[0] || honor_umask) |
new_mode |= S_IWUSR; |
if (ugo[1] || honor_umask) |
new_mode |= S_IWGRP; |
if (ugo[2] || honor_umask) |
new_mode |= S_IWOTH; |
} |
|
/* Execute. */ |
if (rwxXstugo[2]) |
{ |
if (ugo[0] || honor_umask) |
new_mode |= S_IXUSR; |
if (ugo[1] || honor_umask) |
new_mode |= S_IXGRP; |
if (ugo[2] || honor_umask) |
new_mode |= S_IXOTH; |
} |
|
/* 'X' execute. */ |
if (rwxXstugo[3] |
&& (is_dir || (file_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))) |
new_mode |= (S_IXUSR | S_IXGRP | S_IXOTH); |
|
/* 's'. */ |
if (rwxXstugo[4]) |
{ |
if (ugo[0] || honor_umask) |
new_mode |= S_ISUID; |
if (ugo[1] || honor_umask) |
new_mode |= S_ISGID; |
} |
|
/* As original 'u'. */ |
if (rwxXstugo[6]) |
{ |
if (ugo[1] || honor_umask) |
{ |
if (file_mode & S_IRUSR) |
new_mode |= S_IRGRP; |
if (file_mode & S_IWUSR) |
new_mode |= S_IWGRP; |
if (file_mode & S_IXUSR) |
new_mode |= S_IXGRP; |
} |
if (ugo[2] || honor_umask) |
{ |
if (file_mode & S_IRUSR) |
new_mode |= S_IROTH; |
if (file_mode & S_IWUSR) |
new_mode |= S_IWOTH; |
if (file_mode & S_IXUSR) |
new_mode |= S_IXOTH; |
} |
} |
|
/* As original 'g'. */ |
if (rwxXstugo[7]) |
{ |
if (ugo[0] || honor_umask) |
{ |
if (file_mode & S_IRGRP) |
new_mode |= S_IRUSR; |
if (file_mode & S_IWGRP) |
new_mode |= S_IWUSR; |
if (file_mode & S_IXGRP) |
new_mode |= S_IXUSR; |
} |
if (ugo[2] || honor_umask) |
{ |
if (file_mode & S_IRGRP) |
new_mode |= S_IROTH; |
if (file_mode & S_IWGRP) |
new_mode |= S_IWOTH; |
if (file_mode & S_IXGRP) |
new_mode |= S_IXOTH; |
} |
} |
|
/* As original 'o'. */ |
if (rwxXstugo[8]) |
{ |
if (ugo[0] || honor_umask) |
{ |
if (file_mode & S_IROTH) |
new_mode |= S_IRUSR; |
if (file_mode & S_IWOTH) |
new_mode |= S_IWUSR; |
if (file_mode & S_IXOTH) |
new_mode |= S_IXUSR; |
} |
if (ugo[1] || honor_umask) |
{ |
if (file_mode & S_IROTH) |
new_mode |= S_IRGRP; |
if (file_mode & S_IWOTH) |
new_mode |= S_IWGRP; |
if (file_mode & S_IXOTH) |
new_mode |= S_IXGRP; |
} |
} |
#endif /* __MINGW32__ */ |
|
#ifdef HAVE_UMASK |
if (honor_umask) |
new_mode &= ~mode_mask; |
#endif |
|
if (set_mode == 1) |
{ |
#ifdef __MINGW32__ |
if (ugo[0] || honor_umask) |
file_mode = (file_mode & ~(_S_IWRITE | _S_IREAD)) |
| (new_mode & (_S_IWRITE | _S_IREAD)); |
#else |
/* Set '='. */ |
if ((ugo[0] || honor_umask) && !rwxXstugo[6]) |
file_mode = (file_mode & ~(S_ISUID | S_IRUSR | S_IWUSR | S_IXUSR)) |
| (new_mode & (S_ISUID | S_IRUSR | S_IWUSR | S_IXUSR)); |
if ((ugo[1] || honor_umask) && !rwxXstugo[7]) |
file_mode = (file_mode & ~(S_ISGID | S_IRGRP | S_IWGRP | S_IXGRP)) |
| (new_mode & (S_ISGID | S_IRGRP | S_IWGRP | S_IXGRP)); |
if ((ugo[2] || honor_umask) && !rwxXstugo[8]) |
file_mode = (file_mode & ~(S_IROTH | S_IWOTH | S_IXOTH)) |
| (new_mode & (S_IROTH | S_IWOTH | S_IXOTH)); |
if (is_dir && rwxXstugo[5]) |
file_mode |= S_ISVTX; |
else if (!is_dir) |
file_mode &= ~S_ISVTX; |
#endif |
} |
else if (set_mode == 2) |
{ |
/* Clear '-'. */ |
file_mode &= ~new_mode; |
#ifndef __MINGW32__ |
if (rwxXstugo[5] || !is_dir) |
file_mode &= ~S_ISVTX; |
#endif |
} |
else if (set_mode == 3) |
{ |
file_mode |= new_mode; |
#ifndef __MINGW32__ |
if (rwxXstugo[5] && is_dir) |
file_mode |= S_ISVTX; |
else if (!is_dir) |
file_mode &= ~S_ISVTX; |
#endif |
} |
} |
|
return chmod (file, file_mode); |
} |
|
|
extern void chmod_i4_sub (char *, char *, GFC_INTEGER_4 *, |
gfc_charlen_type, gfc_charlen_type); |
export_proto(chmod_i4_sub); |
|
void |
chmod_i4_sub (char *name, char *mode, GFC_INTEGER_4 * status, |
gfc_charlen_type name_len, gfc_charlen_type mode_len) |
{ |
int val; |
|
val = chmod_func (name, mode, name_len, mode_len); |
if (status) |
*status = val; |
} |
|
|
extern void chmod_i8_sub (char *, char *, GFC_INTEGER_8 *, |
gfc_charlen_type, gfc_charlen_type); |
export_proto(chmod_i8_sub); |
|
void |
chmod_i8_sub (char *name, char *mode, GFC_INTEGER_8 * status, |
gfc_charlen_type name_len, gfc_charlen_type mode_len) |
{ |
int val; |
|
val = chmod_func (name, mode, name_len, mode_len); |
if (status) |
*status = val; |
} |
|
#endif |
/selected_char_kind.c
0,0 → 1,46
/* Copyright 2008, 2009, 2010 Free Software Foundation, Inc. |
Contributed by Paul Brook <paul@nowt.org> |
|
This file is part of the GNU Fortran 95 runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
|
#include "libgfortran.h" |
|
#include <string.h> |
|
|
extern GFC_INTEGER_4 selected_char_kind (gfc_charlen_type, char *); |
export_proto(selected_char_kind); |
|
GFC_INTEGER_4 |
selected_char_kind (gfc_charlen_type name_len, char *name) |
{ |
gfc_charlen_type len = fstrlen (name, name_len); |
|
if ((len == 5 && strncasecmp (name, "ascii", 5) == 0) |
|| (len == 7 && strncasecmp (name, "default", 7) == 0)) |
return 1; |
else if (len == 9 && strncasecmp (name, "iso_10646", 9) == 0) |
return 4; |
else |
return -1; |
} |
/c99_functions.c
0,0 → 1,2136
/* Implementation of various C99 functions |
Copyright (C) 2004, 2009, 2010 Free Software Foundation, Inc. |
|
This file is part of the GNU Fortran 95 runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "config.h" |
|
#define C99_PROTOS_H WE_DONT_WANT_PROTOS_NOW |
#include "libgfortran.h" |
|
/* IRIX's <math.h> declares a non-C99 compliant implementation of cabs, |
which takes two floating point arguments instead of a single complex. |
If <complex.h> is missing this prevents building of c99_functions.c. |
To work around this we redirect cabs{,f,l} calls to __gfc_cabs{,f,l}. */ |
|
#if defined(__sgi__) && !defined(HAVE_COMPLEX_H) |
#undef HAVE_CABS |
#undef HAVE_CABSF |
#undef HAVE_CABSL |
#define cabs __gfc_cabs |
#define cabsf __gfc_cabsf |
#define cabsl __gfc_cabsl |
#endif |
|
/* Tru64's <math.h> declares a non-C99 compliant implementation of cabs, |
which takes two floating point arguments instead of a single complex. |
To work around this we redirect cabs{,f,l} calls to __gfc_cabs{,f,l}. */ |
|
#ifdef __osf__ |
#undef HAVE_CABS |
#undef HAVE_CABSF |
#undef HAVE_CABSL |
#define cabs __gfc_cabs |
#define cabsf __gfc_cabsf |
#define cabsl __gfc_cabsl |
#endif |
|
/* On a C99 system "I" (with I*I = -1) should be defined in complex.h; |
if not, we define a fallback version here. */ |
#ifndef I |
# if defined(_Imaginary_I) |
# define I _Imaginary_I |
# elif defined(_Complex_I) |
# define I _Complex_I |
# else |
# define I (1.0fi) |
# endif |
#endif |
|
/* Prototypes are included to silence -Wstrict-prototypes |
-Wmissing-prototypes. */ |
|
|
/* Wrappers for systems without the various C99 single precision Bessel |
functions. */ |
|
#if defined(HAVE_J0) && ! defined(HAVE_J0F) |
#define HAVE_J0F 1 |
float j0f (float); |
|
float |
j0f (float x) |
{ |
return (float) j0 ((double) x); |
} |
#endif |
|
#if defined(HAVE_J1) && !defined(HAVE_J1F) |
#define HAVE_J1F 1 |
float j1f (float); |
|
float j1f (float x) |
{ |
return (float) j1 ((double) x); |
} |
#endif |
|
#if defined(HAVE_JN) && !defined(HAVE_JNF) |
#define HAVE_JNF 1 |
float jnf (int, float); |
|
float |
jnf (int n, float x) |
{ |
return (float) jn (n, (double) x); |
} |
#endif |
|
#if defined(HAVE_Y0) && !defined(HAVE_Y0F) |
#define HAVE_Y0F 1 |
float y0f (float); |
|
float |
y0f (float x) |
{ |
return (float) y0 ((double) x); |
} |
#endif |
|
#if defined(HAVE_Y1) && !defined(HAVE_Y1F) |
#define HAVE_Y1F 1 |
float y1f (float); |
|
float |
y1f (float x) |
{ |
return (float) y1 ((double) x); |
} |
#endif |
|
#if defined(HAVE_YN) && !defined(HAVE_YNF) |
#define HAVE_YNF 1 |
float ynf (int, float); |
|
float |
ynf (int n, float x) |
{ |
return (float) yn (n, (double) x); |
} |
#endif |
|
|
/* Wrappers for systems without the C99 erff() and erfcf() functions. */ |
|
#if defined(HAVE_ERF) && !defined(HAVE_ERFF) |
#define HAVE_ERFF 1 |
float erff (float); |
|
float |
erff (float x) |
{ |
return (float) erf ((double) x); |
} |
#endif |
|
#if defined(HAVE_ERFC) && !defined(HAVE_ERFCF) |
#define HAVE_ERFCF 1 |
float erfcf (float); |
|
float |
erfcf (float x) |
{ |
return (float) erfc ((double) x); |
} |
#endif |
|
|
#ifndef HAVE_ACOSF |
#define HAVE_ACOSF 1 |
float acosf (float x); |
|
float |
acosf (float x) |
{ |
return (float) acos (x); |
} |
#endif |
|
#if HAVE_ACOSH && !HAVE_ACOSHF |
float acoshf (float x); |
|
float |
acoshf (float x) |
{ |
return (float) acosh ((double) x); |
} |
#endif |
|
#ifndef HAVE_ASINF |
#define HAVE_ASINF 1 |
float asinf (float x); |
|
float |
asinf (float x) |
{ |
return (float) asin (x); |
} |
#endif |
|
#if HAVE_ASINH && !HAVE_ASINHF |
float asinhf (float x); |
|
float |
asinhf (float x) |
{ |
return (float) asinh ((double) x); |
} |
#endif |
|
#ifndef HAVE_ATAN2F |
#define HAVE_ATAN2F 1 |
float atan2f (float y, float x); |
|
float |
atan2f (float y, float x) |
{ |
return (float) atan2 (y, x); |
} |
#endif |
|
#ifndef HAVE_ATANF |
#define HAVE_ATANF 1 |
float atanf (float x); |
|
float |
atanf (float x) |
{ |
return (float) atan (x); |
} |
#endif |
|
#if HAVE_ATANH && !HAVE_ATANHF |
float atanhf (float x); |
|
float |
atanhf (float x) |
{ |
return (float) atanh ((double) x); |
} |
#endif |
|
#ifndef HAVE_CEILF |
#define HAVE_CEILF 1 |
float ceilf (float x); |
|
float |
ceilf (float x) |
{ |
return (float) ceil (x); |
} |
#endif |
|
#ifndef HAVE_COPYSIGNF |
#define HAVE_COPYSIGNF 1 |
float copysignf (float x, float y); |
|
float |
copysignf (float x, float y) |
{ |
return (float) copysign (x, y); |
} |
#endif |
|
#ifndef HAVE_COSF |
#define HAVE_COSF 1 |
float cosf (float x); |
|
float |
cosf (float x) |
{ |
return (float) cos (x); |
} |
#endif |
|
#ifndef HAVE_COSHF |
#define HAVE_COSHF 1 |
float coshf (float x); |
|
float |
coshf (float x) |
{ |
return (float) cosh (x); |
} |
#endif |
|
#ifndef HAVE_EXPF |
#define HAVE_EXPF 1 |
float expf (float x); |
|
float |
expf (float x) |
{ |
return (float) exp (x); |
} |
#endif |
|
#ifndef HAVE_FABSF |
#define HAVE_FABSF 1 |
float fabsf (float x); |
|
float |
fabsf (float x) |
{ |
return (float) fabs (x); |
} |
#endif |
|
#ifndef HAVE_FLOORF |
#define HAVE_FLOORF 1 |
float floorf (float x); |
|
float |
floorf (float x) |
{ |
return (float) floor (x); |
} |
#endif |
|
#ifndef HAVE_FMODF |
#define HAVE_FMODF 1 |
float fmodf (float x, float y); |
|
float |
fmodf (float x, float y) |
{ |
return (float) fmod (x, y); |
} |
#endif |
|
#ifndef HAVE_FREXPF |
#define HAVE_FREXPF 1 |
float frexpf (float x, int *exp); |
|
float |
frexpf (float x, int *exp) |
{ |
return (float) frexp (x, exp); |
} |
#endif |
|
#ifndef HAVE_HYPOTF |
#define HAVE_HYPOTF 1 |
float hypotf (float x, float y); |
|
float |
hypotf (float x, float y) |
{ |
return (float) hypot (x, y); |
} |
#endif |
|
#ifndef HAVE_LOGF |
#define HAVE_LOGF 1 |
float logf (float x); |
|
float |
logf (float x) |
{ |
return (float) log (x); |
} |
#endif |
|
#ifndef HAVE_LOG10F |
#define HAVE_LOG10F 1 |
float log10f (float x); |
|
float |
log10f (float x) |
{ |
return (float) log10 (x); |
} |
#endif |
|
#ifndef HAVE_SCALBN |
#define HAVE_SCALBN 1 |
double scalbn (double x, int y); |
|
double |
scalbn (double x, int y) |
{ |
#if (FLT_RADIX == 2) && defined(HAVE_LDEXP) |
return ldexp (x, y); |
#else |
return x * pow (FLT_RADIX, y); |
#endif |
} |
#endif |
|
#ifndef HAVE_SCALBNF |
#define HAVE_SCALBNF 1 |
float scalbnf (float x, int y); |
|
float |
scalbnf (float x, int y) |
{ |
return (float) scalbn (x, y); |
} |
#endif |
|
#ifndef HAVE_SINF |
#define HAVE_SINF 1 |
float sinf (float x); |
|
float |
sinf (float x) |
{ |
return (float) sin (x); |
} |
#endif |
|
#ifndef HAVE_SINHF |
#define HAVE_SINHF 1 |
float sinhf (float x); |
|
float |
sinhf (float x) |
{ |
return (float) sinh (x); |
} |
#endif |
|
#ifndef HAVE_SQRTF |
#define HAVE_SQRTF 1 |
float sqrtf (float x); |
|
float |
sqrtf (float x) |
{ |
return (float) sqrt (x); |
} |
#endif |
|
#ifndef HAVE_TANF |
#define HAVE_TANF 1 |
float tanf (float x); |
|
float |
tanf (float x) |
{ |
return (float) tan (x); |
} |
#endif |
|
#ifndef HAVE_TANHF |
#define HAVE_TANHF 1 |
float tanhf (float x); |
|
float |
tanhf (float x) |
{ |
return (float) tanh (x); |
} |
#endif |
|
#ifndef HAVE_TRUNC |
#define HAVE_TRUNC 1 |
double trunc (double x); |
|
double |
trunc (double x) |
{ |
if (!isfinite (x)) |
return x; |
|
if (x < 0.0) |
return - floor (-x); |
else |
return floor (x); |
} |
#endif |
|
#ifndef HAVE_TRUNCF |
#define HAVE_TRUNCF 1 |
float truncf (float x); |
|
float |
truncf (float x) |
{ |
return (float) trunc (x); |
} |
#endif |
|
#ifndef HAVE_NEXTAFTERF |
#define HAVE_NEXTAFTERF 1 |
/* This is a portable implementation of nextafterf that is intended to be |
independent of the floating point format or its in memory representation. |
This implementation works correctly with denormalized values. */ |
float nextafterf (float x, float y); |
|
float |
nextafterf (float x, float y) |
{ |
/* This variable is marked volatile to avoid excess precision problems |
on some platforms, including IA-32. */ |
volatile float delta; |
float absx, denorm_min; |
|
if (isnan (x) || isnan (y)) |
return x + y; |
if (x == y) |
return x; |
if (!isfinite (x)) |
return x > 0 ? __FLT_MAX__ : - __FLT_MAX__; |
|
/* absx = fabsf (x); */ |
absx = (x < 0.0) ? -x : x; |
|
/* __FLT_DENORM_MIN__ is non-zero iff the target supports denormals. */ |
if (__FLT_DENORM_MIN__ == 0.0f) |
denorm_min = __FLT_MIN__; |
else |
denorm_min = __FLT_DENORM_MIN__; |
|
if (absx < __FLT_MIN__) |
delta = denorm_min; |
else |
{ |
float frac; |
int exp; |
|
/* Discard the fraction from x. */ |
frac = frexpf (absx, &exp); |
delta = scalbnf (0.5f, exp); |
|
/* Scale x by the epsilon of the representation. By rights we should |
have been able to combine this with scalbnf, but some targets don't |
get that correct with denormals. */ |
delta *= __FLT_EPSILON__; |
|
/* If we're going to be reducing the absolute value of X, and doing so |
would reduce the exponent of X, then the delta to be applied is |
one exponent smaller. */ |
if (frac == 0.5f && (y < x) == (x > 0)) |
delta *= 0.5f; |
|
/* If that underflows to zero, then we're back to the minimum. */ |
if (delta == 0.0f) |
delta = denorm_min; |
} |
|
if (y < x) |
delta = -delta; |
|
return x + delta; |
} |
#endif |
|
|
#if !defined(HAVE_POWF) || defined(HAVE_BROKEN_POWF) |
#ifndef HAVE_POWF |
#define HAVE_POWF 1 |
#endif |
float powf (float x, float y); |
|
float |
powf (float x, float y) |
{ |
return (float) pow (x, y); |
} |
#endif |
|
|
#ifndef HAVE_ROUND |
#define HAVE_ROUND 1 |
/* Round to nearest integral value. If the argument is halfway between two |
integral values then round away from zero. */ |
double round (double x); |
|
double |
round (double x) |
{ |
double t; |
if (!isfinite (x)) |
return (x); |
|
if (x >= 0.0) |
{ |
t = floor (x); |
if (t - x <= -0.5) |
t += 1.0; |
return (t); |
} |
else |
{ |
t = floor (-x); |
if (t + x <= -0.5) |
t += 1.0; |
return (-t); |
} |
} |
#endif |
|
|
/* Algorithm by Steven G. Kargl. */ |
|
#if !defined(HAVE_ROUNDL) |
#define HAVE_ROUNDL 1 |
long double roundl (long double x); |
|
#if defined(HAVE_CEILL) |
/* Round to nearest integral value. If the argument is halfway between two |
integral values then round away from zero. */ |
|
long double |
roundl (long double x) |
{ |
long double t; |
if (!isfinite (x)) |
return (x); |
|
if (x >= 0.0) |
{ |
t = ceill (x); |
if (t - x > 0.5) |
t -= 1.0; |
return (t); |
} |
else |
{ |
t = ceill (-x); |
if (t + x > 0.5) |
t -= 1.0; |
return (-t); |
} |
} |
#else |
|
/* Poor version of roundl for system that don't have ceill. */ |
long double |
roundl (long double x) |
{ |
if (x > DBL_MAX || x < -DBL_MAX) |
{ |
#ifdef HAVE_NEXTAFTERL |
long double prechalf = nextafterl (0.5L, LDBL_MAX); |
#else |
static long double prechalf = 0.5L; |
#endif |
return (GFC_INTEGER_LARGEST) (x + (x > 0 ? prechalf : -prechalf)); |
} |
else |
/* Use round(). */ |
return round ((double) x); |
} |
|
#endif |
#endif |
|
#ifndef HAVE_ROUNDF |
#define HAVE_ROUNDF 1 |
/* Round to nearest integral value. If the argument is halfway between two |
integral values then round away from zero. */ |
float roundf (float x); |
|
float |
roundf (float x) |
{ |
float t; |
if (!isfinite (x)) |
return (x); |
|
if (x >= 0.0) |
{ |
t = floorf (x); |
if (t - x <= -0.5) |
t += 1.0; |
return (t); |
} |
else |
{ |
t = floorf (-x); |
if (t + x <= -0.5) |
t += 1.0; |
return (-t); |
} |
} |
#endif |
|
|
/* lround{f,,l} and llround{f,,l} functions. */ |
|
#if !defined(HAVE_LROUNDF) && defined(HAVE_ROUNDF) |
#define HAVE_LROUNDF 1 |
long int lroundf (float x); |
|
long int |
lroundf (float x) |
{ |
return (long int) roundf (x); |
} |
#endif |
|
#if !defined(HAVE_LROUND) && defined(HAVE_ROUND) |
#define HAVE_LROUND 1 |
long int lround (double x); |
|
long int |
lround (double x) |
{ |
return (long int) round (x); |
} |
#endif |
|
#if !defined(HAVE_LROUNDL) && defined(HAVE_ROUNDL) |
#define HAVE_LROUNDL 1 |
long int lroundl (long double x); |
|
long int |
lroundl (long double x) |
{ |
return (long long int) roundl (x); |
} |
#endif |
|
#if !defined(HAVE_LLROUNDF) && defined(HAVE_ROUNDF) |
#define HAVE_LLROUNDF 1 |
long long int llroundf (float x); |
|
long long int |
llroundf (float x) |
{ |
return (long long int) roundf (x); |
} |
#endif |
|
#if !defined(HAVE_LLROUND) && defined(HAVE_ROUND) |
#define HAVE_LLROUND 1 |
long long int llround (double x); |
|
long long int |
llround (double x) |
{ |
return (long long int) round (x); |
} |
#endif |
|
#if !defined(HAVE_LLROUNDL) && defined(HAVE_ROUNDL) |
#define HAVE_LLROUNDL 1 |
long long int llroundl (long double x); |
|
long long int |
llroundl (long double x) |
{ |
return (long long int) roundl (x); |
} |
#endif |
|
|
#ifndef HAVE_LOG10L |
#define HAVE_LOG10L 1 |
/* log10 function for long double variables. The version provided here |
reduces the argument until it fits into a double, then use log10. */ |
long double log10l (long double x); |
|
long double |
log10l (long double x) |
{ |
#if LDBL_MAX_EXP > DBL_MAX_EXP |
if (x > DBL_MAX) |
{ |
double val; |
int p2_result = 0; |
if (x > 0x1p16383L) { p2_result += 16383; x /= 0x1p16383L; } |
if (x > 0x1p8191L) { p2_result += 8191; x /= 0x1p8191L; } |
if (x > 0x1p4095L) { p2_result += 4095; x /= 0x1p4095L; } |
if (x > 0x1p2047L) { p2_result += 2047; x /= 0x1p2047L; } |
if (x > 0x1p1023L) { p2_result += 1023; x /= 0x1p1023L; } |
val = log10 ((double) x); |
return (val + p2_result * .30102999566398119521373889472449302L); |
} |
#endif |
#if LDBL_MIN_EXP < DBL_MIN_EXP |
if (x < DBL_MIN) |
{ |
double val; |
int p2_result = 0; |
if (x < 0x1p-16380L) { p2_result += 16380; x /= 0x1p-16380L; } |
if (x < 0x1p-8189L) { p2_result += 8189; x /= 0x1p-8189L; } |
if (x < 0x1p-4093L) { p2_result += 4093; x /= 0x1p-4093L; } |
if (x < 0x1p-2045L) { p2_result += 2045; x /= 0x1p-2045L; } |
if (x < 0x1p-1021L) { p2_result += 1021; x /= 0x1p-1021L; } |
val = fabs (log10 ((double) x)); |
return (- val - p2_result * .30102999566398119521373889472449302L); |
} |
#endif |
return log10 (x); |
} |
#endif |
|
|
#ifndef HAVE_FLOORL |
#define HAVE_FLOORL 1 |
long double floorl (long double x); |
|
long double |
floorl (long double x) |
{ |
/* Zero, possibly signed. */ |
if (x == 0) |
return x; |
|
/* Large magnitude. */ |
if (x > DBL_MAX || x < (-DBL_MAX)) |
return x; |
|
/* Small positive values. */ |
if (x >= 0 && x < DBL_MIN) |
return 0; |
|
/* Small negative values. */ |
if (x < 0 && x > (-DBL_MIN)) |
return -1; |
|
return floor (x); |
} |
#endif |
|
|
#ifndef HAVE_FMODL |
#define HAVE_FMODL 1 |
long double fmodl (long double x, long double y); |
|
long double |
fmodl (long double x, long double y) |
{ |
if (y == 0.0L) |
return 0.0L; |
|
/* Need to check that the result has the same sign as x and magnitude |
less than the magnitude of y. */ |
return x - floorl (x / y) * y; |
} |
#endif |
|
|
#if !defined(HAVE_CABSF) |
#define HAVE_CABSF 1 |
float cabsf (float complex z); |
|
float |
cabsf (float complex z) |
{ |
return hypotf (REALPART (z), IMAGPART (z)); |
} |
#endif |
|
#if !defined(HAVE_CABS) |
#define HAVE_CABS 1 |
double cabs (double complex z); |
|
double |
cabs (double complex z) |
{ |
return hypot (REALPART (z), IMAGPART (z)); |
} |
#endif |
|
#if !defined(HAVE_CABSL) && defined(HAVE_HYPOTL) |
#define HAVE_CABSL 1 |
long double cabsl (long double complex z); |
|
long double |
cabsl (long double complex z) |
{ |
return hypotl (REALPART (z), IMAGPART (z)); |
} |
#endif |
|
|
#if !defined(HAVE_CARGF) |
#define HAVE_CARGF 1 |
float cargf (float complex z); |
|
float |
cargf (float complex z) |
{ |
return atan2f (IMAGPART (z), REALPART (z)); |
} |
#endif |
|
#if !defined(HAVE_CARG) |
#define HAVE_CARG 1 |
double carg (double complex z); |
|
double |
carg (double complex z) |
{ |
return atan2 (IMAGPART (z), REALPART (z)); |
} |
#endif |
|
#if !defined(HAVE_CARGL) && defined(HAVE_ATAN2L) |
#define HAVE_CARGL 1 |
long double cargl (long double complex z); |
|
long double |
cargl (long double complex z) |
{ |
return atan2l (IMAGPART (z), REALPART (z)); |
} |
#endif |
|
|
/* exp(z) = exp(a)*(cos(b) + i sin(b)) */ |
#if !defined(HAVE_CEXPF) |
#define HAVE_CEXPF 1 |
float complex cexpf (float complex z); |
|
float complex |
cexpf (float complex z) |
{ |
float a, b; |
float complex v; |
|
a = REALPART (z); |
b = IMAGPART (z); |
COMPLEX_ASSIGN (v, cosf (b), sinf (b)); |
return expf (a) * v; |
} |
#endif |
|
#if !defined(HAVE_CEXP) |
#define HAVE_CEXP 1 |
double complex cexp (double complex z); |
|
double complex |
cexp (double complex z) |
{ |
double a, b; |
double complex v; |
|
a = REALPART (z); |
b = IMAGPART (z); |
COMPLEX_ASSIGN (v, cos (b), sin (b)); |
return exp (a) * v; |
} |
#endif |
|
#if !defined(HAVE_CEXPL) && defined(HAVE_COSL) && defined(HAVE_SINL) && defined(EXPL) |
#define HAVE_CEXPL 1 |
long double complex cexpl (long double complex z); |
|
long double complex |
cexpl (long double complex z) |
{ |
long double a, b; |
long double complex v; |
|
a = REALPART (z); |
b = IMAGPART (z); |
COMPLEX_ASSIGN (v, cosl (b), sinl (b)); |
return expl (a) * v; |
} |
#endif |
|
|
/* log(z) = log (cabs(z)) + i*carg(z) */ |
#if !defined(HAVE_CLOGF) |
#define HAVE_CLOGF 1 |
float complex clogf (float complex z); |
|
float complex |
clogf (float complex z) |
{ |
float complex v; |
|
COMPLEX_ASSIGN (v, logf (cabsf (z)), cargf (z)); |
return v; |
} |
#endif |
|
#if !defined(HAVE_CLOG) |
#define HAVE_CLOG 1 |
double complex clog (double complex z); |
|
double complex |
clog (double complex z) |
{ |
double complex v; |
|
COMPLEX_ASSIGN (v, log (cabs (z)), carg (z)); |
return v; |
} |
#endif |
|
#if !defined(HAVE_CLOGL) && defined(HAVE_LOGL) && defined(HAVE_CABSL) && defined(HAVE_CARGL) |
#define HAVE_CLOGL 1 |
long double complex clogl (long double complex z); |
|
long double complex |
clogl (long double complex z) |
{ |
long double complex v; |
|
COMPLEX_ASSIGN (v, logl (cabsl (z)), cargl (z)); |
return v; |
} |
#endif |
|
|
/* log10(z) = log10 (cabs(z)) + i*carg(z) */ |
#if !defined(HAVE_CLOG10F) |
#define HAVE_CLOG10F 1 |
float complex clog10f (float complex z); |
|
float complex |
clog10f (float complex z) |
{ |
float complex v; |
|
COMPLEX_ASSIGN (v, log10f (cabsf (z)), cargf (z)); |
return v; |
} |
#endif |
|
#if !defined(HAVE_CLOG10) |
#define HAVE_CLOG10 1 |
double complex clog10 (double complex z); |
|
double complex |
clog10 (double complex z) |
{ |
double complex v; |
|
COMPLEX_ASSIGN (v, log10 (cabs (z)), carg (z)); |
return v; |
} |
#endif |
|
#if !defined(HAVE_CLOG10L) && defined(HAVE_LOG10L) && defined(HAVE_CABSL) && defined(HAVE_CARGL) |
#define HAVE_CLOG10L 1 |
long double complex clog10l (long double complex z); |
|
long double complex |
clog10l (long double complex z) |
{ |
long double complex v; |
|
COMPLEX_ASSIGN (v, log10l (cabsl (z)), cargl (z)); |
return v; |
} |
#endif |
|
|
/* pow(base, power) = cexp (power * clog (base)) */ |
#if !defined(HAVE_CPOWF) |
#define HAVE_CPOWF 1 |
float complex cpowf (float complex base, float complex power); |
|
float complex |
cpowf (float complex base, float complex power) |
{ |
return cexpf (power * clogf (base)); |
} |
#endif |
|
#if !defined(HAVE_CPOW) |
#define HAVE_CPOW 1 |
double complex cpow (double complex base, double complex power); |
|
double complex |
cpow (double complex base, double complex power) |
{ |
return cexp (power * clog (base)); |
} |
#endif |
|
#if !defined(HAVE_CPOWL) && defined(HAVE_CEXPL) && defined(HAVE_CLOGL) |
#define HAVE_CPOWL 1 |
long double complex cpowl (long double complex base, long double complex power); |
|
long double complex |
cpowl (long double complex base, long double complex power) |
{ |
return cexpl (power * clogl (base)); |
} |
#endif |
|
|
/* sqrt(z). Algorithm pulled from glibc. */ |
#if !defined(HAVE_CSQRTF) |
#define HAVE_CSQRTF 1 |
float complex csqrtf (float complex z); |
|
float complex |
csqrtf (float complex z) |
{ |
float re, im; |
float complex v; |
|
re = REALPART (z); |
im = IMAGPART (z); |
if (im == 0) |
{ |
if (re < 0) |
{ |
COMPLEX_ASSIGN (v, 0, copysignf (sqrtf (-re), im)); |
} |
else |
{ |
COMPLEX_ASSIGN (v, fabsf (sqrtf (re)), copysignf (0, im)); |
} |
} |
else if (re == 0) |
{ |
float r; |
|
r = sqrtf (0.5 * fabsf (im)); |
|
COMPLEX_ASSIGN (v, r, copysignf (r, im)); |
} |
else |
{ |
float d, r, s; |
|
d = hypotf (re, im); |
/* Use the identity 2 Re res Im res = Im x |
to avoid cancellation error in d +/- Re x. */ |
if (re > 0) |
{ |
r = sqrtf (0.5 * d + 0.5 * re); |
s = (0.5 * im) / r; |
} |
else |
{ |
s = sqrtf (0.5 * d - 0.5 * re); |
r = fabsf ((0.5 * im) / s); |
} |
|
COMPLEX_ASSIGN (v, r, copysignf (s, im)); |
} |
return v; |
} |
#endif |
|
#if !defined(HAVE_CSQRT) |
#define HAVE_CSQRT 1 |
double complex csqrt (double complex z); |
|
double complex |
csqrt (double complex z) |
{ |
double re, im; |
double complex v; |
|
re = REALPART (z); |
im = IMAGPART (z); |
if (im == 0) |
{ |
if (re < 0) |
{ |
COMPLEX_ASSIGN (v, 0, copysign (sqrt (-re), im)); |
} |
else |
{ |
COMPLEX_ASSIGN (v, fabs (sqrt (re)), copysign (0, im)); |
} |
} |
else if (re == 0) |
{ |
double r; |
|
r = sqrt (0.5 * fabs (im)); |
|
COMPLEX_ASSIGN (v, r, copysign (r, im)); |
} |
else |
{ |
double d, r, s; |
|
d = hypot (re, im); |
/* Use the identity 2 Re res Im res = Im x |
to avoid cancellation error in d +/- Re x. */ |
if (re > 0) |
{ |
r = sqrt (0.5 * d + 0.5 * re); |
s = (0.5 * im) / r; |
} |
else |
{ |
s = sqrt (0.5 * d - 0.5 * re); |
r = fabs ((0.5 * im) / s); |
} |
|
COMPLEX_ASSIGN (v, r, copysign (s, im)); |
} |
return v; |
} |
#endif |
|
#if !defined(HAVE_CSQRTL) && defined(HAVE_COPYSIGNL) && defined(HAVE_SQRTL) && defined(HAVE_FABSL) && defined(HAVE_HYPOTL) |
#define HAVE_CSQRTL 1 |
long double complex csqrtl (long double complex z); |
|
long double complex |
csqrtl (long double complex z) |
{ |
long double re, im; |
long double complex v; |
|
re = REALPART (z); |
im = IMAGPART (z); |
if (im == 0) |
{ |
if (re < 0) |
{ |
COMPLEX_ASSIGN (v, 0, copysignl (sqrtl (-re), im)); |
} |
else |
{ |
COMPLEX_ASSIGN (v, fabsl (sqrtl (re)), copysignl (0, im)); |
} |
} |
else if (re == 0) |
{ |
long double r; |
|
r = sqrtl (0.5 * fabsl (im)); |
|
COMPLEX_ASSIGN (v, copysignl (r, im), r); |
} |
else |
{ |
long double d, r, s; |
|
d = hypotl (re, im); |
/* Use the identity 2 Re res Im res = Im x |
to avoid cancellation error in d +/- Re x. */ |
if (re > 0) |
{ |
r = sqrtl (0.5 * d + 0.5 * re); |
s = (0.5 * im) / r; |
} |
else |
{ |
s = sqrtl (0.5 * d - 0.5 * re); |
r = fabsl ((0.5 * im) / s); |
} |
|
COMPLEX_ASSIGN (v, r, copysignl (s, im)); |
} |
return v; |
} |
#endif |
|
|
/* sinh(a + i b) = sinh(a) cos(b) + i cosh(a) sin(b) */ |
#if !defined(HAVE_CSINHF) |
#define HAVE_CSINHF 1 |
float complex csinhf (float complex a); |
|
float complex |
csinhf (float complex a) |
{ |
float r, i; |
float complex v; |
|
r = REALPART (a); |
i = IMAGPART (a); |
COMPLEX_ASSIGN (v, sinhf (r) * cosf (i), coshf (r) * sinf (i)); |
return v; |
} |
#endif |
|
#if !defined(HAVE_CSINH) |
#define HAVE_CSINH 1 |
double complex csinh (double complex a); |
|
double complex |
csinh (double complex a) |
{ |
double r, i; |
double complex v; |
|
r = REALPART (a); |
i = IMAGPART (a); |
COMPLEX_ASSIGN (v, sinh (r) * cos (i), cosh (r) * sin (i)); |
return v; |
} |
#endif |
|
#if !defined(HAVE_CSINHL) && defined(HAVE_COSL) && defined(HAVE_COSHL) && defined(HAVE_SINL) && defined(HAVE_SINHL) |
#define HAVE_CSINHL 1 |
long double complex csinhl (long double complex a); |
|
long double complex |
csinhl (long double complex a) |
{ |
long double r, i; |
long double complex v; |
|
r = REALPART (a); |
i = IMAGPART (a); |
COMPLEX_ASSIGN (v, sinhl (r) * cosl (i), coshl (r) * sinl (i)); |
return v; |
} |
#endif |
|
|
/* cosh(a + i b) = cosh(a) cos(b) + i sinh(a) sin(b) */ |
#if !defined(HAVE_CCOSHF) |
#define HAVE_CCOSHF 1 |
float complex ccoshf (float complex a); |
|
float complex |
ccoshf (float complex a) |
{ |
float r, i; |
float complex v; |
|
r = REALPART (a); |
i = IMAGPART (a); |
COMPLEX_ASSIGN (v, coshf (r) * cosf (i), sinhf (r) * sinf (i)); |
return v; |
} |
#endif |
|
#if !defined(HAVE_CCOSH) |
#define HAVE_CCOSH 1 |
double complex ccosh (double complex a); |
|
double complex |
ccosh (double complex a) |
{ |
double r, i; |
double complex v; |
|
r = REALPART (a); |
i = IMAGPART (a); |
COMPLEX_ASSIGN (v, cosh (r) * cos (i), sinh (r) * sin (i)); |
return v; |
} |
#endif |
|
#if !defined(HAVE_CCOSHL) && defined(HAVE_COSL) && defined(HAVE_COSHL) && defined(HAVE_SINL) && defined(HAVE_SINHL) |
#define HAVE_CCOSHL 1 |
long double complex ccoshl (long double complex a); |
|
long double complex |
ccoshl (long double complex a) |
{ |
long double r, i; |
long double complex v; |
|
r = REALPART (a); |
i = IMAGPART (a); |
COMPLEX_ASSIGN (v, coshl (r) * cosl (i), sinhl (r) * sinl (i)); |
return v; |
} |
#endif |
|
|
/* tanh(a + i b) = (tanh(a) + i tan(b)) / (1 + i tanh(a) tan(b)) */ |
#if !defined(HAVE_CTANHF) |
#define HAVE_CTANHF 1 |
float complex ctanhf (float complex a); |
|
float complex |
ctanhf (float complex a) |
{ |
float rt, it; |
float complex n, d; |
|
rt = tanhf (REALPART (a)); |
it = tanf (IMAGPART (a)); |
COMPLEX_ASSIGN (n, rt, it); |
COMPLEX_ASSIGN (d, 1, rt * it); |
|
return n / d; |
} |
#endif |
|
#if !defined(HAVE_CTANH) |
#define HAVE_CTANH 1 |
double complex ctanh (double complex a); |
double complex |
ctanh (double complex a) |
{ |
double rt, it; |
double complex n, d; |
|
rt = tanh (REALPART (a)); |
it = tan (IMAGPART (a)); |
COMPLEX_ASSIGN (n, rt, it); |
COMPLEX_ASSIGN (d, 1, rt * it); |
|
return n / d; |
} |
#endif |
|
#if !defined(HAVE_CTANHL) && defined(HAVE_TANL) && defined(HAVE_TANHL) |
#define HAVE_CTANHL 1 |
long double complex ctanhl (long double complex a); |
|
long double complex |
ctanhl (long double complex a) |
{ |
long double rt, it; |
long double complex n, d; |
|
rt = tanhl (REALPART (a)); |
it = tanl (IMAGPART (a)); |
COMPLEX_ASSIGN (n, rt, it); |
COMPLEX_ASSIGN (d, 1, rt * it); |
|
return n / d; |
} |
#endif |
|
|
/* sin(a + i b) = sin(a) cosh(b) + i cos(a) sinh(b) */ |
#if !defined(HAVE_CSINF) |
#define HAVE_CSINF 1 |
float complex csinf (float complex a); |
|
float complex |
csinf (float complex a) |
{ |
float r, i; |
float complex v; |
|
r = REALPART (a); |
i = IMAGPART (a); |
COMPLEX_ASSIGN (v, sinf (r) * coshf (i), cosf (r) * sinhf (i)); |
return v; |
} |
#endif |
|
#if !defined(HAVE_CSIN) |
#define HAVE_CSIN 1 |
double complex csin (double complex a); |
|
double complex |
csin (double complex a) |
{ |
double r, i; |
double complex v; |
|
r = REALPART (a); |
i = IMAGPART (a); |
COMPLEX_ASSIGN (v, sin (r) * cosh (i), cos (r) * sinh (i)); |
return v; |
} |
#endif |
|
#if !defined(HAVE_CSINL) && defined(HAVE_COSL) && defined(HAVE_COSHL) && defined(HAVE_SINL) && defined(HAVE_SINHL) |
#define HAVE_CSINL 1 |
long double complex csinl (long double complex a); |
|
long double complex |
csinl (long double complex a) |
{ |
long double r, i; |
long double complex v; |
|
r = REALPART (a); |
i = IMAGPART (a); |
COMPLEX_ASSIGN (v, sinl (r) * coshl (i), cosl (r) * sinhl (i)); |
return v; |
} |
#endif |
|
|
/* cos(a + i b) = cos(a) cosh(b) - i sin(a) sinh(b) */ |
#if !defined(HAVE_CCOSF) |
#define HAVE_CCOSF 1 |
float complex ccosf (float complex a); |
|
float complex |
ccosf (float complex a) |
{ |
float r, i; |
float complex v; |
|
r = REALPART (a); |
i = IMAGPART (a); |
COMPLEX_ASSIGN (v, cosf (r) * coshf (i), - (sinf (r) * sinhf (i))); |
return v; |
} |
#endif |
|
#if !defined(HAVE_CCOS) |
#define HAVE_CCOS 1 |
double complex ccos (double complex a); |
|
double complex |
ccos (double complex a) |
{ |
double r, i; |
double complex v; |
|
r = REALPART (a); |
i = IMAGPART (a); |
COMPLEX_ASSIGN (v, cos (r) * cosh (i), - (sin (r) * sinh (i))); |
return v; |
} |
#endif |
|
#if !defined(HAVE_CCOSL) && defined(HAVE_COSL) && defined(HAVE_COSHL) && defined(HAVE_SINL) && defined(HAVE_SINHL) |
#define HAVE_CCOSL 1 |
long double complex ccosl (long double complex a); |
|
long double complex |
ccosl (long double complex a) |
{ |
long double r, i; |
long double complex v; |
|
r = REALPART (a); |
i = IMAGPART (a); |
COMPLEX_ASSIGN (v, cosl (r) * coshl (i), - (sinl (r) * sinhl (i))); |
return v; |
} |
#endif |
|
|
/* tan(a + i b) = (tan(a) + i tanh(b)) / (1 - i tan(a) tanh(b)) */ |
#if !defined(HAVE_CTANF) |
#define HAVE_CTANF 1 |
float complex ctanf (float complex a); |
|
float complex |
ctanf (float complex a) |
{ |
float rt, it; |
float complex n, d; |
|
rt = tanf (REALPART (a)); |
it = tanhf (IMAGPART (a)); |
COMPLEX_ASSIGN (n, rt, it); |
COMPLEX_ASSIGN (d, 1, - (rt * it)); |
|
return n / d; |
} |
#endif |
|
#if !defined(HAVE_CTAN) |
#define HAVE_CTAN 1 |
double complex ctan (double complex a); |
|
double complex |
ctan (double complex a) |
{ |
double rt, it; |
double complex n, d; |
|
rt = tan (REALPART (a)); |
it = tanh (IMAGPART (a)); |
COMPLEX_ASSIGN (n, rt, it); |
COMPLEX_ASSIGN (d, 1, - (rt * it)); |
|
return n / d; |
} |
#endif |
|
#if !defined(HAVE_CTANL) && defined(HAVE_TANL) && defined(HAVE_TANHL) |
#define HAVE_CTANL 1 |
long double complex ctanl (long double complex a); |
|
long double complex |
ctanl (long double complex a) |
{ |
long double rt, it; |
long double complex n, d; |
|
rt = tanl (REALPART (a)); |
it = tanhl (IMAGPART (a)); |
COMPLEX_ASSIGN (n, rt, it); |
COMPLEX_ASSIGN (d, 1, - (rt * it)); |
|
return n / d; |
} |
#endif |
|
|
/* Complex ASIN. Returns wrongly NaN for infinite arguments. |
Algorithm taken from Abramowitz & Stegun. */ |
|
#if !defined(HAVE_CASINF) && defined(HAVE_CLOGF) && defined(HAVE_CSQRTF) |
#define HAVE_CASINF 1 |
complex float casinf (complex float z); |
|
complex float |
casinf (complex float z) |
{ |
return -I*clogf (I*z + csqrtf (1.0f-z*z)); |
} |
#endif |
|
|
#if !defined(HAVE_CASIN) && defined(HAVE_CLOG) && defined(HAVE_CSQRT) |
#define HAVE_CASIN 1 |
complex double casin (complex double z); |
|
complex double |
casin (complex double z) |
{ |
return -I*clog (I*z + csqrt (1.0-z*z)); |
} |
#endif |
|
|
#if !defined(HAVE_CASINL) && defined(HAVE_CLOGL) && defined(HAVE_CSQRTL) |
#define HAVE_CASINL 1 |
complex long double casinl (complex long double z); |
|
complex long double |
casinl (complex long double z) |
{ |
return -I*clogl (I*z + csqrtl (1.0L-z*z)); |
} |
#endif |
|
|
/* Complex ACOS. Returns wrongly NaN for infinite arguments. |
Algorithm taken from Abramowitz & Stegun. */ |
|
#if !defined(HAVE_CACOSF) && defined(HAVE_CLOGF) && defined(HAVE_CSQRTF) |
#define HAVE_CACOSF 1 |
complex float cacosf (complex float z); |
|
complex float |
cacosf (complex float z) |
{ |
return -I*clogf (z + I*csqrtf (1.0f-z*z)); |
} |
#endif |
|
|
#if !defined(HAVE_CACOS) && defined(HAVE_CLOG) && defined(HAVE_CSQRT) |
#define HAVE_CACOS 1 |
complex double cacos (complex double z); |
|
complex double |
cacos (complex double z) |
{ |
return -I*clog (z + I*csqrt (1.0-z*z)); |
} |
#endif |
|
|
#if !defined(HAVE_CACOSL) && defined(HAVE_CLOGL) && defined(HAVE_CSQRTL) |
#define HAVE_CACOSL 1 |
complex long double cacosl (complex long double z); |
|
complex long double |
cacosl (complex long double z) |
{ |
return -I*clogl (z + I*csqrtl (1.0L-z*z)); |
} |
#endif |
|
|
/* Complex ATAN. Returns wrongly NaN for infinite arguments. |
Algorithm taken from Abramowitz & Stegun. */ |
|
#if !defined(HAVE_CATANF) && defined(HAVE_CLOGF) |
#define HAVE_CACOSF 1 |
complex float catanf (complex float z); |
|
complex float |
catanf (complex float z) |
{ |
return I*clogf ((I+z)/(I-z))/2.0f; |
} |
#endif |
|
|
#if !defined(HAVE_CATAN) && defined(HAVE_CLOG) |
#define HAVE_CACOS 1 |
complex double catan (complex double z); |
|
complex double |
catan (complex double z) |
{ |
return I*clog ((I+z)/(I-z))/2.0; |
} |
#endif |
|
|
#if !defined(HAVE_CATANL) && defined(HAVE_CLOGL) |
#define HAVE_CACOSL 1 |
complex long double catanl (complex long double z); |
|
complex long double |
catanl (complex long double z) |
{ |
return I*clogl ((I+z)/(I-z))/2.0L; |
} |
#endif |
|
|
/* Complex ASINH. Returns wrongly NaN for infinite arguments. |
Algorithm taken from Abramowitz & Stegun. */ |
|
#if !defined(HAVE_CASINHF) && defined(HAVE_CLOGF) && defined(HAVE_CSQRTF) |
#define HAVE_CASINHF 1 |
complex float casinhf (complex float z); |
|
complex float |
casinhf (complex float z) |
{ |
return clogf (z + csqrtf (z*z+1.0f)); |
} |
#endif |
|
|
#if !defined(HAVE_CASINH) && defined(HAVE_CLOG) && defined(HAVE_CSQRT) |
#define HAVE_CASINH 1 |
complex double casinh (complex double z); |
|
complex double |
casinh (complex double z) |
{ |
return clog (z + csqrt (z*z+1.0)); |
} |
#endif |
|
|
#if !defined(HAVE_CASINHL) && defined(HAVE_CLOGL) && defined(HAVE_CSQRTL) |
#define HAVE_CASINHL 1 |
complex long double casinhl (complex long double z); |
|
complex long double |
casinhl (complex long double z) |
{ |
return clogl (z + csqrtl (z*z+1.0L)); |
} |
#endif |
|
|
/* Complex ACOSH. Returns wrongly NaN for infinite arguments. |
Algorithm taken from Abramowitz & Stegun. */ |
|
#if !defined(HAVE_CACOSHF) && defined(HAVE_CLOGF) && defined(HAVE_CSQRTF) |
#define HAVE_CACOSHF 1 |
complex float cacoshf (complex float z); |
|
complex float |
cacoshf (complex float z) |
{ |
return clogf (z + csqrtf (z-1.0f) * csqrtf (z+1.0f)); |
} |
#endif |
|
|
#if !defined(HAVE_CACOSH) && defined(HAVE_CLOG) && defined(HAVE_CSQRT) |
#define HAVE_CACOSH 1 |
complex double cacosh (complex double z); |
|
complex double |
cacosh (complex double z) |
{ |
return clog (z + csqrt (z-1.0) * csqrt (z+1.0)); |
} |
#endif |
|
|
#if !defined(HAVE_CACOSHL) && defined(HAVE_CLOGL) && defined(HAVE_CSQRTL) |
#define HAVE_CACOSHL 1 |
complex long double cacoshl (complex long double z); |
|
complex long double |
cacoshl (complex long double z) |
{ |
return clogl (z + csqrtl (z-1.0L) * csqrtl (z+1.0L)); |
} |
#endif |
|
|
/* Complex ATANH. Returns wrongly NaN for infinite arguments. |
Algorithm taken from Abramowitz & Stegun. */ |
|
#if !defined(HAVE_CATANHF) && defined(HAVE_CLOGF) |
#define HAVE_CATANHF 1 |
complex float catanhf (complex float z); |
|
complex float |
catanhf (complex float z) |
{ |
return clogf ((1.0f+z)/(1.0f-z))/2.0f; |
} |
#endif |
|
|
#if !defined(HAVE_CATANH) && defined(HAVE_CLOG) |
#define HAVE_CATANH 1 |
complex double catanh (complex double z); |
|
complex double |
catanh (complex double z) |
{ |
return clog ((1.0+z)/(1.0-z))/2.0; |
} |
#endif |
|
#if !defined(HAVE_CATANHL) && defined(HAVE_CLOGL) |
#define HAVE_CATANHL 1 |
complex long double catanhl (complex long double z); |
|
complex long double |
catanhl (complex long double z) |
{ |
return clogl ((1.0L+z)/(1.0L-z))/2.0L; |
} |
#endif |
|
|
#if !defined(HAVE_TGAMMA) |
#define HAVE_TGAMMA 1 |
double tgamma (double); |
|
/* Fallback tgamma() function. Uses the algorithm from |
http://www.netlib.org/specfun/gamma and references therein. */ |
|
#undef SQRTPI |
#define SQRTPI 0.9189385332046727417803297 |
|
#undef PI |
#define PI 3.1415926535897932384626434 |
|
double |
tgamma (double x) |
{ |
int i, n, parity; |
double fact, res, sum, xden, xnum, y, y1, ysq, z; |
|
static double p[8] = { |
-1.71618513886549492533811e0, 2.47656508055759199108314e1, |
-3.79804256470945635097577e2, 6.29331155312818442661052e2, |
8.66966202790413211295064e2, -3.14512729688483675254357e4, |
-3.61444134186911729807069e4, 6.64561438202405440627855e4 }; |
|
static double q[8] = { |
-3.08402300119738975254353e1, 3.15350626979604161529144e2, |
-1.01515636749021914166146e3, -3.10777167157231109440444e3, |
2.25381184209801510330112e4, 4.75584627752788110767815e3, |
-1.34659959864969306392456e5, -1.15132259675553483497211e5 }; |
|
static double c[7] = { -1.910444077728e-03, |
8.4171387781295e-04, -5.952379913043012e-04, |
7.93650793500350248e-04, -2.777777777777681622553e-03, |
8.333333333333333331554247e-02, 5.7083835261e-03 }; |
|
static const double xminin = 2.23e-308; |
static const double xbig = 171.624; |
static const double xnan = __builtin_nan ("0x0"), xinf = __builtin_inf (); |
static double eps = 0; |
|
if (eps == 0) |
eps = nextafter (1., 2.) - 1.; |
|
parity = 0; |
fact = 1; |
n = 0; |
y = x; |
|
if (isnan (x)) |
return x; |
|
if (y <= 0) |
{ |
y = -x; |
y1 = trunc (y); |
res = y - y1; |
|
if (res != 0) |
{ |
if (y1 != trunc (y1*0.5l)*2) |
parity = 1; |
fact = -PI / sin (PI*res); |
y = y + 1; |
} |
else |
return x == 0 ? copysign (xinf, x) : xnan; |
} |
|
if (y < eps) |
{ |
if (y >= xminin) |
res = 1 / y; |
else |
return xinf; |
} |
else if (y < 13) |
{ |
y1 = y; |
if (y < 1) |
{ |
z = y; |
y = y + 1; |
} |
else |
{ |
n = (int)y - 1; |
y = y - n; |
z = y - 1; |
} |
|
xnum = 0; |
xden = 1; |
for (i = 0; i < 8; i++) |
{ |
xnum = (xnum + p[i]) * z; |
xden = xden * z + q[i]; |
} |
|
res = xnum / xden + 1; |
|
if (y1 < y) |
res = res / y1; |
else if (y1 > y) |
for (i = 1; i <= n; i++) |
{ |
res = res * y; |
y = y + 1; |
} |
} |
else |
{ |
if (y < xbig) |
{ |
ysq = y * y; |
sum = c[6]; |
for (i = 0; i < 6; i++) |
sum = sum / ysq + c[i]; |
|
sum = sum/y - y + SQRTPI; |
sum = sum + (y - 0.5) * log (y); |
res = exp (sum); |
} |
else |
return x < 0 ? xnan : xinf; |
} |
|
if (parity) |
res = -res; |
if (fact != 1) |
res = fact / res; |
|
return res; |
} |
#endif |
|
|
|
#if !defined(HAVE_LGAMMA) |
#define HAVE_LGAMMA 1 |
double lgamma (double); |
|
/* Fallback lgamma() function. Uses the algorithm from |
http://www.netlib.org/specfun/algama and references therein, |
except for negative arguments (where netlib would return +Inf) |
where we use the following identity: |
lgamma(y) = log(pi/(|y*sin(pi*y)|)) - lgamma(-y) |
*/ |
|
double |
lgamma (double y) |
{ |
|
#undef SQRTPI |
#define SQRTPI 0.9189385332046727417803297 |
|
#undef PI |
#define PI 3.1415926535897932384626434 |
|
#define PNT68 0.6796875 |
#define D1 -0.5772156649015328605195174 |
#define D2 0.4227843350984671393993777 |
#define D4 1.791759469228055000094023 |
|
static double p1[8] = { |
4.945235359296727046734888e0, 2.018112620856775083915565e2, |
2.290838373831346393026739e3, 1.131967205903380828685045e4, |
2.855724635671635335736389e4, 3.848496228443793359990269e4, |
2.637748787624195437963534e4, 7.225813979700288197698961e3 }; |
static double q1[8] = { |
6.748212550303777196073036e1, 1.113332393857199323513008e3, |
7.738757056935398733233834e3, 2.763987074403340708898585e4, |
5.499310206226157329794414e4, 6.161122180066002127833352e4, |
3.635127591501940507276287e4, 8.785536302431013170870835e3 }; |
static double p2[8] = { |
4.974607845568932035012064e0, 5.424138599891070494101986e2, |
1.550693864978364947665077e4, 1.847932904445632425417223e5, |
1.088204769468828767498470e6, 3.338152967987029735917223e6, |
5.106661678927352456275255e6, 3.074109054850539556250927e6 }; |
static double q2[8] = { |
1.830328399370592604055942e2, 7.765049321445005871323047e3, |
1.331903827966074194402448e5, 1.136705821321969608938755e6, |
5.267964117437946917577538e6, 1.346701454311101692290052e7, |
1.782736530353274213975932e7, 9.533095591844353613395747e6 }; |
static double p4[8] = { |
1.474502166059939948905062e4, 2.426813369486704502836312e6, |
1.214755574045093227939592e8, 2.663432449630976949898078e9, |
2.940378956634553899906876e10, 1.702665737765398868392998e11, |
4.926125793377430887588120e11, 5.606251856223951465078242e11 }; |
static double q4[8] = { |
2.690530175870899333379843e3, 6.393885654300092398984238e5, |
4.135599930241388052042842e7, 1.120872109616147941376570e9, |
1.488613728678813811542398e10, 1.016803586272438228077304e11, |
3.417476345507377132798597e11, 4.463158187419713286462081e11 }; |
static double c[7] = { |
-1.910444077728e-03, 8.4171387781295e-04, |
-5.952379913043012e-04, 7.93650793500350248e-04, |
-2.777777777777681622553e-03, 8.333333333333333331554247e-02, |
5.7083835261e-03 }; |
|
static double xbig = 2.55e305, xinf = __builtin_inf (), eps = 0, |
frtbig = 2.25e76; |
|
int i; |
double corr, res, xden, xm1, xm2, xm4, xnum, ysq; |
|
if (eps == 0) |
eps = __builtin_nextafter (1., 2.) - 1.; |
|
if ((y > 0) && (y <= xbig)) |
{ |
if (y <= eps) |
res = -log (y); |
else if (y <= 1.5) |
{ |
if (y < PNT68) |
{ |
corr = -log (y); |
xm1 = y; |
} |
else |
{ |
corr = 0; |
xm1 = (y - 0.5) - 0.5; |
} |
|
if ((y <= 0.5) || (y >= PNT68)) |
{ |
xden = 1; |
xnum = 0; |
for (i = 0; i < 8; i++) |
{ |
xnum = xnum*xm1 + p1[i]; |
xden = xden*xm1 + q1[i]; |
} |
res = corr + (xm1 * (D1 + xm1*(xnum/xden))); |
} |
else |
{ |
xm2 = (y - 0.5) - 0.5; |
xden = 1; |
xnum = 0; |
for (i = 0; i < 8; i++) |
{ |
xnum = xnum*xm2 + p2[i]; |
xden = xden*xm2 + q2[i]; |
} |
res = corr + xm2 * (D2 + xm2*(xnum/xden)); |
} |
} |
else if (y <= 4) |
{ |
xm2 = y - 2; |
xden = 1; |
xnum = 0; |
for (i = 0; i < 8; i++) |
{ |
xnum = xnum*xm2 + p2[i]; |
xden = xden*xm2 + q2[i]; |
} |
res = xm2 * (D2 + xm2*(xnum/xden)); |
} |
else if (y <= 12) |
{ |
xm4 = y - 4; |
xden = -1; |
xnum = 0; |
for (i = 0; i < 8; i++) |
{ |
xnum = xnum*xm4 + p4[i]; |
xden = xden*xm4 + q4[i]; |
} |
res = D4 + xm4*(xnum/xden); |
} |
else |
{ |
res = 0; |
if (y <= frtbig) |
{ |
res = c[6]; |
ysq = y * y; |
for (i = 0; i < 6; i++) |
res = res / ysq + c[i]; |
} |
res = res/y; |
corr = log (y); |
res = res + SQRTPI - 0.5*corr; |
res = res + y*(corr-1); |
} |
} |
else if (y < 0 && __builtin_floor (y) != y) |
{ |
/* lgamma(y) = log(pi/(|y*sin(pi*y)|)) - lgamma(-y) |
For abs(y) very close to zero, we use a series expansion to |
the first order in y to avoid overflow. */ |
if (y > -1.e-100) |
res = -2 * log (fabs (y)) - lgamma (-y); |
else |
res = log (PI / fabs (y * sin (PI * y))) - lgamma (-y); |
} |
else |
res = xinf; |
|
return res; |
} |
#endif |
|
|
#if defined(HAVE_TGAMMA) && !defined(HAVE_TGAMMAF) |
#define HAVE_TGAMMAF 1 |
float tgammaf (float); |
|
float |
tgammaf (float x) |
{ |
return (float) tgamma ((double) x); |
} |
#endif |
|
#if defined(HAVE_LGAMMA) && !defined(HAVE_LGAMMAF) |
#define HAVE_LGAMMAF 1 |
float lgammaf (float); |
|
float |
lgammaf (float x) |
{ |
return (float) lgamma ((double) x); |
} |
#endif |
/dprod_r8.f90
0,0 → 1,32
! Copyright 2003, 2009 Free Software Foundation, Inc. |
! Contributed by Paul Brook <paul@nowt.org> |
! |
!This file is part of the GNU Fortran 95 runtime library (libgfortran). |
! |
!Libgfortran is free software; you can redistribute it and/or |
!modify it under the terms of the GNU General Public |
!License as published by the Free Software Foundation; either |
!version 3 of the License, or (at your option) any later version. |
! |
!Libgfortran is distributed in the hope that it will be useful, |
!but WITHOUT ANY WARRANTY; without even the implied warranty of |
!MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
!GNU General Public License for more details. |
! |
!Under Section 7 of GPL version 3, you are granted additional |
!permissions described in the GCC Runtime Library Exception, version |
!3.1, as published by the Free Software Foundation. |
! |
!You should have received a copy of the GNU General Public License and |
!a copy of the GCC Runtime Library Exception along with this program; |
!see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
!<http://www.gnu.org/licenses/>. |
|
|
elemental function _gfortran_specific__dprod_r8 (p1, p2) |
implicit none |
real (kind=4), intent (in) :: p1, p2 |
real (kind=8) :: _gfortran_specific__dprod_r8 |
|
_gfortran_specific__dprod_r8 = dprod (p1, p2) |
end function |
/ierrno.c
0,0 → 1,49
/* Implementation of the IERRNO intrinsic. |
Copyright (C) 2005, 2007, 2009 Free Software Foundation, Inc. |
Contributed by François-Xavier Coudert <coudert@clipper.ens.fr> |
|
This file is part of the GNU Fortran 95 runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
|
#include <errno.h> |
|
|
/* INTEGER FUNCTION IERRNO() */ |
|
extern GFC_INTEGER_4 ierrno_i4 (void); |
export_proto(ierrno_i4); |
|
GFC_INTEGER_4 |
ierrno_i4 (void) |
{ |
return (GFC_INTEGER_4) errno; |
} |
|
extern GFC_INTEGER_8 ierrno_i8 (void); |
export_proto(ierrno_i8); |
|
GFC_INTEGER_8 |
ierrno_i8 (void) |
{ |
return (GFC_INTEGER_8) errno; |
} |
/system_clock.c
0,0 → 1,207
/* Implementation of the SYSTEM_CLOCK intrinsic. |
Copyright (C) 2004, 2005, 2007, 2009, 2010, 2011 Free Software |
Foundation, Inc. |
|
This file is part of the GNU Fortran runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
|
#include <limits.h> |
|
#include "time_1.h" |
|
|
/* POSIX states that CLOCK_REALTIME must be present if clock_gettime |
is available, others are optional. */ |
#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_CLOCK_GETTIME_LIBRT) |
#ifdef CLOCK_MONOTONIC |
#define GF_CLOCK_MONOTONIC CLOCK_MONOTONIC |
#else |
#define GF_CLOCK_MONOTONIC CLOCK_REALTIME |
#endif |
#endif |
|
/* Weakref trickery for clock_gettime(). On Glibc, clock_gettime() |
requires us to link in librt, which also pulls in libpthread. In |
order to avoid this by default, only call clock_gettime() through a |
weak reference. |
|
Some targets don't support weak undefined references; on these |
GTHREAD_USE_WEAK is 0. So we need to define it to 1 on other |
targets. */ |
#ifndef GTHREAD_USE_WEAK |
#define GTHREAD_USE_WEAK 1 |
#endif |
|
#if SUPPORTS_WEAK && GTHREAD_USE_WEAK && defined(HAVE_CLOCK_GETTIME_LIBRT) |
static int weak_gettime (clockid_t, struct timespec *) |
__attribute__((__weakref__("clock_gettime"))); |
#endif |
|
|
/* High resolution monotonic clock, falling back to the realtime clock |
if the target does not support such a clock. |
|
Arguments: |
secs - OUTPUT, seconds |
nanosecs - OUTPUT, nanoseconds |
|
If the target supports a monotonic clock, the OUTPUT arguments |
represent a monotonically incrementing clock starting from some |
unspecified time in the past. |
|
If a monotonic clock is not available, falls back to the realtime |
clock which is not monotonic. |
|
Return value: 0 for success, -1 for error. In case of error, errno |
is set. |
*/ |
static int |
gf_gettime_mono (time_t * secs, long * nanosecs) |
{ |
int err; |
#ifdef HAVE_CLOCK_GETTIME |
struct timespec ts; |
err = clock_gettime (GF_CLOCK_MONOTONIC, &ts); |
*secs = ts.tv_sec; |
*nanosecs = ts.tv_nsec; |
return err; |
#else |
#if defined(HAVE_CLOCK_GETTIME_LIBRT) && SUPPORTS_WEAK && GTHREAD_USE_WEAK |
if (weak_gettime) |
{ |
struct timespec ts; |
err = weak_gettime (GF_CLOCK_MONOTONIC, &ts); |
*secs = ts.tv_sec; |
*nanosecs = ts.tv_nsec; |
return err; |
} |
#endif |
err = gf_gettime (secs, nanosecs); |
*nanosecs *= 1000; |
return err; |
#endif |
} |
|
extern void system_clock_4 (GFC_INTEGER_4 *, GFC_INTEGER_4 *, GFC_INTEGER_4 *); |
export_proto(system_clock_4); |
|
extern void system_clock_8 (GFC_INTEGER_8 *, GFC_INTEGER_8 *, GFC_INTEGER_8 *); |
export_proto(system_clock_8); |
|
|
/* prefix(system_clock_4) is the INTEGER(4) version of the SYSTEM_CLOCK |
intrinsic subroutine. It returns the number of clock ticks for the current |
system time, the number of ticks per second, and the maximum possible value |
for COUNT. On the first call to SYSTEM_CLOCK, COUNT is set to zero. */ |
|
void |
system_clock_4(GFC_INTEGER_4 *count, GFC_INTEGER_4 *count_rate, |
GFC_INTEGER_4 *count_max) |
{ |
#undef TCK |
#define TCK 1000 |
GFC_INTEGER_4 cnt; |
GFC_INTEGER_4 mx; |
|
time_t secs; |
long nanosecs; |
|
if (sizeof (secs) < sizeof (GFC_INTEGER_4)) |
internal_error (NULL, "secs too small"); |
|
if (gf_gettime_mono (&secs, &nanosecs) == 0) |
{ |
GFC_UINTEGER_4 ucnt = (GFC_UINTEGER_4) secs * TCK; |
ucnt += (nanosecs + 500000000 / TCK) / (1000000000 / TCK); |
if (ucnt > GFC_INTEGER_4_HUGE) |
cnt = ucnt - GFC_INTEGER_4_HUGE - 1; |
else |
cnt = ucnt; |
mx = GFC_INTEGER_4_HUGE; |
} |
else |
{ |
if (count != NULL) |
*count = - GFC_INTEGER_4_HUGE; |
if (count_rate != NULL) |
*count_rate = 0; |
if (count_max != NULL) |
*count_max = 0; |
return; |
} |
|
if (count != NULL) |
*count = cnt; |
if (count_rate != NULL) |
*count_rate = TCK; |
if (count_max != NULL) |
*count_max = mx; |
} |
|
|
/* INTEGER(8) version of the above routine. */ |
|
void |
system_clock_8 (GFC_INTEGER_8 *count, GFC_INTEGER_8 *count_rate, |
GFC_INTEGER_8 *count_max) |
{ |
#undef TCK |
#define TCK 1000000000 |
GFC_INTEGER_8 cnt; |
GFC_INTEGER_8 mx; |
|
time_t secs; |
long nanosecs; |
|
if (sizeof (secs) < sizeof (GFC_INTEGER_4)) |
internal_error (NULL, "secs too small"); |
|
if (gf_gettime_mono (&secs, &nanosecs) == 0) |
{ |
GFC_UINTEGER_8 ucnt = (GFC_UINTEGER_8) secs * TCK; |
ucnt += (nanosecs + 500000000 / TCK) / (1000000000 / TCK); |
if (ucnt > GFC_INTEGER_8_HUGE) |
cnt = ucnt - GFC_INTEGER_8_HUGE - 1; |
else |
cnt = ucnt; |
mx = GFC_INTEGER_8_HUGE; |
} |
else |
{ |
if (count != NULL) |
*count = - GFC_INTEGER_8_HUGE; |
if (count_rate != NULL) |
*count_rate = 0; |
if (count_max != NULL) |
*count_max = 0; |
|
return; |
} |
|
if (count != NULL) |
*count = cnt; |
if (count_rate != NULL) |
*count_rate = TCK; |
if (count_max != NULL) |
*count_max = mx; |
} |
/unlink.c
0,0 → 1,91
/* Implementation of the UNLINK intrinsic. |
Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc. |
Contributed by Steven G. Kargl <kargls@comcast.net>. |
|
This file is part of the GNU Fortran 95 runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
|
#include <string.h> |
#include <errno.h> |
|
#ifdef HAVE_UNISTD_H |
#include <unistd.h> |
#endif |
|
/* SUBROUTINE UNLINK(NAME, STATUS) |
CHARACTER(LEN= ), INTENT(IN) :: NAME |
INTEGER, INTENT(OUT), OPTIONAL :: STATUS) */ |
|
extern void unlink_i4_sub (char *name, GFC_INTEGER_4 *status, |
gfc_charlen_type name_len); |
iexport_proto(unlink_i4_sub); |
|
void |
unlink_i4_sub (char *name, GFC_INTEGER_4 *status, gfc_charlen_type name_len) |
{ |
char *str; |
GFC_INTEGER_4 stat; |
|
/* Trim trailing spaces from name. */ |
while (name_len > 0 && name[name_len - 1] == ' ') |
name_len--; |
|
/* Make a null terminated copy of the string. */ |
str = gfc_alloca (name_len + 1); |
memcpy (str, name, name_len); |
str[name_len] = '\0'; |
|
stat = unlink (str); |
|
if (status != NULL) |
*status = (stat == 0) ? stat : errno; |
} |
iexport(unlink_i4_sub); |
|
extern void unlink_i8_sub (char *name, GFC_INTEGER_8 *status, |
gfc_charlen_type name_len); |
export_proto(unlink_i8_sub); |
|
void |
unlink_i8_sub (char *name, GFC_INTEGER_8 *status, gfc_charlen_type name_len) |
{ |
GFC_INTEGER_4 status4; |
unlink_i4_sub (name, &status4, name_len); |
if (status) |
*status = status4; |
} |
|
|
/* INTEGER FUNCTION UNLINK(NAME) |
CHARACTER(LEN= ), INTENT(IN) :: NAME */ |
|
extern GFC_INTEGER_4 PREFIX(unlink) (char *, gfc_charlen_type); |
export_proto_np(PREFIX(unlink)); |
|
GFC_INTEGER_4 |
PREFIX(unlink) (char *name, gfc_charlen_type name_len) |
{ |
GFC_INTEGER_4 status; |
unlink_i4_sub (name, &status, name_len); |
return status; |
} |
/cshift0.c
0,0 → 1,452
/* Generic implementation of the CSHIFT intrinsic |
Copyright 2003, 2005, 2006, 2007, 2010 Free Software Foundation, Inc. |
Contributed by Feng Wang <wf_cs@yahoo.com> |
|
This file is part of the GNU Fortran runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
#include <stdlib.h> |
#include <assert.h> |
#include <string.h> |
|
static void |
cshift0 (gfc_array_char * ret, const gfc_array_char * array, |
ptrdiff_t shift, int which, index_type size) |
{ |
/* r.* indicates the return array. */ |
index_type rstride[GFC_MAX_DIMENSIONS]; |
index_type rstride0; |
index_type roffset; |
char *rptr; |
|
/* s.* indicates the source array. */ |
index_type sstride[GFC_MAX_DIMENSIONS]; |
index_type sstride0; |
index_type soffset; |
const char *sptr; |
|
index_type count[GFC_MAX_DIMENSIONS]; |
index_type extent[GFC_MAX_DIMENSIONS]; |
index_type dim; |
index_type len; |
index_type n; |
index_type arraysize; |
|
index_type type_size; |
|
if (which < 1 || which > GFC_DESCRIPTOR_RANK (array)) |
runtime_error ("Argument 'DIM' is out of range in call to 'CSHIFT'"); |
|
arraysize = size0 ((array_t *) array); |
|
if (ret->data == NULL) |
{ |
int i; |
|
ret->offset = 0; |
ret->dtype = array->dtype; |
for (i = 0; i < GFC_DESCRIPTOR_RANK (array); i++) |
{ |
index_type ub, str; |
|
ub = GFC_DESCRIPTOR_EXTENT(array,i) - 1; |
|
if (i == 0) |
str = 1; |
else |
str = GFC_DESCRIPTOR_EXTENT(ret,i-1) * |
GFC_DESCRIPTOR_STRIDE(ret,i-1); |
|
GFC_DIMENSION_SET(ret->dim[i], 0, ub, str); |
} |
|
/* internal_malloc_size allocates a single byte for zero size. */ |
ret->data = internal_malloc_size (size * arraysize); |
} |
else if (unlikely (compile_options.bounds_check)) |
{ |
bounds_equal_extents ((array_t *) ret, (array_t *) array, |
"return value", "CSHIFT"); |
} |
|
if (arraysize == 0) |
return; |
|
type_size = GFC_DTYPE_TYPE_SIZE (array); |
|
switch(type_size) |
{ |
case GFC_DTYPE_LOGICAL_1: |
case GFC_DTYPE_INTEGER_1: |
case GFC_DTYPE_DERIVED_1: |
cshift0_i1 ((gfc_array_i1 *)ret, (gfc_array_i1 *) array, shift, which); |
return; |
|
case GFC_DTYPE_LOGICAL_2: |
case GFC_DTYPE_INTEGER_2: |
cshift0_i2 ((gfc_array_i2 *)ret, (gfc_array_i2 *) array, shift, which); |
return; |
|
case GFC_DTYPE_LOGICAL_4: |
case GFC_DTYPE_INTEGER_4: |
cshift0_i4 ((gfc_array_i4 *)ret, (gfc_array_i4 *) array, shift, which); |
return; |
|
case GFC_DTYPE_LOGICAL_8: |
case GFC_DTYPE_INTEGER_8: |
cshift0_i8 ((gfc_array_i8 *)ret, (gfc_array_i8 *) array, shift, which); |
return; |
|
#ifdef HAVE_GFC_INTEGER_16 |
case GFC_DTYPE_LOGICAL_16: |
case GFC_DTYPE_INTEGER_16: |
cshift0_i16 ((gfc_array_i16 *)ret, (gfc_array_i16 *) array, shift, |
which); |
return; |
#endif |
|
case GFC_DTYPE_REAL_4: |
cshift0_r4 ((gfc_array_r4 *)ret, (gfc_array_r4 *) array, shift, which); |
return; |
|
case GFC_DTYPE_REAL_8: |
cshift0_r8 ((gfc_array_r8 *)ret, (gfc_array_r8 *) array, shift, which); |
return; |
|
/* FIXME: This here is a hack, which will have to be removed when |
the array descriptor is reworked. Currently, we don't store the |
kind value for the type, but only the size. Because on targets with |
__float128, we have sizeof(logn double) == sizeof(__float128), |
we cannot discriminate here and have to fall back to the generic |
handling (which is suboptimal). */ |
#if !defined(GFC_REAL_16_IS_FLOAT128) |
# ifdef HAVE_GFC_REAL_10 |
case GFC_DTYPE_REAL_10: |
cshift0_r10 ((gfc_array_r10 *)ret, (gfc_array_r10 *) array, shift, |
which); |
return; |
# endif |
|
# ifdef HAVE_GFC_REAL_16 |
case GFC_DTYPE_REAL_16: |
cshift0_r16 ((gfc_array_r16 *)ret, (gfc_array_r16 *) array, shift, |
which); |
return; |
# endif |
#endif |
|
case GFC_DTYPE_COMPLEX_4: |
cshift0_c4 ((gfc_array_c4 *)ret, (gfc_array_c4 *) array, shift, which); |
return; |
|
case GFC_DTYPE_COMPLEX_8: |
cshift0_c8 ((gfc_array_c8 *)ret, (gfc_array_c8 *) array, shift, which); |
return; |
|
/* FIXME: This here is a hack, which will have to be removed when |
the array descriptor is reworked. Currently, we don't store the |
kind value for the type, but only the size. Because on targets with |
__float128, we have sizeof(logn double) == sizeof(__float128), |
we cannot discriminate here and have to fall back to the generic |
handling (which is suboptimal). */ |
#if !defined(GFC_REAL_16_IS_FLOAT128) |
# ifdef HAVE_GFC_COMPLEX_10 |
case GFC_DTYPE_COMPLEX_10: |
cshift0_c10 ((gfc_array_c10 *)ret, (gfc_array_c10 *) array, shift, |
which); |
return; |
# endif |
|
# ifdef HAVE_GFC_COMPLEX_16 |
case GFC_DTYPE_COMPLEX_16: |
cshift0_c16 ((gfc_array_c16 *)ret, (gfc_array_c16 *) array, shift, |
which); |
return; |
# endif |
#endif |
|
default: |
break; |
} |
|
switch (size) |
{ |
/* Let's check the actual alignment of the data pointers. If they |
are suitably aligned, we can safely call the unpack functions. */ |
|
case sizeof (GFC_INTEGER_1): |
cshift0_i1 ((gfc_array_i1 *) ret, (gfc_array_i1 *) array, shift, |
which); |
break; |
|
case sizeof (GFC_INTEGER_2): |
if (GFC_UNALIGNED_2(ret->data) || GFC_UNALIGNED_2(array->data)) |
break; |
else |
{ |
cshift0_i2 ((gfc_array_i2 *) ret, (gfc_array_i2 *) array, shift, |
which); |
return; |
} |
|
case sizeof (GFC_INTEGER_4): |
if (GFC_UNALIGNED_4(ret->data) || GFC_UNALIGNED_4(array->data)) |
break; |
else |
{ |
cshift0_i4 ((gfc_array_i4 *)ret, (gfc_array_i4 *) array, shift, |
which); |
return; |
} |
|
case sizeof (GFC_INTEGER_8): |
if (GFC_UNALIGNED_8(ret->data) || GFC_UNALIGNED_8(array->data)) |
{ |
/* Let's try to use the complex routines. First, a sanity |
check that the sizes match; this should be optimized to |
a no-op. */ |
if (sizeof(GFC_INTEGER_8) != sizeof(GFC_COMPLEX_4)) |
break; |
|
if (GFC_UNALIGNED_C4(ret->data) || GFC_UNALIGNED_C4(array->data)) |
break; |
|
cshift0_c4 ((gfc_array_c4 *) ret, (gfc_array_c4 *) array, shift, |
which); |
return; |
} |
else |
{ |
cshift0_i8 ((gfc_array_i8 *)ret, (gfc_array_i8 *) array, shift, |
which); |
return; |
} |
|
#ifdef HAVE_GFC_INTEGER_16 |
case sizeof (GFC_INTEGER_16): |
if (GFC_UNALIGNED_16(ret->data) || GFC_UNALIGNED_16(array->data)) |
{ |
/* Let's try to use the complex routines. First, a sanity |
check that the sizes match; this should be optimized to |
a no-op. */ |
if (sizeof(GFC_INTEGER_16) != sizeof(GFC_COMPLEX_8)) |
break; |
|
if (GFC_UNALIGNED_C8(ret->data) || GFC_UNALIGNED_C8(array->data)) |
break; |
|
cshift0_c8 ((gfc_array_c8 *) ret, (gfc_array_c8 *) array, shift, |
which); |
return; |
} |
else |
{ |
cshift0_i16 ((gfc_array_i16 *) ret, (gfc_array_i16 *) array, |
shift, which); |
return; |
} |
#else |
case sizeof (GFC_COMPLEX_8): |
|
if (GFC_UNALIGNED_C8(ret->data) || GFC_UNALIGNED_C8(array->data)) |
break; |
else |
{ |
cshift0_c8 ((gfc_array_c8 *) ret, (gfc_array_c8 *) array, shift, |
which); |
return; |
} |
#endif |
|
default: |
break; |
} |
|
|
which = which - 1; |
sstride[0] = 0; |
rstride[0] = 0; |
|
extent[0] = 1; |
count[0] = 0; |
n = 0; |
/* Initialized for avoiding compiler warnings. */ |
roffset = size; |
soffset = size; |
len = 0; |
|
for (dim = 0; dim < GFC_DESCRIPTOR_RANK (array); dim++) |
{ |
if (dim == which) |
{ |
roffset = GFC_DESCRIPTOR_STRIDE_BYTES(ret,dim); |
if (roffset == 0) |
roffset = size; |
soffset = GFC_DESCRIPTOR_STRIDE_BYTES(array,dim); |
if (soffset == 0) |
soffset = size; |
len = GFC_DESCRIPTOR_EXTENT(array,dim); |
} |
else |
{ |
count[n] = 0; |
extent[n] = GFC_DESCRIPTOR_EXTENT(array,dim); |
rstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(ret,dim); |
sstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(array,dim); |
n++; |
} |
} |
if (sstride[0] == 0) |
sstride[0] = size; |
if (rstride[0] == 0) |
rstride[0] = size; |
|
dim = GFC_DESCRIPTOR_RANK (array); |
rstride0 = rstride[0]; |
sstride0 = sstride[0]; |
rptr = ret->data; |
sptr = array->data; |
|
shift = len == 0 ? 0 : shift % (ptrdiff_t)len; |
if (shift < 0) |
shift += len; |
|
while (rptr) |
{ |
/* Do the shift for this dimension. */ |
|
/* If elements are contiguous, perform the operation |
in two block moves. */ |
if (soffset == size && roffset == size) |
{ |
size_t len1 = shift * size; |
size_t len2 = (len - shift) * size; |
memcpy (rptr, sptr + len1, len2); |
memcpy (rptr + len2, sptr, len1); |
} |
else |
{ |
/* Otherwise, we'll have to perform the copy one element at |
a time. */ |
char *dest = rptr; |
const char *src = &sptr[shift * soffset]; |
|
for (n = 0; n < len - shift; n++) |
{ |
memcpy (dest, src, size); |
dest += roffset; |
src += soffset; |
} |
for (src = sptr, n = 0; n < shift; n++) |
{ |
memcpy (dest, src, size); |
dest += roffset; |
src += soffset; |
} |
} |
|
/* Advance to the next section. */ |
rptr += rstride0; |
sptr += sstride0; |
count[0]++; |
n = 0; |
while (count[n] == extent[n]) |
{ |
/* When we get to the end of a dimension, reset it and increment |
the next dimension. */ |
count[n] = 0; |
/* We could precalculate these products, but this is a less |
frequently used path so probably not worth it. */ |
rptr -= rstride[n] * extent[n]; |
sptr -= sstride[n] * extent[n]; |
n++; |
if (n >= dim - 1) |
{ |
/* Break out of the loop. */ |
rptr = NULL; |
break; |
} |
else |
{ |
count[n]++; |
rptr += rstride[n]; |
sptr += sstride[n]; |
} |
} |
} |
} |
|
#define DEFINE_CSHIFT(N) \ |
extern void cshift0_##N (gfc_array_char *, const gfc_array_char *, \ |
const GFC_INTEGER_##N *, const GFC_INTEGER_##N *); \ |
export_proto(cshift0_##N); \ |
\ |
void \ |
cshift0_##N (gfc_array_char *ret, const gfc_array_char *array, \ |
const GFC_INTEGER_##N *pshift, const GFC_INTEGER_##N *pdim) \ |
{ \ |
cshift0 (ret, array, *pshift, pdim ? *pdim : 1, \ |
GFC_DESCRIPTOR_SIZE (array)); \ |
} \ |
\ |
extern void cshift0_##N##_char (gfc_array_char *, GFC_INTEGER_4, \ |
const gfc_array_char *, \ |
const GFC_INTEGER_##N *, \ |
const GFC_INTEGER_##N *, GFC_INTEGER_4); \ |
export_proto(cshift0_##N##_char); \ |
\ |
void \ |
cshift0_##N##_char (gfc_array_char *ret, \ |
GFC_INTEGER_4 ret_length __attribute__((unused)), \ |
const gfc_array_char *array, \ |
const GFC_INTEGER_##N *pshift, \ |
const GFC_INTEGER_##N *pdim, \ |
GFC_INTEGER_4 array_length) \ |
{ \ |
cshift0 (ret, array, *pshift, pdim ? *pdim : 1, array_length); \ |
} \ |
\ |
extern void cshift0_##N##_char4 (gfc_array_char *, GFC_INTEGER_4, \ |
const gfc_array_char *, \ |
const GFC_INTEGER_##N *, \ |
const GFC_INTEGER_##N *, GFC_INTEGER_4); \ |
export_proto(cshift0_##N##_char4); \ |
\ |
void \ |
cshift0_##N##_char4 (gfc_array_char *ret, \ |
GFC_INTEGER_4 ret_length __attribute__((unused)), \ |
const gfc_array_char *array, \ |
const GFC_INTEGER_##N *pshift, \ |
const GFC_INTEGER_##N *pdim, \ |
GFC_INTEGER_4 array_length) \ |
{ \ |
cshift0 (ret, array, *pshift, pdim ? *pdim : 1, \ |
array_length * sizeof (gfc_char4_t)); \ |
} |
|
DEFINE_CSHIFT (1); |
DEFINE_CSHIFT (2); |
DEFINE_CSHIFT (4); |
DEFINE_CSHIFT (8); |
#ifdef HAVE_GFC_INTEGER_16 |
DEFINE_CSHIFT (16); |
#endif |
/ctime.c
0,0 → 1,110
/* Implementation of the CTIME and FDATE g77 intrinsics. |
Copyright (C) 2005, 2007, 2009, 2011 Free Software Foundation, Inc. |
Contributed by François-Xavier Coudert <coudert@clipper.ens.fr> |
|
This file is part of the GNU Fortran runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
|
#include "time_1.h" |
|
#include <stdlib.h> |
#include <string.h> |
|
|
/* strftime-like function that fills a C string with %c format which |
is identical to ctime in the default locale. As ctime and ctime_r |
are poorly specified and their usage not recommended, the |
implementation instead uses strftime. */ |
|
static size_t |
strctime (char *s, size_t max, const time_t *timep) |
{ |
struct tm ltm; |
int failed; |
/* Some targets provide a localtime_r based on a draft of the POSIX |
standard where the return type is int rather than the |
standardized struct tm*. */ |
__builtin_choose_expr (__builtin_classify_type (localtime_r (timep, <m)) |
== 5, |
failed = localtime_r (timep, <m) == NULL, |
failed = localtime_r (timep, <m) != 0); |
if (failed) |
return 0; |
return strftime (s, max, "%c", <m); |
} |
|
/* In the default locale, the date and time representation fits in 26 |
bytes. However, other locales might need more space. */ |
#define CSZ 100 |
|
extern void fdate (char **, gfc_charlen_type *); |
export_proto(fdate); |
|
void |
fdate (char ** date, gfc_charlen_type * date_len) |
{ |
time_t now = time(NULL); |
*date = get_mem (CSZ); |
*date_len = strctime (*date, CSZ, &now); |
} |
|
|
extern void fdate_sub (char *, gfc_charlen_type); |
export_proto(fdate_sub); |
|
void |
fdate_sub (char * date, gfc_charlen_type date_len) |
{ |
time_t now = time(NULL); |
char *s = get_mem (date_len + 1); |
size_t n = strctime (s, date_len + 1, &now); |
fstrcpy (date, date_len, s, n); |
free (s); |
} |
|
|
|
extern void PREFIX(ctime) (char **, gfc_charlen_type *, GFC_INTEGER_8); |
export_proto_np(PREFIX(ctime)); |
|
void |
PREFIX(ctime) (char ** date, gfc_charlen_type * date_len, GFC_INTEGER_8 t) |
{ |
time_t now = t; |
*date = get_mem (CSZ); |
*date_len = strctime (*date, CSZ, &now); |
} |
|
|
extern void ctime_sub (GFC_INTEGER_8 *, char *, gfc_charlen_type); |
export_proto(ctime_sub); |
|
void |
ctime_sub (GFC_INTEGER_8 * t, char * date, gfc_charlen_type date_len) |
{ |
time_t now = *t; |
char *s = get_mem (date_len + 1); |
size_t n = strctime (s, date_len + 1, &now); |
fstrcpy (date, date_len, s, n); |
free (s); |
} |
/etime.c
0,0 → 1,73
/* Implementation of the ETIME intrinsic. |
Copyright (C) 2004, 2005, 2006, 2007, 2009, 2011 Free Software |
Foundation, Inc. |
Contributed by Steven G. Kargl <kargls@comcast.net>. |
|
This file is part of the GNU Fortran runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
#include "time_1.h" |
|
extern void etime_sub (gfc_array_r4 *t, GFC_REAL_4 *result); |
iexport_proto(etime_sub); |
|
void |
etime_sub (gfc_array_r4 *t, GFC_REAL_4 *result) |
{ |
GFC_REAL_4 tu, ts, tt, *tp; |
long user_sec, user_usec, system_sec, system_usec; |
|
if (((GFC_DESCRIPTOR_EXTENT(t,0))) < 2) |
runtime_error ("Insufficient number of elements in TARRAY."); |
|
if (gf_cputime (&user_sec, &user_usec, &system_sec, &system_usec) == 0) |
{ |
tu = (GFC_REAL_4)(user_sec + 1.e-6 * user_usec); |
ts = (GFC_REAL_4)(system_sec + 1.e-6 * system_usec); |
tt = tu + ts; |
} |
else |
{ |
tu = (GFC_REAL_4)-1.0; |
ts = (GFC_REAL_4)-1.0; |
tt = (GFC_REAL_4)-1.0; |
} |
|
tp = t->data; |
|
*tp = tu; |
tp += GFC_DESCRIPTOR_STRIDE(t,0); |
*tp = ts; |
*result = tt; |
} |
iexport(etime_sub); |
|
extern GFC_REAL_4 etime (gfc_array_r4 *t); |
export_proto(etime); |
|
GFC_REAL_4 |
etime (gfc_array_r4 *t) |
{ |
GFC_REAL_4 val; |
etime_sub (t, &val); |
return val; |
} |
/mvbits.c
0,0 → 1,86
/* Implementation of the MVBITS intrinsic |
Copyright (C) 2004, 2006, 2009 Free Software Foundation, Inc. |
Contributed by Tobias Schlüter |
|
This file is part of the GNU Fortran 95 runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
/* TODO: This should be replaced by a compiler builtin. */ |
|
#ifndef SUB_NAME |
#include <libgfortran.h> |
#endif |
|
#ifdef SUB_NAME |
/* MVBITS copies LEN bits starting at bit position FROMPOS from FROM |
into TO, starting at bit position TOPOS. */ |
|
extern void SUB_NAME (const TYPE *, const int *, const int *, TYPE *, |
const int *); |
export_proto(SUB_NAME); |
|
void |
SUB_NAME (const TYPE *from, const int *frompos, const int *len, TYPE *to, |
const int *topos) |
{ |
TYPE oldbits, newbits, lenmask; |
|
lenmask = (*len == sizeof (TYPE)*8) ? ~(TYPE)0 : ((TYPE)1 << *len) - 1; |
newbits = (((UTYPE)(*from) >> *frompos) & lenmask) << *topos; |
oldbits = *to & (~(lenmask << *topos)); |
|
*to = newbits | oldbits; |
} |
#endif |
|
#ifndef SUB_NAME |
# define TYPE GFC_INTEGER_1 |
# define UTYPE GFC_UINTEGER_1 |
# define SUB_NAME mvbits_i1 |
# include "mvbits.c" |
# undef SUB_NAME |
# undef TYPE |
# undef UTYPE |
|
# define TYPE GFC_INTEGER_2 |
# define UTYPE GFC_UINTEGER_2 |
# define SUB_NAME mvbits_i2 |
# include "mvbits.c" |
# undef SUB_NAME |
# undef TYPE |
# undef UTYPE |
|
# define TYPE GFC_INTEGER_4 |
# define UTYPE GFC_UINTEGER_4 |
# define SUB_NAME mvbits_i4 |
# include "mvbits.c" |
# undef SUB_NAME |
# undef TYPE |
# undef UTYPE |
|
# define TYPE GFC_INTEGER_8 |
# define UTYPE GFC_UINTEGER_8 |
# define SUB_NAME mvbits_i8 |
# include "mvbits.c" |
# undef SUB_NAME |
# undef TYPE |
# undef UTYPE |
#endif |
/cpu_time.c
0,0 → 1,109
/* Implementation of the CPU_TIME intrinsic. |
Copyright (C) 2003, 2007, 2009, 2010, 2011 Free Software Foundation, Inc. |
|
This file is part of the GNU Fortran runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
#include "time_1.h" |
|
|
static void |
__cpu_time_1 (long *sec, long *usec) |
{ |
long user_sec, user_usec, system_sec, system_usec; |
if (gf_cputime (&user_sec, &user_usec, &system_sec, &system_usec) == 0) |
{ |
*sec = user_sec + system_sec; |
*usec = user_usec + system_usec; |
} |
else |
{ |
*sec = -1; |
*usec = 0; |
} |
} |
|
|
extern void cpu_time_4 (GFC_REAL_4 *); |
iexport_proto(cpu_time_4); |
|
void cpu_time_4 (GFC_REAL_4 *time) |
{ |
long sec, usec; |
__cpu_time_1 (&sec, &usec); |
*time = sec + usec * GFC_REAL_4_LITERAL(1.e-6); |
} |
iexport(cpu_time_4); |
|
extern void cpu_time_8 (GFC_REAL_8 *); |
export_proto(cpu_time_8); |
|
void cpu_time_8 (GFC_REAL_8 *time) |
{ |
long sec, usec; |
__cpu_time_1 (&sec, &usec); |
*time = sec + usec * GFC_REAL_8_LITERAL(1.e-6); |
} |
|
#ifdef HAVE_GFC_REAL_10 |
extern void cpu_time_10 (GFC_REAL_10 *); |
export_proto(cpu_time_10); |
|
void cpu_time_10 (GFC_REAL_10 *time) |
{ |
long sec, usec; |
__cpu_time_1 (&sec, &usec); |
*time = sec + usec * GFC_REAL_10_LITERAL(1.e-6); |
} |
#endif |
|
#ifdef HAVE_GFC_REAL_16 |
extern void cpu_time_16 (GFC_REAL_16 *); |
export_proto(cpu_time_16); |
|
void cpu_time_16 (GFC_REAL_16 *time) |
{ |
long sec, usec; |
__cpu_time_1 (&sec, &usec); |
*time = sec + usec * GFC_REAL_16_LITERAL(1.e-6); |
} |
#endif |
|
extern void second_sub (GFC_REAL_4 *); |
export_proto(second_sub); |
|
void |
second_sub (GFC_REAL_4 *s) |
{ |
cpu_time_4 (s); |
} |
|
extern GFC_REAL_4 second (void); |
export_proto(second); |
|
GFC_REAL_4 |
second (void) |
{ |
GFC_REAL_4 s; |
cpu_time_4 (&s); |
return s; |
} |
/malloc.c
0,0 → 1,47
/* Implementation of the MALLOC and FREE intrinsics |
Copyright (C) 2005, 2007, 2009, 2011 Free Software Foundation, Inc. |
Contributed by François-Xavier Coudert <coudert@clipper.ens.fr> |
|
This file is part of the GNU Fortran runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
#include <stdlib.h> |
|
|
extern void PREFIX(free) (void **); |
export_proto_np(PREFIX(free)); |
|
void |
PREFIX(free) (void ** ptr) |
{ |
free (*ptr); |
} |
|
|
extern void * PREFIX(malloc) (size_t *); |
export_proto_np(PREFIX(malloc)); |
|
void * |
PREFIX(malloc) (size_t * size) |
{ |
return malloc (*size); |
} |
/spread_generic.c
0,0 → 1,652
/* Generic implementation of the SPREAD intrinsic |
Copyright 2002, 2005, 2006, 2007, 2009, 2010 Free Software Foundation, Inc. |
Contributed by Paul Brook <paul@nowt.org> |
|
This file is part of the GNU Fortran 95 runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Ligbfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
#include <stdlib.h> |
#include <assert.h> |
#include <string.h> |
|
static void |
spread_internal (gfc_array_char *ret, const gfc_array_char *source, |
const index_type *along, const index_type *pncopies) |
{ |
/* r.* indicates the return array. */ |
index_type rstride[GFC_MAX_DIMENSIONS]; |
index_type rstride0; |
index_type rdelta = 0; |
index_type rrank; |
index_type rs; |
char *rptr; |
char *dest; |
/* s.* indicates the source array. */ |
index_type sstride[GFC_MAX_DIMENSIONS]; |
index_type sstride0; |
index_type srank; |
const char *sptr; |
|
index_type count[GFC_MAX_DIMENSIONS]; |
index_type extent[GFC_MAX_DIMENSIONS]; |
index_type n; |
index_type dim; |
index_type ncopies; |
index_type size; |
|
size = GFC_DESCRIPTOR_SIZE(source); |
|
srank = GFC_DESCRIPTOR_RANK(source); |
|
rrank = srank + 1; |
if (rrank > GFC_MAX_DIMENSIONS) |
runtime_error ("return rank too large in spread()"); |
|
if (*along > rrank) |
runtime_error ("dim outside of rank in spread()"); |
|
ncopies = *pncopies; |
|
if (ret->data == NULL) |
{ |
/* The front end has signalled that we need to populate the |
return array descriptor. */ |
|
size_t ub, stride; |
|
ret->dtype = (source->dtype & ~GFC_DTYPE_RANK_MASK) | rrank; |
dim = 0; |
rs = 1; |
for (n = 0; n < rrank; n++) |
{ |
stride = rs; |
if (n == *along - 1) |
{ |
ub = ncopies - 1; |
rdelta = rs * size; |
rs *= ncopies; |
} |
else |
{ |
count[dim] = 0; |
extent[dim] = GFC_DESCRIPTOR_EXTENT(source,dim); |
sstride[dim] = GFC_DESCRIPTOR_STRIDE_BYTES(source,dim); |
rstride[dim] = rs * size; |
|
ub = extent[dim]-1; |
rs *= extent[dim]; |
dim++; |
} |
|
GFC_DIMENSION_SET(ret->dim[n], 0, ub, stride); |
} |
ret->offset = 0; |
ret->data = internal_malloc_size (rs * size); |
|
if (rs <= 0) |
return; |
} |
else |
{ |
int zero_sized; |
|
zero_sized = 0; |
|
dim = 0; |
if (GFC_DESCRIPTOR_RANK(ret) != rrank) |
runtime_error ("rank mismatch in spread()"); |
|
if (compile_options.bounds_check) |
{ |
for (n = 0; n < rrank; n++) |
{ |
index_type ret_extent; |
|
ret_extent = GFC_DESCRIPTOR_EXTENT(ret,n); |
if (n == *along - 1) |
{ |
rdelta = GFC_DESCRIPTOR_STRIDE_BYTES(ret,n); |
|
if (ret_extent != ncopies) |
runtime_error("Incorrect extent in return value of SPREAD" |
" intrinsic in dimension %ld: is %ld," |
" should be %ld", (long int) n+1, |
(long int) ret_extent, (long int) ncopies); |
} |
else |
{ |
count[dim] = 0; |
extent[dim] = GFC_DESCRIPTOR_EXTENT(source,dim); |
if (ret_extent != extent[dim]) |
runtime_error("Incorrect extent in return value of SPREAD" |
" intrinsic in dimension %ld: is %ld," |
" should be %ld", (long int) n+1, |
(long int) ret_extent, |
(long int) extent[dim]); |
|
if (extent[dim] <= 0) |
zero_sized = 1; |
sstride[dim] = GFC_DESCRIPTOR_STRIDE_BYTES(source,dim); |
rstride[dim] = GFC_DESCRIPTOR_STRIDE_BYTES(ret,n); |
dim++; |
} |
} |
} |
else |
{ |
for (n = 0; n < rrank; n++) |
{ |
if (n == *along - 1) |
{ |
rdelta = GFC_DESCRIPTOR_STRIDE_BYTES(ret,n); |
} |
else |
{ |
count[dim] = 0; |
extent[dim] = GFC_DESCRIPTOR_EXTENT(source,dim); |
if (extent[dim] <= 0) |
zero_sized = 1; |
sstride[dim] = GFC_DESCRIPTOR_STRIDE_BYTES(source,dim); |
rstride[dim] = GFC_DESCRIPTOR_STRIDE_BYTES(ret,n); |
dim++; |
} |
} |
} |
|
if (zero_sized) |
return; |
|
if (sstride[0] == 0) |
sstride[0] = size; |
} |
sstride0 = sstride[0]; |
rstride0 = rstride[0]; |
rptr = ret->data; |
sptr = source->data; |
|
while (sptr) |
{ |
/* Spread this element. */ |
dest = rptr; |
for (n = 0; n < ncopies; n++) |
{ |
memcpy (dest, sptr, size); |
dest += rdelta; |
} |
/* Advance to the next element. */ |
sptr += sstride0; |
rptr += rstride0; |
count[0]++; |
n = 0; |
while (count[n] == extent[n]) |
{ |
/* When we get to the end of a dimension, reset it and increment |
the next dimension. */ |
count[n] = 0; |
/* We could precalculate these products, but this is a less |
frequently used path so probably not worth it. */ |
sptr -= sstride[n] * extent[n]; |
rptr -= rstride[n] * extent[n]; |
n++; |
if (n >= srank) |
{ |
/* Break out of the loop. */ |
sptr = NULL; |
break; |
} |
else |
{ |
count[n]++; |
sptr += sstride[n]; |
rptr += rstride[n]; |
} |
} |
} |
} |
|
/* This version of spread_internal treats the special case of a scalar |
source. This is much simpler than the more general case above. */ |
|
static void |
spread_internal_scalar (gfc_array_char *ret, const char *source, |
const index_type *along, const index_type *pncopies) |
{ |
int n; |
int ncopies = *pncopies; |
char * dest; |
size_t size; |
|
size = GFC_DESCRIPTOR_SIZE(ret); |
|
if (GFC_DESCRIPTOR_RANK (ret) != 1) |
runtime_error ("incorrect destination rank in spread()"); |
|
if (*along > 1) |
runtime_error ("dim outside of rank in spread()"); |
|
if (ret->data == NULL) |
{ |
ret->data = internal_malloc_size (ncopies * size); |
ret->offset = 0; |
GFC_DIMENSION_SET(ret->dim[0], 0, ncopies - 1, 1); |
} |
else |
{ |
if (ncopies - 1 > (GFC_DESCRIPTOR_EXTENT(ret,0) - 1) |
/ GFC_DESCRIPTOR_STRIDE(ret,0)) |
runtime_error ("dim too large in spread()"); |
} |
|
for (n = 0; n < ncopies; n++) |
{ |
dest = (char*)(ret->data + n * GFC_DESCRIPTOR_STRIDE_BYTES(ret,0)); |
memcpy (dest , source, size); |
} |
} |
|
extern void spread (gfc_array_char *, const gfc_array_char *, |
const index_type *, const index_type *); |
export_proto(spread); |
|
void |
spread (gfc_array_char *ret, const gfc_array_char *source, |
const index_type *along, const index_type *pncopies) |
{ |
index_type type_size; |
|
type_size = GFC_DTYPE_TYPE_SIZE(ret); |
switch(type_size) |
{ |
case GFC_DTYPE_DERIVED_1: |
case GFC_DTYPE_LOGICAL_1: |
case GFC_DTYPE_INTEGER_1: |
spread_i1 ((gfc_array_i1 *) ret, (gfc_array_i1 *) source, |
*along, *pncopies); |
return; |
|
case GFC_DTYPE_LOGICAL_2: |
case GFC_DTYPE_INTEGER_2: |
spread_i2 ((gfc_array_i2 *) ret, (gfc_array_i2 *) source, |
*along, *pncopies); |
return; |
|
case GFC_DTYPE_LOGICAL_4: |
case GFC_DTYPE_INTEGER_4: |
spread_i4 ((gfc_array_i4 *) ret, (gfc_array_i4 *) source, |
*along, *pncopies); |
return; |
|
case GFC_DTYPE_LOGICAL_8: |
case GFC_DTYPE_INTEGER_8: |
spread_i8 ((gfc_array_i8 *) ret, (gfc_array_i8 *) source, |
*along, *pncopies); |
return; |
|
#ifdef HAVE_GFC_INTEGER_16 |
case GFC_DTYPE_LOGICAL_16: |
case GFC_DTYPE_INTEGER_16: |
spread_i16 ((gfc_array_i16 *) ret, (gfc_array_i16 *) source, |
*along, *pncopies); |
return; |
#endif |
|
case GFC_DTYPE_REAL_4: |
spread_r4 ((gfc_array_r4 *) ret, (gfc_array_r4 *) source, |
*along, *pncopies); |
return; |
|
case GFC_DTYPE_REAL_8: |
spread_r8 ((gfc_array_r8 *) ret, (gfc_array_r8 *) source, |
*along, *pncopies); |
return; |
|
/* FIXME: This here is a hack, which will have to be removed when |
the array descriptor is reworked. Currently, we don't store the |
kind value for the type, but only the size. Because on targets with |
__float128, we have sizeof(logn double) == sizeof(__float128), |
we cannot discriminate here and have to fall back to the generic |
handling (which is suboptimal). */ |
#if !defined(GFC_REAL_16_IS_FLOAT128) |
# ifdef GFC_HAVE_REAL_10 |
case GFC_DTYPE_REAL_10: |
spread_r10 ((gfc_array_r10 *) ret, (gfc_array_r10 *) source, |
*along, *pncopies); |
return; |
# endif |
|
# ifdef GFC_HAVE_REAL_16 |
case GFC_DTYPE_REAL_16: |
spread_r16 ((gfc_array_r16 *) ret, (gfc_array_r16 *) source, |
*along, *pncopies); |
return; |
# endif |
#endif |
|
case GFC_DTYPE_COMPLEX_4: |
spread_c4 ((gfc_array_c4 *) ret, (gfc_array_c4 *) source, |
*along, *pncopies); |
return; |
|
case GFC_DTYPE_COMPLEX_8: |
spread_c8 ((gfc_array_c8 *) ret, (gfc_array_c8 *) source, |
*along, *pncopies); |
return; |
|
/* FIXME: This here is a hack, which will have to be removed when |
the array descriptor is reworked. Currently, we don't store the |
kind value for the type, but only the size. Because on targets with |
__float128, we have sizeof(logn double) == sizeof(__float128), |
we cannot discriminate here and have to fall back to the generic |
handling (which is suboptimal). */ |
#if !defined(GFC_REAL_16_IS_FLOAT128) |
# ifdef GFC_HAVE_COMPLEX_10 |
case GFC_DTYPE_COMPLEX_10: |
spread_c10 ((gfc_array_c10 *) ret, (gfc_array_c10 *) source, |
*along, *pncopies); |
return; |
# endif |
|
# ifdef GFC_HAVE_COMPLEX_16 |
case GFC_DTYPE_COMPLEX_16: |
spread_c16 ((gfc_array_c16 *) ret, (gfc_array_c16 *) source, |
*along, *pncopies); |
return; |
# endif |
#endif |
|
case GFC_DTYPE_DERIVED_2: |
if (GFC_UNALIGNED_2(ret->data) || GFC_UNALIGNED_2(source->data)) |
break; |
else |
{ |
spread_i2 ((gfc_array_i2 *) ret, (gfc_array_i2 *) source, |
*along, *pncopies); |
return; |
} |
|
case GFC_DTYPE_DERIVED_4: |
if (GFC_UNALIGNED_4(ret->data) || GFC_UNALIGNED_4(source->data)) |
break; |
else |
{ |
spread_i4 ((gfc_array_i4 *) ret, (gfc_array_i4 *) source, |
*along, *pncopies); |
return; |
} |
|
case GFC_DTYPE_DERIVED_8: |
if (GFC_UNALIGNED_8(ret->data) || GFC_UNALIGNED_8(source->data)) |
break; |
else |
{ |
spread_i8 ((gfc_array_i8 *) ret, (gfc_array_i8 *) source, |
*along, *pncopies); |
return; |
} |
|
#ifdef HAVE_GFC_INTEGER_16 |
case GFC_DTYPE_DERIVED_16: |
if (GFC_UNALIGNED_16(ret->data) || GFC_UNALIGNED_16(source->data)) |
break; |
else |
{ |
spread_i16 ((gfc_array_i16 *) ret, (gfc_array_i16 *) source, |
*along, *pncopies); |
return; |
} |
#endif |
} |
|
spread_internal (ret, source, along, pncopies); |
} |
|
|
extern void spread_char (gfc_array_char *, GFC_INTEGER_4, |
const gfc_array_char *, const index_type *, |
const index_type *, GFC_INTEGER_4); |
export_proto(spread_char); |
|
void |
spread_char (gfc_array_char *ret, |
GFC_INTEGER_4 ret_length __attribute__((unused)), |
const gfc_array_char *source, const index_type *along, |
const index_type *pncopies, |
GFC_INTEGER_4 source_length __attribute__((unused))) |
{ |
spread_internal (ret, source, along, pncopies); |
} |
|
|
extern void spread_char4 (gfc_array_char *, GFC_INTEGER_4, |
const gfc_array_char *, const index_type *, |
const index_type *, GFC_INTEGER_4); |
export_proto(spread_char4); |
|
void |
spread_char4 (gfc_array_char *ret, |
GFC_INTEGER_4 ret_length __attribute__((unused)), |
const gfc_array_char *source, const index_type *along, |
const index_type *pncopies, |
GFC_INTEGER_4 source_length __attribute__((unused))) |
{ |
spread_internal (ret, source, along, pncopies); |
} |
|
|
/* The following are the prototypes for the versions of spread with a |
scalar source. */ |
|
extern void spread_scalar (gfc_array_char *, const char *, |
const index_type *, const index_type *); |
export_proto(spread_scalar); |
|
void |
spread_scalar (gfc_array_char *ret, const char *source, |
const index_type *along, const index_type *pncopies) |
{ |
index_type type_size; |
|
if (!ret->dtype) |
runtime_error ("return array missing descriptor in spread()"); |
|
type_size = GFC_DTYPE_TYPE_SIZE(ret); |
switch(type_size) |
{ |
case GFC_DTYPE_DERIVED_1: |
case GFC_DTYPE_LOGICAL_1: |
case GFC_DTYPE_INTEGER_1: |
spread_scalar_i1 ((gfc_array_i1 *) ret, (GFC_INTEGER_1 *) source, |
*along, *pncopies); |
return; |
|
case GFC_DTYPE_LOGICAL_2: |
case GFC_DTYPE_INTEGER_2: |
spread_scalar_i2 ((gfc_array_i2 *) ret, (GFC_INTEGER_2 *) source, |
*along, *pncopies); |
return; |
|
case GFC_DTYPE_LOGICAL_4: |
case GFC_DTYPE_INTEGER_4: |
spread_scalar_i4 ((gfc_array_i4 *) ret, (GFC_INTEGER_4 *) source, |
*along, *pncopies); |
return; |
|
case GFC_DTYPE_LOGICAL_8: |
case GFC_DTYPE_INTEGER_8: |
spread_scalar_i8 ((gfc_array_i8 *) ret, (GFC_INTEGER_8 *) source, |
*along, *pncopies); |
return; |
|
#ifdef HAVE_GFC_INTEGER_16 |
case GFC_DTYPE_LOGICAL_16: |
case GFC_DTYPE_INTEGER_16: |
spread_scalar_i16 ((gfc_array_i16 *) ret, (GFC_INTEGER_16 *) source, |
*along, *pncopies); |
return; |
#endif |
|
case GFC_DTYPE_REAL_4: |
spread_scalar_r4 ((gfc_array_r4 *) ret, (GFC_REAL_4 *) source, |
*along, *pncopies); |
return; |
|
case GFC_DTYPE_REAL_8: |
spread_scalar_r8 ((gfc_array_r8 *) ret, (GFC_REAL_8 *) source, |
*along, *pncopies); |
return; |
|
/* FIXME: This here is a hack, which will have to be removed when |
the array descriptor is reworked. Currently, we don't store the |
kind value for the type, but only the size. Because on targets with |
__float128, we have sizeof(logn double) == sizeof(__float128), |
we cannot discriminate here and have to fall back to the generic |
handling (which is suboptimal). */ |
#if !defined(GFC_REAL_16_IS_FLOAT128) |
# ifdef HAVE_GFC_REAL_10 |
case GFC_DTYPE_REAL_10: |
spread_scalar_r10 ((gfc_array_r10 *) ret, (GFC_REAL_10 *) source, |
*along, *pncopies); |
return; |
# endif |
|
# ifdef HAVE_GFC_REAL_16 |
case GFC_DTYPE_REAL_16: |
spread_scalar_r16 ((gfc_array_r16 *) ret, (GFC_REAL_16 *) source, |
*along, *pncopies); |
return; |
# endif |
#endif |
|
case GFC_DTYPE_COMPLEX_4: |
spread_scalar_c4 ((gfc_array_c4 *) ret, (GFC_COMPLEX_4 *) source, |
*along, *pncopies); |
return; |
|
case GFC_DTYPE_COMPLEX_8: |
spread_scalar_c8 ((gfc_array_c8 *) ret, (GFC_COMPLEX_8 *) source, |
*along, *pncopies); |
return; |
|
/* FIXME: This here is a hack, which will have to be removed when |
the array descriptor is reworked. Currently, we don't store the |
kind value for the type, but only the size. Because on targets with |
__float128, we have sizeof(logn double) == sizeof(__float128), |
we cannot discriminate here and have to fall back to the generic |
handling (which is suboptimal). */ |
#if !defined(GFC_REAL_16_IS_FLOAT128) |
# ifdef HAVE_GFC_COMPLEX_10 |
case GFC_DTYPE_COMPLEX_10: |
spread_scalar_c10 ((gfc_array_c10 *) ret, (GFC_COMPLEX_10 *) source, |
*along, *pncopies); |
return; |
# endif |
|
# ifdef HAVE_GFC_COMPLEX_16 |
case GFC_DTYPE_COMPLEX_16: |
spread_scalar_c16 ((gfc_array_c16 *) ret, (GFC_COMPLEX_16 *) source, |
*along, *pncopies); |
return; |
# endif |
#endif |
|
case GFC_DTYPE_DERIVED_2: |
if (GFC_UNALIGNED_2(ret->data) || GFC_UNALIGNED_2(source)) |
break; |
else |
{ |
spread_scalar_i2 ((gfc_array_i2 *) ret, (GFC_INTEGER_2 *) source, |
*along, *pncopies); |
return; |
} |
|
case GFC_DTYPE_DERIVED_4: |
if (GFC_UNALIGNED_4(ret->data) || GFC_UNALIGNED_4(source)) |
break; |
else |
{ |
spread_scalar_i4 ((gfc_array_i4 *) ret, (GFC_INTEGER_4 *) source, |
*along, *pncopies); |
return; |
} |
|
case GFC_DTYPE_DERIVED_8: |
if (GFC_UNALIGNED_8(ret->data) || GFC_UNALIGNED_8(source)) |
break; |
else |
{ |
spread_scalar_i8 ((gfc_array_i8 *) ret, (GFC_INTEGER_8 *) source, |
*along, *pncopies); |
return; |
} |
#ifdef HAVE_GFC_INTEGER_16 |
case GFC_DTYPE_DERIVED_16: |
if (GFC_UNALIGNED_16(ret->data) || GFC_UNALIGNED_16(source)) |
break; |
else |
{ |
spread_scalar_i16 ((gfc_array_i16 *) ret, (GFC_INTEGER_16 *) source, |
*along, *pncopies); |
return; |
} |
#endif |
} |
|
spread_internal_scalar (ret, source, along, pncopies); |
} |
|
|
extern void spread_char_scalar (gfc_array_char *, GFC_INTEGER_4, |
const char *, const index_type *, |
const index_type *, GFC_INTEGER_4); |
export_proto(spread_char_scalar); |
|
void |
spread_char_scalar (gfc_array_char *ret, |
GFC_INTEGER_4 ret_length __attribute__((unused)), |
const char *source, const index_type *along, |
const index_type *pncopies, |
GFC_INTEGER_4 source_length __attribute__((unused))) |
{ |
if (!ret->dtype) |
runtime_error ("return array missing descriptor in spread()"); |
spread_internal_scalar (ret, source, along, pncopies); |
} |
|
|
extern void spread_char4_scalar (gfc_array_char *, GFC_INTEGER_4, |
const char *, const index_type *, |
const index_type *, GFC_INTEGER_4); |
export_proto(spread_char4_scalar); |
|
void |
spread_char4_scalar (gfc_array_char *ret, |
GFC_INTEGER_4 ret_length __attribute__((unused)), |
const char *source, const index_type *along, |
const index_type *pncopies, |
GFC_INTEGER_4 source_length __attribute__((unused))) |
{ |
if (!ret->dtype) |
runtime_error ("return array missing descriptor in spread()"); |
spread_internal_scalar (ret, source, along, pncopies); |
|
} |
|
/stat.c
0,0 → 1,556
/* Implementation of the STAT and FSTAT intrinsics. |
Copyright (C) 2004, 2005, 2006, 2007, 2009, 2011 |
Free Software Foundation, Inc. |
Contributed by Steven G. Kargl <kargls@comcast.net>. |
|
This file is part of the GNU Fortran runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
|
#include <string.h> |
#include <errno.h> |
|
#ifdef HAVE_SYS_STAT_H |
#include <sys/stat.h> |
#endif |
|
#include <stdlib.h> |
|
|
#ifdef HAVE_STAT |
|
/* SUBROUTINE STAT(FILE, SARRAY, STATUS) |
CHARACTER(len=*), INTENT(IN) :: FILE |
INTEGER, INTENT(OUT), :: SARRAY(13) |
INTEGER, INTENT(OUT), OPTIONAL :: STATUS |
|
FUNCTION STAT(FILE, SARRAY) |
INTEGER STAT |
CHARACTER(len=*), INTENT(IN) :: FILE |
INTEGER, INTENT(OUT), :: SARRAY(13) */ |
|
/*extern void stat_i4_sub_0 (char *, gfc_array_i4 *, GFC_INTEGER_4 *, |
gfc_charlen_type, int); |
internal_proto(stat_i4_sub_0);*/ |
|
static void |
stat_i4_sub_0 (char *name, gfc_array_i4 *sarray, GFC_INTEGER_4 *status, |
gfc_charlen_type name_len, int is_lstat __attribute__ ((unused))) |
{ |
int val; |
char *str; |
struct stat sb; |
|
/* If the rank of the array is not 1, abort. */ |
if (GFC_DESCRIPTOR_RANK (sarray) != 1) |
runtime_error ("Array rank of SARRAY is not 1."); |
|
/* If the array is too small, abort. */ |
if (GFC_DESCRIPTOR_EXTENT(sarray,0) < 13) |
runtime_error ("Array size of SARRAY is too small."); |
|
/* Trim trailing spaces from name. */ |
while (name_len > 0 && name[name_len - 1] == ' ') |
name_len--; |
|
/* Make a null terminated copy of the string. */ |
str = gfc_alloca (name_len + 1); |
memcpy (str, name, name_len); |
str[name_len] = '\0'; |
|
/* On platforms that don't provide lstat(), we use stat() instead. */ |
#ifdef HAVE_LSTAT |
if (is_lstat) |
val = lstat(str, &sb); |
else |
#endif |
val = stat(str, &sb); |
|
if (val == 0) |
{ |
index_type stride = GFC_DESCRIPTOR_STRIDE(sarray,0); |
|
/* Device ID */ |
sarray->data[0 * stride] = sb.st_dev; |
|
/* Inode number */ |
sarray->data[1 * stride] = sb.st_ino; |
|
/* File mode */ |
sarray->data[2 * stride] = sb.st_mode; |
|
/* Number of (hard) links */ |
sarray->data[3 * stride] = sb.st_nlink; |
|
/* Owner's uid */ |
sarray->data[4 * stride] = sb.st_uid; |
|
/* Owner's gid */ |
sarray->data[5 * stride] = sb.st_gid; |
|
/* ID of device containing directory entry for file (0 if not available) */ |
#if HAVE_STRUCT_STAT_ST_RDEV |
sarray->data[6 * stride] = sb.st_rdev; |
#else |
sarray->data[6 * stride] = 0; |
#endif |
|
/* File size (bytes) */ |
sarray->data[7 * stride] = sb.st_size; |
|
/* Last access time */ |
sarray->data[8 * stride] = sb.st_atime; |
|
/* Last modification time */ |
sarray->data[9 * stride] = sb.st_mtime; |
|
/* Last file status change time */ |
sarray->data[10 * stride] = sb.st_ctime; |
|
/* Preferred I/O block size (-1 if not available) */ |
#if HAVE_STRUCT_STAT_ST_BLKSIZE |
sarray->data[11 * stride] = sb.st_blksize; |
#else |
sarray->data[11 * stride] = -1; |
#endif |
|
/* Number of blocks allocated (-1 if not available) */ |
#if HAVE_STRUCT_STAT_ST_BLOCKS |
sarray->data[12 * stride] = sb.st_blocks; |
#else |
sarray->data[12 * stride] = -1; |
#endif |
} |
|
if (status != NULL) |
*status = (val == 0) ? 0 : errno; |
} |
|
|
extern void stat_i4_sub (char *, gfc_array_i4 *, GFC_INTEGER_4 *, |
gfc_charlen_type); |
iexport_proto(stat_i4_sub); |
|
void |
stat_i4_sub (char *name, gfc_array_i4 *sarray, GFC_INTEGER_4 *status, |
gfc_charlen_type name_len) |
{ |
stat_i4_sub_0 (name, sarray, status, name_len, 0); |
} |
iexport(stat_i4_sub); |
|
|
extern void lstat_i4_sub (char *, gfc_array_i4 *, GFC_INTEGER_4 *, |
gfc_charlen_type); |
iexport_proto(lstat_i4_sub); |
|
void |
lstat_i4_sub (char *name, gfc_array_i4 *sarray, GFC_INTEGER_4 *status, |
gfc_charlen_type name_len) |
{ |
stat_i4_sub_0 (name, sarray, status, name_len, 1); |
} |
iexport(lstat_i4_sub); |
|
|
|
static void |
stat_i8_sub_0 (char *name, gfc_array_i8 *sarray, GFC_INTEGER_8 *status, |
gfc_charlen_type name_len, int is_lstat __attribute__ ((unused))) |
{ |
int val; |
char *str; |
struct stat sb; |
|
/* If the rank of the array is not 1, abort. */ |
if (GFC_DESCRIPTOR_RANK (sarray) != 1) |
runtime_error ("Array rank of SARRAY is not 1."); |
|
/* If the array is too small, abort. */ |
if (GFC_DESCRIPTOR_EXTENT(sarray,0) < 13) |
runtime_error ("Array size of SARRAY is too small."); |
|
/* Trim trailing spaces from name. */ |
while (name_len > 0 && name[name_len - 1] == ' ') |
name_len--; |
|
/* Make a null terminated copy of the string. */ |
str = gfc_alloca (name_len + 1); |
memcpy (str, name, name_len); |
str[name_len] = '\0'; |
|
/* On platforms that don't provide lstat(), we use stat() instead. */ |
#ifdef HAVE_LSTAT |
if (is_lstat) |
val = lstat(str, &sb); |
else |
#endif |
val = stat(str, &sb); |
|
if (val == 0) |
{ |
index_type stride = GFC_DESCRIPTOR_STRIDE(sarray,0); |
|
/* Device ID */ |
sarray->data[0] = sb.st_dev; |
|
/* Inode number */ |
sarray->data[stride] = sb.st_ino; |
|
/* File mode */ |
sarray->data[2 * stride] = sb.st_mode; |
|
/* Number of (hard) links */ |
sarray->data[3 * stride] = sb.st_nlink; |
|
/* Owner's uid */ |
sarray->data[4 * stride] = sb.st_uid; |
|
/* Owner's gid */ |
sarray->data[5 * stride] = sb.st_gid; |
|
/* ID of device containing directory entry for file (0 if not available) */ |
#if HAVE_STRUCT_STAT_ST_RDEV |
sarray->data[6 * stride] = sb.st_rdev; |
#else |
sarray->data[6 * stride] = 0; |
#endif |
|
/* File size (bytes) */ |
sarray->data[7 * stride] = sb.st_size; |
|
/* Last access time */ |
sarray->data[8 * stride] = sb.st_atime; |
|
/* Last modification time */ |
sarray->data[9 * stride] = sb.st_mtime; |
|
/* Last file status change time */ |
sarray->data[10 * stride] = sb.st_ctime; |
|
/* Preferred I/O block size (-1 if not available) */ |
#if HAVE_STRUCT_STAT_ST_BLKSIZE |
sarray->data[11 * stride] = sb.st_blksize; |
#else |
sarray->data[11 * stride] = -1; |
#endif |
|
/* Number of blocks allocated (-1 if not available) */ |
#if HAVE_STRUCT_STAT_ST_BLOCKS |
sarray->data[12 * stride] = sb.st_blocks; |
#else |
sarray->data[12 * stride] = -1; |
#endif |
} |
|
if (status != NULL) |
*status = (val == 0) ? 0 : errno; |
} |
|
|
extern void stat_i8_sub (char *, gfc_array_i8 *, GFC_INTEGER_8 *, |
gfc_charlen_type); |
iexport_proto(stat_i8_sub); |
|
void |
stat_i8_sub (char *name, gfc_array_i8 *sarray, GFC_INTEGER_8 *status, |
gfc_charlen_type name_len) |
{ |
stat_i8_sub_0 (name, sarray, status, name_len, 0); |
} |
|
iexport(stat_i8_sub); |
|
|
extern void lstat_i8_sub (char *, gfc_array_i8 *, GFC_INTEGER_8 *, |
gfc_charlen_type); |
iexport_proto(lstat_i8_sub); |
|
void |
lstat_i8_sub (char *name, gfc_array_i8 *sarray, GFC_INTEGER_8 *status, |
gfc_charlen_type name_len) |
{ |
stat_i8_sub_0 (name, sarray, status, name_len, 1); |
} |
|
iexport(lstat_i8_sub); |
|
|
extern GFC_INTEGER_4 stat_i4 (char *, gfc_array_i4 *, gfc_charlen_type); |
export_proto(stat_i4); |
|
GFC_INTEGER_4 |
stat_i4 (char *name, gfc_array_i4 *sarray, gfc_charlen_type name_len) |
{ |
GFC_INTEGER_4 val; |
stat_i4_sub (name, sarray, &val, name_len); |
return val; |
} |
|
extern GFC_INTEGER_8 stat_i8 (char *, gfc_array_i8 *, gfc_charlen_type); |
export_proto(stat_i8); |
|
GFC_INTEGER_8 |
stat_i8 (char *name, gfc_array_i8 *sarray, gfc_charlen_type name_len) |
{ |
GFC_INTEGER_8 val; |
stat_i8_sub (name, sarray, &val, name_len); |
return val; |
} |
|
|
/* SUBROUTINE LSTAT(FILE, SARRAY, STATUS) |
CHARACTER(len=*), INTENT(IN) :: FILE |
INTEGER, INTENT(OUT), :: SARRAY(13) |
INTEGER, INTENT(OUT), OPTIONAL :: STATUS |
|
FUNCTION LSTAT(FILE, SARRAY) |
INTEGER LSTAT |
CHARACTER(len=*), INTENT(IN) :: FILE |
INTEGER, INTENT(OUT), :: SARRAY(13) */ |
|
extern GFC_INTEGER_4 lstat_i4 (char *, gfc_array_i4 *, gfc_charlen_type); |
export_proto(lstat_i4); |
|
GFC_INTEGER_4 |
lstat_i4 (char *name, gfc_array_i4 *sarray, gfc_charlen_type name_len) |
{ |
GFC_INTEGER_4 val; |
lstat_i4_sub (name, sarray, &val, name_len); |
return val; |
} |
|
extern GFC_INTEGER_8 lstat_i8 (char *, gfc_array_i8 *, gfc_charlen_type); |
export_proto(lstat_i8); |
|
GFC_INTEGER_8 |
lstat_i8 (char *name, gfc_array_i8 *sarray, gfc_charlen_type name_len) |
{ |
GFC_INTEGER_8 val; |
lstat_i8_sub (name, sarray, &val, name_len); |
return val; |
} |
|
#endif |
|
|
#ifdef HAVE_FSTAT |
|
/* SUBROUTINE FSTAT(UNIT, SARRAY, STATUS) |
INTEGER, INTENT(IN) :: UNIT |
INTEGER, INTENT(OUT) :: SARRAY(13) |
INTEGER, INTENT(OUT), OPTIONAL :: STATUS |
|
FUNCTION FSTAT(UNIT, SARRAY) |
INTEGER FSTAT |
INTEGER, INTENT(IN) :: UNIT |
INTEGER, INTENT(OUT) :: SARRAY(13) */ |
|
extern void fstat_i4_sub (GFC_INTEGER_4 *, gfc_array_i4 *, GFC_INTEGER_4 *); |
iexport_proto(fstat_i4_sub); |
|
void |
fstat_i4_sub (GFC_INTEGER_4 *unit, gfc_array_i4 *sarray, GFC_INTEGER_4 *status) |
{ |
int val; |
struct stat sb; |
|
/* If the rank of the array is not 1, abort. */ |
if (GFC_DESCRIPTOR_RANK (sarray) != 1) |
runtime_error ("Array rank of SARRAY is not 1."); |
|
/* If the array is too small, abort. */ |
if (GFC_DESCRIPTOR_EXTENT(sarray,0) < 13) |
runtime_error ("Array size of SARRAY is too small."); |
|
/* Convert Fortran unit number to C file descriptor. */ |
val = unit_to_fd (*unit); |
if (val >= 0) |
val = fstat(val, &sb); |
|
if (val == 0) |
{ |
index_type stride = GFC_DESCRIPTOR_STRIDE(sarray,0); |
|
/* Device ID */ |
sarray->data[0 * stride] = sb.st_dev; |
|
/* Inode number */ |
sarray->data[1 * stride] = sb.st_ino; |
|
/* File mode */ |
sarray->data[2 * stride] = sb.st_mode; |
|
/* Number of (hard) links */ |
sarray->data[3 * stride] = sb.st_nlink; |
|
/* Owner's uid */ |
sarray->data[4 * stride] = sb.st_uid; |
|
/* Owner's gid */ |
sarray->data[5 * stride] = sb.st_gid; |
|
/* ID of device containing directory entry for file (0 if not available) */ |
#if HAVE_STRUCT_STAT_ST_RDEV |
sarray->data[6 * stride] = sb.st_rdev; |
#else |
sarray->data[6 * stride] = 0; |
#endif |
|
/* File size (bytes) */ |
sarray->data[7 * stride] = sb.st_size; |
|
/* Last access time */ |
sarray->data[8 * stride] = sb.st_atime; |
|
/* Last modification time */ |
sarray->data[9 * stride] = sb.st_mtime; |
|
/* Last file status change time */ |
sarray->data[10 * stride] = sb.st_ctime; |
|
/* Preferred I/O block size (-1 if not available) */ |
#if HAVE_STRUCT_STAT_ST_BLKSIZE |
sarray->data[11 * stride] = sb.st_blksize; |
#else |
sarray->data[11 * stride] = -1; |
#endif |
|
/* Number of blocks allocated (-1 if not available) */ |
#if HAVE_STRUCT_STAT_ST_BLOCKS |
sarray->data[12 * stride] = sb.st_blocks; |
#else |
sarray->data[12 * stride] = -1; |
#endif |
} |
|
if (status != NULL) |
*status = (val == 0) ? 0 : errno; |
} |
iexport(fstat_i4_sub); |
|
extern void fstat_i8_sub (GFC_INTEGER_8 *, gfc_array_i8 *, GFC_INTEGER_8 *); |
iexport_proto(fstat_i8_sub); |
|
void |
fstat_i8_sub (GFC_INTEGER_8 *unit, gfc_array_i8 *sarray, GFC_INTEGER_8 *status) |
{ |
int val; |
struct stat sb; |
|
/* If the rank of the array is not 1, abort. */ |
if (GFC_DESCRIPTOR_RANK (sarray) != 1) |
runtime_error ("Array rank of SARRAY is not 1."); |
|
/* If the array is too small, abort. */ |
if (GFC_DESCRIPTOR_EXTENT(sarray,0) < 13) |
runtime_error ("Array size of SARRAY is too small."); |
|
/* Convert Fortran unit number to C file descriptor. */ |
val = unit_to_fd ((int) *unit); |
if (val >= 0) |
val = fstat(val, &sb); |
|
if (val == 0) |
{ |
index_type stride = GFC_DESCRIPTOR_STRIDE(sarray,0); |
|
/* Device ID */ |
sarray->data[0] = sb.st_dev; |
|
/* Inode number */ |
sarray->data[stride] = sb.st_ino; |
|
/* File mode */ |
sarray->data[2 * stride] = sb.st_mode; |
|
/* Number of (hard) links */ |
sarray->data[3 * stride] = sb.st_nlink; |
|
/* Owner's uid */ |
sarray->data[4 * stride] = sb.st_uid; |
|
/* Owner's gid */ |
sarray->data[5 * stride] = sb.st_gid; |
|
/* ID of device containing directory entry for file (0 if not available) */ |
#if HAVE_STRUCT_STAT_ST_RDEV |
sarray->data[6 * stride] = sb.st_rdev; |
#else |
sarray->data[6 * stride] = 0; |
#endif |
|
/* File size (bytes) */ |
sarray->data[7 * stride] = sb.st_size; |
|
/* Last access time */ |
sarray->data[8 * stride] = sb.st_atime; |
|
/* Last modification time */ |
sarray->data[9 * stride] = sb.st_mtime; |
|
/* Last file status change time */ |
sarray->data[10 * stride] = sb.st_ctime; |
|
/* Preferred I/O block size (-1 if not available) */ |
#if HAVE_STRUCT_STAT_ST_BLKSIZE |
sarray->data[11 * stride] = sb.st_blksize; |
#else |
sarray->data[11 * stride] = -1; |
#endif |
|
/* Number of blocks allocated (-1 if not available) */ |
#if HAVE_STRUCT_STAT_ST_BLOCKS |
sarray->data[12 * stride] = sb.st_blocks; |
#else |
sarray->data[12 * stride] = -1; |
#endif |
} |
|
if (status != NULL) |
*status = (val == 0) ? 0 : errno; |
} |
iexport(fstat_i8_sub); |
|
extern GFC_INTEGER_4 fstat_i4 (GFC_INTEGER_4 *, gfc_array_i4 *); |
export_proto(fstat_i4); |
|
GFC_INTEGER_4 |
fstat_i4 (GFC_INTEGER_4 *unit, gfc_array_i4 *sarray) |
{ |
GFC_INTEGER_4 val; |
fstat_i4_sub (unit, sarray, &val); |
return val; |
} |
|
extern GFC_INTEGER_8 fstat_i8 (GFC_INTEGER_8 *, gfc_array_i8 *); |
export_proto(fstat_i8); |
|
GFC_INTEGER_8 |
fstat_i8 (GFC_INTEGER_8 *unit, gfc_array_i8 *sarray) |
{ |
GFC_INTEGER_8 val; |
fstat_i8_sub (unit, sarray, &val); |
return val; |
} |
|
#endif |
/getcwd.c
0,0 → 1,83
/* Implementation of the GETCWD intrinsic. |
Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc. |
Contributed by Steven G. Kargl <kargls@comcast.net>. |
|
This file is part of the GNU Fortran 95 runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
|
#include <string.h> |
#include <errno.h> |
|
#ifdef HAVE_UNISTD_H |
#include <unistd.h> |
#endif |
|
#ifdef HAVE_GETCWD |
|
extern void getcwd_i4_sub (char *, GFC_INTEGER_4 *, gfc_charlen_type); |
iexport_proto(getcwd_i4_sub); |
|
void |
getcwd_i4_sub (char *cwd, GFC_INTEGER_4 *status, gfc_charlen_type cwd_len) |
{ |
char str[cwd_len + 1]; |
GFC_INTEGER_4 stat; |
|
memset(cwd, ' ', (size_t) cwd_len); |
|
if (!getcwd (str, (size_t) cwd_len + 1)) |
stat = errno; |
else |
{ |
stat = 0; |
memcpy (cwd, str, strlen (str)); |
} |
if (status != NULL) |
*status = stat; |
} |
iexport(getcwd_i4_sub); |
|
extern void getcwd_i8_sub (char *, GFC_INTEGER_8 *, gfc_charlen_type); |
export_proto(getcwd_i8_sub); |
|
void |
getcwd_i8_sub (char *cwd, GFC_INTEGER_8 *status, gfc_charlen_type cwd_len) |
{ |
GFC_INTEGER_4 status4; |
getcwd_i4_sub (cwd, &status4, cwd_len); |
if (status) |
*status = status4; |
} |
|
extern GFC_INTEGER_4 PREFIX(getcwd) (char *, gfc_charlen_type); |
export_proto_np(PREFIX(getcwd)); |
|
GFC_INTEGER_4 |
PREFIX(getcwd) (char *cwd, gfc_charlen_type cwd_len) |
{ |
GFC_INTEGER_4 status; |
getcwd_i4_sub (cwd, &status, cwd_len); |
return status; |
} |
|
#endif |
/date_and_time.c
0,0 → 1,631
/* Implementation of the DATE_AND_TIME intrinsic. |
Copyright (C) 2003, 2004, 2005, 2006, 2007, 2009, 2010, 2011 |
Free Software Foundation, Inc. |
Contributed by Steven Bosscher. |
|
This file is part of the GNU Fortran runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
#include <string.h> |
#include <assert.h> |
#include <stdlib.h> |
|
#include "time_1.h" |
|
|
/* If the re-entrant version of gmtime is not available, provide a |
fallback implementation. On some targets where the _r version is |
not available, gmtime uses thread-local storage so it's |
threadsafe. */ |
|
#ifndef HAVE_GMTIME_R |
/* If _POSIX is defined gmtime_r gets defined by mingw-w64 headers. */ |
#ifdef gmtime_r |
#undef gmtime_r |
#endif |
|
static struct tm * |
gmtime_r (const time_t * timep, struct tm * result) |
{ |
*result = *gmtime (timep); |
return result; |
} |
#endif |
|
|
/* DATE_AND_TIME ([DATE, TIME, ZONE, VALUES]) |
|
Description: Returns data on the real-time clock and date in a form |
compatible with the representations defined in ISO 8601:1988. |
|
Class: Non-elemental subroutine. |
|
Arguments: |
|
DATE (optional) shall be scalar and of type default character. |
It is an INTENT(OUT) argument. It is assigned a value of the |
form CCYYMMDD, where CC is the century, YY the year within the |
century, MM the month within the year, and DD the day within the |
month. If there is no date available, they are assigned blanks. |
|
TIME (optional) shall be scalar and of type default character. |
It is an INTENT(OUT) argument. It is assigned a value of the |
form hhmmss.sss, where hh is the hour of the day, mm is the |
minutes of the hour, and ss.sss is the seconds and milliseconds |
of the minute. If there is no clock available, they are assigned |
blanks. |
|
ZONE (optional) shall be scalar and of type default character. |
It is an INTENT(OUT) argument. It is assigned a value of the |
form [+-]hhmm, where hh and mm are the time difference with |
respect to Coordinated Universal Time (UTC) in hours and parts |
of an hour expressed in minutes, respectively. If there is no |
clock available, they are assigned blanks. |
|
VALUES (optional) shall be of type default integer and of rank |
one. It is an INTENT(OUT) argument. Its size shall be at least |
8. The values returned in VALUES are as follows: |
|
VALUES(1) the year (for example, 2003), or -HUGE(0) if there is |
no date available; |
|
VALUES(2) the month of the year, or -HUGE(0) if there |
is no date available; |
|
VALUES(3) the day of the month, or -HUGE(0) if there is no date |
available; |
|
VALUES(4) the time difference with respect to Coordinated |
Universal Time (UTC) in minutes, or -HUGE(0) if this information |
is not available; |
|
VALUES(5) the hour of the day, in the range of 0 to 23, or |
-HUGE(0) if there is no clock; |
|
VALUES(6) the minutes of the hour, in the range 0 to 59, or |
-HUGE(0) if there is no clock; |
|
VALUES(7) the seconds of the minute, in the range 0 to 60, or |
-HUGE(0) if there is no clock; |
|
VALUES(8) the milliseconds of the second, in the range 0 to |
999, or -HUGE(0) if there is no clock. |
|
NULL pointer represent missing OPTIONAL arguments. All arguments |
have INTENT(OUT). Because of the -i8 option, we must implement |
VALUES for INTEGER(kind=4) and INTEGER(kind=8). |
|
Based on libU77's date_time_.c. |
|
TODO : |
- Check year boundaries. |
*/ |
#define DATE_LEN 8 |
#define TIME_LEN 10 |
#define ZONE_LEN 5 |
#define VALUES_SIZE 8 |
|
extern void date_and_time (char *, char *, char *, gfc_array_i4 *, |
GFC_INTEGER_4, GFC_INTEGER_4, GFC_INTEGER_4); |
export_proto(date_and_time); |
|
void |
date_and_time (char *__date, char *__time, char *__zone, |
gfc_array_i4 *__values, GFC_INTEGER_4 __date_len, |
GFC_INTEGER_4 __time_len, GFC_INTEGER_4 __zone_len) |
{ |
int i; |
char date[DATE_LEN + 1]; |
char timec[TIME_LEN + 1]; |
char zone[ZONE_LEN + 1]; |
GFC_INTEGER_4 values[VALUES_SIZE]; |
|
time_t lt; |
struct tm local_time; |
struct tm UTC_time; |
|
long usecs; |
|
if (!gf_gettime (<, &usecs)) |
{ |
values[7] = usecs / 1000; |
|
localtime_r (<, &local_time); |
gmtime_r (<, &UTC_time); |
|
/* All arguments can be derived from VALUES. */ |
values[0] = 1900 + local_time.tm_year; |
values[1] = 1 + local_time.tm_mon; |
values[2] = local_time.tm_mday; |
values[3] = (local_time.tm_min - UTC_time.tm_min + |
60 * (local_time.tm_hour - UTC_time.tm_hour + |
24 * (local_time.tm_yday - UTC_time.tm_yday))); |
values[4] = local_time.tm_hour; |
values[5] = local_time.tm_min; |
values[6] = local_time.tm_sec; |
|
if (__date) |
snprintf (date, DATE_LEN + 1, "%04d%02d%02d", |
values[0], values[1], values[2]); |
if (__time) |
snprintf (timec, TIME_LEN + 1, "%02d%02d%02d.%03d", |
values[4], values[5], values[6], values[7]); |
|
if (__zone) |
snprintf (zone, ZONE_LEN + 1, "%+03d%02d", |
values[3] / 60, abs (values[3] % 60)); |
} |
else |
{ |
memset (date, ' ', DATE_LEN); |
date[DATE_LEN] = '\0'; |
|
memset (timec, ' ', TIME_LEN); |
timec[TIME_LEN] = '\0'; |
|
memset (zone, ' ', ZONE_LEN); |
zone[ZONE_LEN] = '\0'; |
|
for (i = 0; i < VALUES_SIZE; i++) |
values[i] = - GFC_INTEGER_4_HUGE; |
} |
|
/* Copy the values into the arguments. */ |
if (__values) |
{ |
index_type len, delta, elt_size; |
|
elt_size = GFC_DESCRIPTOR_SIZE (__values); |
len = GFC_DESCRIPTOR_EXTENT(__values,0); |
delta = GFC_DESCRIPTOR_STRIDE(__values,0); |
if (delta == 0) |
delta = 1; |
|
if (unlikely (len < VALUES_SIZE)) |
runtime_error ("Incorrect extent in VALUE argument to" |
" DATE_AND_TIME intrinsic: is %ld, should" |
" be >=%ld", (long int) len, (long int) VALUES_SIZE); |
|
/* Cope with different type kinds. */ |
if (elt_size == 4) |
{ |
GFC_INTEGER_4 *vptr4 = __values->data; |
|
for (i = 0; i < VALUES_SIZE; i++, vptr4 += delta) |
*vptr4 = values[i]; |
} |
else if (elt_size == 8) |
{ |
GFC_INTEGER_8 *vptr8 = (GFC_INTEGER_8 *)__values->data; |
|
for (i = 0; i < VALUES_SIZE; i++, vptr8 += delta) |
{ |
if (values[i] == - GFC_INTEGER_4_HUGE) |
*vptr8 = - GFC_INTEGER_8_HUGE; |
else |
*vptr8 = values[i]; |
} |
} |
else |
abort (); |
} |
|
if (__zone) |
fstrcpy (__zone, __zone_len, zone, ZONE_LEN); |
|
if (__time) |
fstrcpy (__time, __time_len, timec, TIME_LEN); |
|
if (__date) |
fstrcpy (__date, __date_len, date, DATE_LEN); |
} |
|
|
/* SECNDS (X) - Non-standard |
|
Description: Returns the system time of day, or elapsed time, as a GFC_REAL_4 |
in seconds. |
|
Class: Non-elemental subroutine. |
|
Arguments: |
|
X must be REAL(4) and the result is of the same type. The accuracy is system |
dependent. |
|
Usage: |
|
T = SECNDS (X) |
|
yields the time in elapsed seconds since X. If X is 0.0, T is the time in |
seconds since midnight. Note that a time that spans midnight but is less than |
24hours will be calculated correctly. */ |
|
extern GFC_REAL_4 secnds (GFC_REAL_4 *); |
export_proto(secnds); |
|
GFC_REAL_4 |
secnds (GFC_REAL_4 *x) |
{ |
GFC_INTEGER_4 values[VALUES_SIZE]; |
GFC_REAL_4 temp1, temp2; |
|
/* Make the INTEGER*4 array for passing to date_and_time. */ |
gfc_array_i4 *avalues = internal_malloc_size (sizeof (gfc_array_i4)); |
avalues->data = &values[0]; |
GFC_DESCRIPTOR_DTYPE (avalues) = ((BT_REAL << GFC_DTYPE_TYPE_SHIFT) |
& GFC_DTYPE_TYPE_MASK) + |
(4 << GFC_DTYPE_SIZE_SHIFT); |
|
GFC_DIMENSION_SET(avalues->dim[0], 0, 7, 1); |
|
date_and_time (NULL, NULL, NULL, avalues, 0, 0, 0); |
|
free (avalues); |
|
temp1 = 3600.0 * (GFC_REAL_4)values[4] + |
60.0 * (GFC_REAL_4)values[5] + |
(GFC_REAL_4)values[6] + |
0.001 * (GFC_REAL_4)values[7]; |
temp2 = fmod (*x, 86400.0); |
temp2 = (temp1 - temp2 >= 0.0) ? temp2 : (temp2 - 86400.0); |
return temp1 - temp2; |
} |
|
|
|
/* ITIME(X) - Non-standard |
|
Description: Returns the current local time hour, minutes, and seconds |
in elements 1, 2, and 3 of X, respectively. */ |
|
static void |
itime0 (int x[3]) |
{ |
time_t lt; |
struct tm local_time; |
|
lt = time (NULL); |
|
if (lt != (time_t) -1) |
{ |
localtime_r (<, &local_time); |
|
x[0] = local_time.tm_hour; |
x[1] = local_time.tm_min; |
x[2] = local_time.tm_sec; |
} |
} |
|
extern void itime_i4 (gfc_array_i4 *); |
export_proto(itime_i4); |
|
void |
itime_i4 (gfc_array_i4 *__values) |
{ |
int x[3], i; |
index_type len, delta; |
GFC_INTEGER_4 *vptr; |
|
/* Call helper function. */ |
itime0(x); |
|
/* Copy the value into the array. */ |
len = GFC_DESCRIPTOR_EXTENT(__values,0); |
assert (len >= 3); |
delta = GFC_DESCRIPTOR_STRIDE(__values,0); |
if (delta == 0) |
delta = 1; |
|
vptr = __values->data; |
for (i = 0; i < 3; i++, vptr += delta) |
*vptr = x[i]; |
} |
|
|
extern void itime_i8 (gfc_array_i8 *); |
export_proto(itime_i8); |
|
void |
itime_i8 (gfc_array_i8 *__values) |
{ |
int x[3], i; |
index_type len, delta; |
GFC_INTEGER_8 *vptr; |
|
/* Call helper function. */ |
itime0(x); |
|
/* Copy the value into the array. */ |
len = GFC_DESCRIPTOR_EXTENT(__values,0); |
assert (len >= 3); |
delta = GFC_DESCRIPTOR_STRIDE(__values,0); |
if (delta == 0) |
delta = 1; |
|
vptr = __values->data; |
for (i = 0; i < 3; i++, vptr += delta) |
*vptr = x[i]; |
} |
|
|
|
/* IDATE(X) - Non-standard |
|
Description: Fills TArray with the numerical values at the current |
local time. The day (in the range 1-31), month (in the range 1-12), |
and year appear in elements 1, 2, and 3 of X, respectively. |
The year has four significant digits. */ |
|
static void |
idate0 (int x[3]) |
{ |
time_t lt; |
struct tm local_time; |
|
lt = time (NULL); |
|
if (lt != (time_t) -1) |
{ |
localtime_r (<, &local_time); |
|
x[0] = local_time.tm_mday; |
x[1] = 1 + local_time.tm_mon; |
x[2] = 1900 + local_time.tm_year; |
} |
} |
|
extern void idate_i4 (gfc_array_i4 *); |
export_proto(idate_i4); |
|
void |
idate_i4 (gfc_array_i4 *__values) |
{ |
int x[3], i; |
index_type len, delta; |
GFC_INTEGER_4 *vptr; |
|
/* Call helper function. */ |
idate0(x); |
|
/* Copy the value into the array. */ |
len = GFC_DESCRIPTOR_EXTENT(__values,0); |
assert (len >= 3); |
delta = GFC_DESCRIPTOR_STRIDE(__values,0); |
if (delta == 0) |
delta = 1; |
|
vptr = __values->data; |
for (i = 0; i < 3; i++, vptr += delta) |
*vptr = x[i]; |
} |
|
|
extern void idate_i8 (gfc_array_i8 *); |
export_proto(idate_i8); |
|
void |
idate_i8 (gfc_array_i8 *__values) |
{ |
int x[3], i; |
index_type len, delta; |
GFC_INTEGER_8 *vptr; |
|
/* Call helper function. */ |
idate0(x); |
|
/* Copy the value into the array. */ |
len = GFC_DESCRIPTOR_EXTENT(__values,0); |
assert (len >= 3); |
delta = GFC_DESCRIPTOR_STRIDE(__values,0); |
if (delta == 0) |
delta = 1; |
|
vptr = __values->data; |
for (i = 0; i < 3; i++, vptr += delta) |
*vptr = x[i]; |
} |
|
|
|
/* GMTIME(STIME, TARRAY) - Non-standard |
|
Description: Given a system time value STime, fills TArray with values |
extracted from it appropriate to the GMT time zone using gmtime_r(3). |
|
The array elements are as follows: |
|
1. Seconds after the minute, range 0-59 or 0-61 to allow for leap seconds |
2. Minutes after the hour, range 0-59 |
3. Hours past midnight, range 0-23 |
4. Day of month, range 0-31 |
5. Number of months since January, range 0-11 |
6. Years since 1900 |
7. Number of days since Sunday, range 0-6 |
8. Days since January 1 |
9. Daylight savings indicator: positive if daylight savings is in effect, |
zero if not, and negative if the information isn't available. */ |
|
static void |
gmtime_0 (const time_t * t, int x[9]) |
{ |
struct tm lt; |
|
gmtime_r (t, <); |
x[0] = lt.tm_sec; |
x[1] = lt.tm_min; |
x[2] = lt.tm_hour; |
x[3] = lt.tm_mday; |
x[4] = lt.tm_mon; |
x[5] = lt.tm_year; |
x[6] = lt.tm_wday; |
x[7] = lt.tm_yday; |
x[8] = lt.tm_isdst; |
} |
|
extern void gmtime_i4 (GFC_INTEGER_4 *, gfc_array_i4 *); |
export_proto(gmtime_i4); |
|
void |
gmtime_i4 (GFC_INTEGER_4 * t, gfc_array_i4 * tarray) |
{ |
int x[9], i; |
index_type len, delta; |
GFC_INTEGER_4 *vptr; |
time_t tt; |
|
/* Call helper function. */ |
tt = (time_t) *t; |
gmtime_0(&tt, x); |
|
/* Copy the values into the array. */ |
len = GFC_DESCRIPTOR_EXTENT(tarray,0); |
assert (len >= 9); |
delta = GFC_DESCRIPTOR_STRIDE(tarray,0); |
if (delta == 0) |
delta = 1; |
|
vptr = tarray->data; |
for (i = 0; i < 9; i++, vptr += delta) |
*vptr = x[i]; |
} |
|
extern void gmtime_i8 (GFC_INTEGER_8 *, gfc_array_i8 *); |
export_proto(gmtime_i8); |
|
void |
gmtime_i8 (GFC_INTEGER_8 * t, gfc_array_i8 * tarray) |
{ |
int x[9], i; |
index_type len, delta; |
GFC_INTEGER_8 *vptr; |
time_t tt; |
|
/* Call helper function. */ |
tt = (time_t) *t; |
gmtime_0(&tt, x); |
|
/* Copy the values into the array. */ |
len = GFC_DESCRIPTOR_EXTENT(tarray,0); |
assert (len >= 9); |
delta = GFC_DESCRIPTOR_STRIDE(tarray,0); |
if (delta == 0) |
delta = 1; |
|
vptr = tarray->data; |
for (i = 0; i < 9; i++, vptr += delta) |
*vptr = x[i]; |
} |
|
|
|
|
/* LTIME(STIME, TARRAY) - Non-standard |
|
Description: Given a system time value STime, fills TArray with values |
extracted from it appropriate to the local time zone using localtime_r(3). |
|
The array elements are as follows: |
|
1. Seconds after the minute, range 0-59 or 0-61 to allow for leap seconds |
2. Minutes after the hour, range 0-59 |
3. Hours past midnight, range 0-23 |
4. Day of month, range 0-31 |
5. Number of months since January, range 0-11 |
6. Years since 1900 |
7. Number of days since Sunday, range 0-6 |
8. Days since January 1 |
9. Daylight savings indicator: positive if daylight savings is in effect, |
zero if not, and negative if the information isn't available. */ |
|
static void |
ltime_0 (const time_t * t, int x[9]) |
{ |
struct tm lt; |
|
localtime_r (t, <); |
x[0] = lt.tm_sec; |
x[1] = lt.tm_min; |
x[2] = lt.tm_hour; |
x[3] = lt.tm_mday; |
x[4] = lt.tm_mon; |
x[5] = lt.tm_year; |
x[6] = lt.tm_wday; |
x[7] = lt.tm_yday; |
x[8] = lt.tm_isdst; |
} |
|
extern void ltime_i4 (GFC_INTEGER_4 *, gfc_array_i4 *); |
export_proto(ltime_i4); |
|
void |
ltime_i4 (GFC_INTEGER_4 * t, gfc_array_i4 * tarray) |
{ |
int x[9], i; |
index_type len, delta; |
GFC_INTEGER_4 *vptr; |
time_t tt; |
|
/* Call helper function. */ |
tt = (time_t) *t; |
ltime_0(&tt, x); |
|
/* Copy the values into the array. */ |
len = GFC_DESCRIPTOR_EXTENT(tarray,0); |
assert (len >= 9); |
delta = GFC_DESCRIPTOR_STRIDE(tarray,0); |
if (delta == 0) |
delta = 1; |
|
vptr = tarray->data; |
for (i = 0; i < 9; i++, vptr += delta) |
*vptr = x[i]; |
} |
|
extern void ltime_i8 (GFC_INTEGER_8 *, gfc_array_i8 *); |
export_proto(ltime_i8); |
|
void |
ltime_i8 (GFC_INTEGER_8 * t, gfc_array_i8 * tarray) |
{ |
int x[9], i; |
index_type len, delta; |
GFC_INTEGER_8 *vptr; |
time_t tt; |
|
/* Call helper function. */ |
tt = (time_t) * t; |
ltime_0(&tt, x); |
|
/* Copy the values into the array. */ |
len = GFC_DESCRIPTOR_EXTENT(tarray,0); |
assert (len >= 9); |
delta = GFC_DESCRIPTOR_STRIDE(tarray,0); |
if (delta == 0) |
delta = 1; |
|
vptr = tarray->data; |
for (i = 0; i < 9; i++, vptr += delta) |
*vptr = x[i]; |
} |
|
|
/unpack_generic.c
0,0 → 1,630
/* Generic implementation of the UNPACK intrinsic |
Copyright 2002, 2003, 2004, 2005, 2007, 2009, 2010 |
Free Software Foundation, Inc. |
Contributed by Paul Brook <paul@nowt.org> |
|
This file is part of the GNU Fortran 95 runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Ligbfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
#include <stdlib.h> |
#include <assert.h> |
#include <string.h> |
|
/* All the bounds checking for unpack in one function. If field is NULL, |
we don't check it, for the unpack0 functions. */ |
|
static void |
unpack_bounds (gfc_array_char *ret, const gfc_array_char *vector, |
const gfc_array_l1 *mask, const gfc_array_char *field) |
{ |
index_type vec_size, mask_count; |
vec_size = size0 ((array_t *) vector); |
mask_count = count_0 (mask); |
if (vec_size < mask_count) |
runtime_error ("Incorrect size of return value in UNPACK" |
" intrinsic: should be at least %ld, is" |
" %ld", (long int) mask_count, |
(long int) vec_size); |
|
if (field != NULL) |
bounds_equal_extents ((array_t *) field, (array_t *) mask, |
"FIELD", "UNPACK"); |
|
if (ret->data != NULL) |
bounds_equal_extents ((array_t *) ret, (array_t *) mask, |
"return value", "UNPACK"); |
|
} |
|
static void |
unpack_internal (gfc_array_char *ret, const gfc_array_char *vector, |
const gfc_array_l1 *mask, const gfc_array_char *field, |
index_type size) |
{ |
/* r.* indicates the return array. */ |
index_type rstride[GFC_MAX_DIMENSIONS]; |
index_type rstride0; |
index_type rs; |
char * restrict rptr; |
/* v.* indicates the vector array. */ |
index_type vstride0; |
char *vptr; |
/* f.* indicates the field array. */ |
index_type fstride[GFC_MAX_DIMENSIONS]; |
index_type fstride0; |
const char *fptr; |
/* m.* indicates the mask array. */ |
index_type mstride[GFC_MAX_DIMENSIONS]; |
index_type mstride0; |
const GFC_LOGICAL_1 *mptr; |
|
index_type count[GFC_MAX_DIMENSIONS]; |
index_type extent[GFC_MAX_DIMENSIONS]; |
index_type n; |
index_type dim; |
|
int empty; |
int mask_kind; |
|
empty = 0; |
|
mptr = mask->data; |
|
/* Use the same loop for all logical types, by using GFC_LOGICAL_1 |
and using shifting to address size and endian issues. */ |
|
mask_kind = GFC_DESCRIPTOR_SIZE (mask); |
|
if (mask_kind == 1 || mask_kind == 2 || mask_kind == 4 || mask_kind == 8 |
#ifdef HAVE_GFC_LOGICAL_16 |
|| mask_kind == 16 |
#endif |
) |
{ |
/* Don't convert a NULL pointer as we use test for NULL below. */ |
if (mptr) |
mptr = GFOR_POINTER_TO_L1 (mptr, mask_kind); |
} |
else |
runtime_error ("Funny sized logical array"); |
|
if (ret->data == NULL) |
{ |
/* The front end has signalled that we need to populate the |
return array descriptor. */ |
dim = GFC_DESCRIPTOR_RANK (mask); |
rs = 1; |
for (n = 0; n < dim; n++) |
{ |
count[n] = 0; |
GFC_DIMENSION_SET(ret->dim[n], 0, |
GFC_DESCRIPTOR_EXTENT(mask,n) - 1, rs); |
extent[n] = GFC_DESCRIPTOR_EXTENT(ret,n); |
empty = empty || extent[n] <= 0; |
rstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(ret, n); |
fstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(field, n); |
mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask, n); |
rs *= extent[n]; |
} |
ret->offset = 0; |
ret->data = internal_malloc_size (rs * size); |
} |
else |
{ |
dim = GFC_DESCRIPTOR_RANK (ret); |
for (n = 0; n < dim; n++) |
{ |
count[n] = 0; |
extent[n] = GFC_DESCRIPTOR_EXTENT(ret,n); |
empty = empty || extent[n] <= 0; |
rstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(ret, n); |
fstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(field, n); |
mstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(mask, n); |
} |
} |
|
if (empty) |
return; |
|
vstride0 = GFC_DESCRIPTOR_STRIDE_BYTES(vector,0); |
rstride0 = rstride[0]; |
fstride0 = fstride[0]; |
mstride0 = mstride[0]; |
rptr = ret->data; |
fptr = field->data; |
vptr = vector->data; |
|
while (rptr) |
{ |
if (*mptr) |
{ |
/* From vector. */ |
memcpy (rptr, vptr, size); |
vptr += vstride0; |
} |
else |
{ |
/* From field. */ |
memcpy (rptr, fptr, size); |
} |
/* Advance to the next element. */ |
rptr += rstride0; |
fptr += fstride0; |
mptr += mstride0; |
count[0]++; |
n = 0; |
while (count[n] == extent[n]) |
{ |
/* When we get to the end of a dimension, reset it and increment |
the next dimension. */ |
count[n] = 0; |
/* We could precalculate these products, but this is a less |
frequently used path so probably not worth it. */ |
rptr -= rstride[n] * extent[n]; |
fptr -= fstride[n] * extent[n]; |
mptr -= mstride[n] * extent[n]; |
n++; |
if (n >= dim) |
{ |
/* Break out of the loop. */ |
rptr = NULL; |
break; |
} |
else |
{ |
count[n]++; |
rptr += rstride[n]; |
fptr += fstride[n]; |
mptr += mstride[n]; |
} |
} |
} |
} |
|
extern void unpack1 (gfc_array_char *, const gfc_array_char *, |
const gfc_array_l1 *, const gfc_array_char *); |
export_proto(unpack1); |
|
void |
unpack1 (gfc_array_char *ret, const gfc_array_char *vector, |
const gfc_array_l1 *mask, const gfc_array_char *field) |
{ |
index_type type_size; |
index_type size; |
|
if (unlikely(compile_options.bounds_check)) |
unpack_bounds (ret, vector, mask, field); |
|
type_size = GFC_DTYPE_TYPE_SIZE (vector); |
size = GFC_DESCRIPTOR_SIZE (vector); |
|
switch(type_size) |
{ |
case GFC_DTYPE_LOGICAL_1: |
case GFC_DTYPE_INTEGER_1: |
case GFC_DTYPE_DERIVED_1: |
unpack1_i1 ((gfc_array_i1 *) ret, (gfc_array_i1 *) vector, |
mask, (gfc_array_i1 *) field); |
return; |
|
case GFC_DTYPE_LOGICAL_2: |
case GFC_DTYPE_INTEGER_2: |
unpack1_i2 ((gfc_array_i2 *) ret, (gfc_array_i2 *) vector, |
mask, (gfc_array_i2 *) field); |
return; |
|
case GFC_DTYPE_LOGICAL_4: |
case GFC_DTYPE_INTEGER_4: |
unpack1_i4 ((gfc_array_i4 *) ret, (gfc_array_i4 *) vector, |
mask, (gfc_array_i4 *) field); |
return; |
|
case GFC_DTYPE_LOGICAL_8: |
case GFC_DTYPE_INTEGER_8: |
unpack1_i8 ((gfc_array_i8 *) ret, (gfc_array_i8 *) vector, |
mask, (gfc_array_i8 *) field); |
return; |
|
#ifdef HAVE_GFC_INTEGER_16 |
case GFC_DTYPE_LOGICAL_16: |
case GFC_DTYPE_INTEGER_16: |
unpack1_i16 ((gfc_array_i16 *) ret, (gfc_array_i16 *) vector, |
mask, (gfc_array_i16 *) field); |
return; |
#endif |
|
case GFC_DTYPE_REAL_4: |
unpack1_r4 ((gfc_array_r4 *) ret, (gfc_array_r4 *) vector, |
mask, (gfc_array_r4 *) field); |
return; |
|
case GFC_DTYPE_REAL_8: |
unpack1_r8 ((gfc_array_r8 *) ret, (gfc_array_r8 *) vector, |
mask, (gfc_array_r8 *) field); |
return; |
|
/* FIXME: This here is a hack, which will have to be removed when |
the array descriptor is reworked. Currently, we don't store the |
kind value for the type, but only the size. Because on targets with |
__float128, we have sizeof(logn double) == sizeof(__float128), |
we cannot discriminate here and have to fall back to the generic |
handling (which is suboptimal). */ |
#if !defined(GFC_REAL_16_IS_FLOAT128) |
# ifdef HAVE_GFC_REAL_10 |
case GFC_DTYPE_REAL_10: |
unpack1_r10 ((gfc_array_r10 *) ret, (gfc_array_r10 *) vector, |
mask, (gfc_array_r10 *) field); |
return; |
# endif |
|
# ifdef HAVE_GFC_REAL_16 |
case GFC_DTYPE_REAL_16: |
unpack1_r16 ((gfc_array_r16 *) ret, (gfc_array_r16 *) vector, |
mask, (gfc_array_r16 *) field); |
return; |
# endif |
#endif |
|
case GFC_DTYPE_COMPLEX_4: |
unpack1_c4 ((gfc_array_c4 *) ret, (gfc_array_c4 *) vector, |
mask, (gfc_array_c4 *) field); |
return; |
|
case GFC_DTYPE_COMPLEX_8: |
unpack1_c8 ((gfc_array_c8 *) ret, (gfc_array_c8 *) vector, |
mask, (gfc_array_c8 *) field); |
return; |
|
/* FIXME: This here is a hack, which will have to be removed when |
the array descriptor is reworked. Currently, we don't store the |
kind value for the type, but only the size. Because on targets with |
__float128, we have sizeof(logn double) == sizeof(__float128), |
we cannot discriminate here and have to fall back to the generic |
handling (which is suboptimal). */ |
#if !defined(GFC_REAL_16_IS_FLOAT128) |
# ifdef HAVE_GFC_COMPLEX_10 |
case GFC_DTYPE_COMPLEX_10: |
unpack1_c10 ((gfc_array_c10 *) ret, (gfc_array_c10 *) vector, |
mask, (gfc_array_c10 *) field); |
return; |
# endif |
|
# ifdef HAVE_GFC_COMPLEX_16 |
case GFC_DTYPE_COMPLEX_16: |
unpack1_c16 ((gfc_array_c16 *) ret, (gfc_array_c16 *) vector, |
mask, (gfc_array_c16 *) field); |
return; |
# endif |
#endif |
|
case GFC_DTYPE_DERIVED_2: |
if (GFC_UNALIGNED_2(ret->data) || GFC_UNALIGNED_2(vector->data) |
|| GFC_UNALIGNED_2(field->data)) |
break; |
else |
{ |
unpack1_i2 ((gfc_array_i2 *) ret, (gfc_array_i2 *) vector, |
mask, (gfc_array_i2 *) field); |
return; |
} |
|
case GFC_DTYPE_DERIVED_4: |
if (GFC_UNALIGNED_4(ret->data) || GFC_UNALIGNED_4(vector->data) |
|| GFC_UNALIGNED_4(field->data)) |
break; |
else |
{ |
unpack1_i4 ((gfc_array_i4 *) ret, (gfc_array_i4 *) vector, |
mask, (gfc_array_i4 *) field); |
return; |
} |
|
case GFC_DTYPE_DERIVED_8: |
if (GFC_UNALIGNED_8(ret->data) || GFC_UNALIGNED_8(vector->data) |
|| GFC_UNALIGNED_8(field->data)) |
break; |
else |
{ |
unpack1_i8 ((gfc_array_i8 *) ret, (gfc_array_i8 *) vector, |
mask, (gfc_array_i8 *) field); |
return; |
} |
|
#ifdef HAVE_GFC_INTEGER_16 |
case GFC_DTYPE_DERIVED_16: |
if (GFC_UNALIGNED_16(ret->data) || GFC_UNALIGNED_16(vector->data) |
|| GFC_UNALIGNED_16(field->data)) |
break; |
else |
{ |
unpack1_i16 ((gfc_array_i16 *) ret, (gfc_array_i16 *) vector, |
mask, (gfc_array_i16 *) field); |
return; |
} |
#endif |
} |
|
unpack_internal (ret, vector, mask, field, size); |
} |
|
|
extern void unpack1_char (gfc_array_char *, GFC_INTEGER_4, |
const gfc_array_char *, const gfc_array_l1 *, |
const gfc_array_char *, GFC_INTEGER_4, |
GFC_INTEGER_4); |
export_proto(unpack1_char); |
|
void |
unpack1_char (gfc_array_char *ret, |
GFC_INTEGER_4 ret_length __attribute__((unused)), |
const gfc_array_char *vector, const gfc_array_l1 *mask, |
const gfc_array_char *field, GFC_INTEGER_4 vector_length, |
GFC_INTEGER_4 field_length __attribute__((unused))) |
{ |
|
if (unlikely(compile_options.bounds_check)) |
unpack_bounds (ret, vector, mask, field); |
|
unpack_internal (ret, vector, mask, field, vector_length); |
} |
|
|
extern void unpack1_char4 (gfc_array_char *, GFC_INTEGER_4, |
const gfc_array_char *, const gfc_array_l1 *, |
const gfc_array_char *, GFC_INTEGER_4, |
GFC_INTEGER_4); |
export_proto(unpack1_char4); |
|
void |
unpack1_char4 (gfc_array_char *ret, |
GFC_INTEGER_4 ret_length __attribute__((unused)), |
const gfc_array_char *vector, const gfc_array_l1 *mask, |
const gfc_array_char *field, GFC_INTEGER_4 vector_length, |
GFC_INTEGER_4 field_length __attribute__((unused))) |
{ |
|
if (unlikely(compile_options.bounds_check)) |
unpack_bounds (ret, vector, mask, field); |
|
unpack_internal (ret, vector, mask, field, |
vector_length * sizeof (gfc_char4_t)); |
} |
|
|
extern void unpack0 (gfc_array_char *, const gfc_array_char *, |
const gfc_array_l1 *, char *); |
export_proto(unpack0); |
|
void |
unpack0 (gfc_array_char *ret, const gfc_array_char *vector, |
const gfc_array_l1 *mask, char *field) |
{ |
gfc_array_char tmp; |
|
index_type type_size; |
|
if (unlikely(compile_options.bounds_check)) |
unpack_bounds (ret, vector, mask, NULL); |
|
type_size = GFC_DTYPE_TYPE_SIZE (vector); |
|
switch (type_size) |
{ |
case GFC_DTYPE_LOGICAL_1: |
case GFC_DTYPE_INTEGER_1: |
case GFC_DTYPE_DERIVED_1: |
unpack0_i1 ((gfc_array_i1 *) ret, (gfc_array_i1 *) vector, |
mask, (GFC_INTEGER_1 *) field); |
return; |
|
case GFC_DTYPE_LOGICAL_2: |
case GFC_DTYPE_INTEGER_2: |
unpack0_i2 ((gfc_array_i2 *) ret, (gfc_array_i2 *) vector, |
mask, (GFC_INTEGER_2 *) field); |
return; |
|
case GFC_DTYPE_LOGICAL_4: |
case GFC_DTYPE_INTEGER_4: |
unpack0_i4 ((gfc_array_i4 *) ret, (gfc_array_i4 *) vector, |
mask, (GFC_INTEGER_4 *) field); |
return; |
|
case GFC_DTYPE_LOGICAL_8: |
case GFC_DTYPE_INTEGER_8: |
unpack0_i8 ((gfc_array_i8 *) ret, (gfc_array_i8 *) vector, |
mask, (GFC_INTEGER_8 *) field); |
return; |
|
#ifdef HAVE_GFC_INTEGER_16 |
case GFC_DTYPE_LOGICAL_16: |
case GFC_DTYPE_INTEGER_16: |
unpack0_i16 ((gfc_array_i16 *) ret, (gfc_array_i16 *) vector, |
mask, (GFC_INTEGER_16 *) field); |
return; |
#endif |
|
case GFC_DTYPE_REAL_4: |
unpack0_r4 ((gfc_array_r4 *) ret, (gfc_array_r4 *) vector, |
mask, (GFC_REAL_4 *) field); |
return; |
|
case GFC_DTYPE_REAL_8: |
unpack0_r8 ((gfc_array_r8 *) ret, (gfc_array_r8*) vector, |
mask, (GFC_REAL_8 *) field); |
return; |
|
/* FIXME: This here is a hack, which will have to be removed when |
the array descriptor is reworked. Currently, we don't store the |
kind value for the type, but only the size. Because on targets with |
__float128, we have sizeof(logn double) == sizeof(__float128), |
we cannot discriminate here and have to fall back to the generic |
handling (which is suboptimal). */ |
#if !defined(GFC_REAL_16_IS_FLOAT128) |
# ifdef HAVE_GFC_REAL_10 |
case GFC_DTYPE_REAL_10: |
unpack0_r10 ((gfc_array_r10 *) ret, (gfc_array_r10 *) vector, |
mask, (GFC_REAL_10 *) field); |
return; |
# endif |
|
# ifdef HAVE_GFC_REAL_16 |
case GFC_DTYPE_REAL_16: |
unpack0_r16 ((gfc_array_r16 *) ret, (gfc_array_r16 *) vector, |
mask, (GFC_REAL_16 *) field); |
return; |
# endif |
#endif |
|
case GFC_DTYPE_COMPLEX_4: |
unpack0_c4 ((gfc_array_c4 *) ret, (gfc_array_c4 *) vector, |
mask, (GFC_COMPLEX_4 *) field); |
return; |
|
case GFC_DTYPE_COMPLEX_8: |
unpack0_c8 ((gfc_array_c8 *) ret, (gfc_array_c8 *) vector, |
mask, (GFC_COMPLEX_8 *) field); |
return; |
|
/* FIXME: This here is a hack, which will have to be removed when |
the array descriptor is reworked. Currently, we don't store the |
kind value for the type, but only the size. Because on targets with |
__float128, we have sizeof(logn double) == sizeof(__float128), |
we cannot discriminate here and have to fall back to the generic |
handling (which is suboptimal). */ |
#if !defined(GFC_REAL_16_IS_FLOAT128) |
# ifdef HAVE_GFC_COMPLEX_10 |
case GFC_DTYPE_COMPLEX_10: |
unpack0_c10 ((gfc_array_c10 *) ret, (gfc_array_c10 *) vector, |
mask, (GFC_COMPLEX_10 *) field); |
return; |
# endif |
|
# ifdef HAVE_GFC_COMPLEX_16 |
case GFC_DTYPE_COMPLEX_16: |
unpack0_c16 ((gfc_array_c16 *) ret, (gfc_array_c16 *) vector, |
mask, (GFC_COMPLEX_16 *) field); |
return; |
# endif |
#endif |
|
case GFC_DTYPE_DERIVED_2: |
if (GFC_UNALIGNED_2(ret->data) || GFC_UNALIGNED_2(vector->data) |
|| GFC_UNALIGNED_2(field)) |
break; |
else |
{ |
unpack0_i2 ((gfc_array_i2 *) ret, (gfc_array_i2 *) vector, |
mask, (GFC_INTEGER_2 *) field); |
return; |
} |
|
case GFC_DTYPE_DERIVED_4: |
if (GFC_UNALIGNED_4(ret->data) || GFC_UNALIGNED_4(vector->data) |
|| GFC_UNALIGNED_4(field)) |
break; |
else |
{ |
unpack0_i4 ((gfc_array_i4 *) ret, (gfc_array_i4 *) vector, |
mask, (GFC_INTEGER_4 *) field); |
return; |
} |
|
case GFC_DTYPE_DERIVED_8: |
if (GFC_UNALIGNED_8(ret->data) || GFC_UNALIGNED_8(vector->data) |
|| GFC_UNALIGNED_8(field)) |
break; |
else |
{ |
unpack0_i8 ((gfc_array_i8 *) ret, (gfc_array_i8 *) vector, |
mask, (GFC_INTEGER_8 *) field); |
return; |
} |
|
#ifdef HAVE_GFC_INTEGER_16 |
case GFC_DTYPE_DERIVED_16: |
if (GFC_UNALIGNED_16(ret->data) || GFC_UNALIGNED_16(vector->data) |
|| GFC_UNALIGNED_16(field)) |
break; |
else |
{ |
unpack0_i16 ((gfc_array_i16 *) ret, (gfc_array_i16 *) vector, |
mask, (GFC_INTEGER_16 *) field); |
return; |
} |
#endif |
|
} |
|
memset (&tmp, 0, sizeof (tmp)); |
tmp.dtype = 0; |
tmp.data = field; |
unpack_internal (ret, vector, mask, &tmp, GFC_DESCRIPTOR_SIZE (vector)); |
} |
|
|
extern void unpack0_char (gfc_array_char *, GFC_INTEGER_4, |
const gfc_array_char *, const gfc_array_l1 *, |
char *, GFC_INTEGER_4, GFC_INTEGER_4); |
export_proto(unpack0_char); |
|
void |
unpack0_char (gfc_array_char *ret, |
GFC_INTEGER_4 ret_length __attribute__((unused)), |
const gfc_array_char *vector, const gfc_array_l1 *mask, |
char *field, GFC_INTEGER_4 vector_length, |
GFC_INTEGER_4 field_length __attribute__((unused))) |
{ |
gfc_array_char tmp; |
|
if (unlikely(compile_options.bounds_check)) |
unpack_bounds (ret, vector, mask, NULL); |
|
memset (&tmp, 0, sizeof (tmp)); |
tmp.dtype = 0; |
tmp.data = field; |
unpack_internal (ret, vector, mask, &tmp, vector_length); |
} |
|
|
extern void unpack0_char4 (gfc_array_char *, GFC_INTEGER_4, |
const gfc_array_char *, const gfc_array_l1 *, |
char *, GFC_INTEGER_4, GFC_INTEGER_4); |
export_proto(unpack0_char4); |
|
void |
unpack0_char4 (gfc_array_char *ret, |
GFC_INTEGER_4 ret_length __attribute__((unused)), |
const gfc_array_char *vector, const gfc_array_l1 *mask, |
char *field, GFC_INTEGER_4 vector_length, |
GFC_INTEGER_4 field_length __attribute__((unused))) |
{ |
gfc_array_char tmp; |
|
if (unlikely(compile_options.bounds_check)) |
unpack_bounds (ret, vector, mask, NULL); |
|
memset (&tmp, 0, sizeof (tmp)); |
tmp.dtype = 0; |
tmp.data = field; |
unpack_internal (ret, vector, mask, &tmp, |
vector_length * sizeof (gfc_char4_t)); |
} |
/associated.c
0,0 → 1,58
/* Implementation of the ASSOCIATED intrinsic |
Copyright 2003, 2009 Free Software Foundation, Inc. |
Contributed by kejia Zhao (CCRG) <kejia_zh@yahoo.com.cn> |
|
This file is part of the GNU Fortran 95 runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
|
extern int associated (const gfc_array_void *, const gfc_array_void *); |
export_proto(associated); |
|
int |
associated (const gfc_array_void *pointer, const gfc_array_void *target) |
{ |
int n, rank; |
|
if (GFC_DESCRIPTOR_DATA (pointer) == NULL) |
return 0; |
if (GFC_DESCRIPTOR_DATA (pointer) != GFC_DESCRIPTOR_DATA (target)) |
return 0; |
if (GFC_DESCRIPTOR_DTYPE (pointer) != GFC_DESCRIPTOR_DTYPE (target)) |
return 0; |
|
rank = GFC_DESCRIPTOR_RANK (pointer); |
for (n = 0; n < rank; n++) |
{ |
long extent; |
extent = GFC_DESCRIPTOR_EXTENT(pointer,n); |
|
if (extent != GFC_DESCRIPTOR_EXTENT(target,n)) |
return 0; |
if (GFC_DESCRIPTOR_STRIDE(pointer,n) != GFC_DESCRIPTOR_STRIDE(target,n) && extent != 1) |
return 0; |
if (extent <= 0) |
return 0; |
} |
|
return 1; |
} |
/eoshift0.c
0,0 → 1,299
/* Generic implementation of the EOSHIFT intrinsic |
Copyright 2002, 2005, 2007, 2009 Free Software Foundation, Inc. |
Contributed by Paul Brook <paul@nowt.org> |
|
This file is part of the GNU Fortran 95 runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
#include <stdlib.h> |
#include <assert.h> |
#include <string.h> |
|
/* TODO: make this work for large shifts when |
sizeof(int) < sizeof (index_type). */ |
|
static void |
eoshift0 (gfc_array_char * ret, const gfc_array_char * array, |
int shift, const char * pbound, int which, index_type size, |
const char *filler, index_type filler_len) |
{ |
/* r.* indicates the return array. */ |
index_type rstride[GFC_MAX_DIMENSIONS]; |
index_type rstride0; |
index_type roffset; |
char * restrict rptr; |
char *dest; |
/* s.* indicates the source array. */ |
index_type sstride[GFC_MAX_DIMENSIONS]; |
index_type sstride0; |
index_type soffset; |
const char *sptr; |
const char *src; |
|
index_type count[GFC_MAX_DIMENSIONS]; |
index_type extent[GFC_MAX_DIMENSIONS]; |
index_type dim; |
index_type len; |
index_type n; |
index_type arraysize; |
|
/* The compiler cannot figure out that these are set, initialize |
them to avoid warnings. */ |
len = 0; |
soffset = 0; |
roffset = 0; |
|
arraysize = size0 ((array_t *) array); |
|
if (ret->data == NULL) |
{ |
int i; |
|
ret->offset = 0; |
ret->dtype = array->dtype; |
for (i = 0; i < GFC_DESCRIPTOR_RANK (array); i++) |
{ |
index_type ub, str; |
|
ub = GFC_DESCRIPTOR_EXTENT(array,i) - 1; |
|
if (i == 0) |
str = 1; |
else |
str = GFC_DESCRIPTOR_EXTENT(ret,i-1) |
* GFC_DESCRIPTOR_STRIDE(ret,i-1); |
|
GFC_DIMENSION_SET(ret->dim[i], 0, ub, str); |
|
} |
|
/* internal_malloc_size allocates a single byte for zero size. */ |
ret->data = internal_malloc_size (size * arraysize); |
} |
else if (unlikely (compile_options.bounds_check)) |
{ |
bounds_equal_extents ((array_t *) ret, (array_t *) array, |
"return value", "EOSHIFT"); |
} |
|
if (arraysize == 0) |
return; |
|
which = which - 1; |
|
extent[0] = 1; |
count[0] = 0; |
sstride[0] = -1; |
rstride[0] = -1; |
n = 0; |
for (dim = 0; dim < GFC_DESCRIPTOR_RANK (array); dim++) |
{ |
if (dim == which) |
{ |
roffset = GFC_DESCRIPTOR_STRIDE_BYTES(ret,dim); |
if (roffset == 0) |
roffset = size; |
soffset = GFC_DESCRIPTOR_STRIDE_BYTES(array,dim); |
if (soffset == 0) |
soffset = size; |
len = GFC_DESCRIPTOR_EXTENT(array,dim); |
} |
else |
{ |
count[n] = 0; |
extent[n] = GFC_DESCRIPTOR_EXTENT(array,dim); |
rstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(ret,dim); |
sstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(array,dim); |
n++; |
} |
} |
if (sstride[0] == 0) |
sstride[0] = size; |
if (rstride[0] == 0) |
rstride[0] = size; |
|
dim = GFC_DESCRIPTOR_RANK (array); |
rstride0 = rstride[0]; |
sstride0 = sstride[0]; |
rptr = ret->data; |
sptr = array->data; |
|
if ((shift >= 0 ? shift : -shift) > len) |
{ |
shift = len; |
len = 0; |
} |
else |
{ |
if (shift > 0) |
len = len - shift; |
else |
len = len + shift; |
} |
|
while (rptr) |
{ |
/* Do the shift for this dimension. */ |
if (shift > 0) |
{ |
src = &sptr[shift * soffset]; |
dest = rptr; |
} |
else |
{ |
src = sptr; |
dest = &rptr[-shift * roffset]; |
} |
for (n = 0; n < len; n++) |
{ |
memcpy (dest, src, size); |
dest += roffset; |
src += soffset; |
} |
if (shift >= 0) |
{ |
n = shift; |
} |
else |
{ |
dest = rptr; |
n = -shift; |
} |
|
if (pbound) |
while (n--) |
{ |
memcpy (dest, pbound, size); |
dest += roffset; |
} |
else |
while (n--) |
{ |
index_type i; |
|
if (filler_len == 1) |
memset (dest, filler[0], size); |
else |
for (i = 0; i < size ; i += filler_len) |
memcpy (&dest[i], filler, filler_len); |
|
dest += roffset; |
} |
|
/* Advance to the next section. */ |
rptr += rstride0; |
sptr += sstride0; |
count[0]++; |
n = 0; |
while (count[n] == extent[n]) |
{ |
/* When we get to the end of a dimension, reset it and increment |
the next dimension. */ |
count[n] = 0; |
/* We could precalculate these products, but this is a less |
frequently used path so probably not worth it. */ |
rptr -= rstride[n] * extent[n]; |
sptr -= sstride[n] * extent[n]; |
n++; |
if (n >= dim - 1) |
{ |
/* Break out of the loop. */ |
rptr = NULL; |
break; |
} |
else |
{ |
count[n]++; |
rptr += rstride[n]; |
sptr += sstride[n]; |
} |
} |
} |
} |
|
|
#define DEFINE_EOSHIFT(N) \ |
extern void eoshift0_##N (gfc_array_char *, const gfc_array_char *, \ |
const GFC_INTEGER_##N *, const char *, \ |
const GFC_INTEGER_##N *); \ |
export_proto(eoshift0_##N); \ |
\ |
void \ |
eoshift0_##N (gfc_array_char *ret, const gfc_array_char *array, \ |
const GFC_INTEGER_##N *pshift, const char *pbound, \ |
const GFC_INTEGER_##N *pdim) \ |
{ \ |
eoshift0 (ret, array, *pshift, pbound, pdim ? *pdim : 1, \ |
GFC_DESCRIPTOR_SIZE (array), "\0", 1); \ |
} \ |
\ |
extern void eoshift0_##N##_char (gfc_array_char *, GFC_INTEGER_4, \ |
const gfc_array_char *, \ |
const GFC_INTEGER_##N *, const char *, \ |
const GFC_INTEGER_##N *, GFC_INTEGER_4, \ |
GFC_INTEGER_4); \ |
export_proto(eoshift0_##N##_char); \ |
\ |
void \ |
eoshift0_##N##_char (gfc_array_char *ret, \ |
GFC_INTEGER_4 ret_length __attribute__((unused)), \ |
const gfc_array_char *array, \ |
const GFC_INTEGER_##N *pshift, \ |
const char *pbound, \ |
const GFC_INTEGER_##N *pdim, \ |
GFC_INTEGER_4 array_length, \ |
GFC_INTEGER_4 bound_length __attribute__((unused))) \ |
{ \ |
eoshift0 (ret, array, *pshift, pbound, pdim ? *pdim : 1, \ |
array_length, " ", 1); \ |
} \ |
\ |
extern void eoshift0_##N##_char4 (gfc_array_char *, GFC_INTEGER_4, \ |
const gfc_array_char *, \ |
const GFC_INTEGER_##N *, const char *, \ |
const GFC_INTEGER_##N *, GFC_INTEGER_4, \ |
GFC_INTEGER_4); \ |
export_proto(eoshift0_##N##_char4); \ |
\ |
void \ |
eoshift0_##N##_char4 (gfc_array_char *ret, \ |
GFC_INTEGER_4 ret_length __attribute__((unused)), \ |
const gfc_array_char *array, \ |
const GFC_INTEGER_##N *pshift, \ |
const char *pbound, \ |
const GFC_INTEGER_##N *pdim, \ |
GFC_INTEGER_4 array_length, \ |
GFC_INTEGER_4 bound_length __attribute__((unused))) \ |
{ \ |
static const gfc_char4_t space = (unsigned char) ' '; \ |
eoshift0 (ret, array, *pshift, pbound, pdim ? *pdim : 1, \ |
array_length * sizeof (gfc_char4_t), (const char *) &space, \ |
sizeof (gfc_char4_t)); \ |
} |
|
DEFINE_EOSHIFT (1); |
DEFINE_EOSHIFT (2); |
DEFINE_EOSHIFT (4); |
DEFINE_EOSHIFT (8); |
#ifdef HAVE_GFC_INTEGER_16 |
DEFINE_EOSHIFT (16); |
#endif |
/reshape_generic.c
0,0 → 1,388
/* Generic implementation of the RESHAPE intrinsic |
Copyright 2002, 2006, 2007, 2009 Free Software Foundation, Inc. |
Contributed by Paul Brook <paul@nowt.org> |
|
This file is part of the GNU Fortran 95 runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Ligbfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
#include <stdlib.h> |
#include <string.h> |
#include <assert.h> |
|
typedef GFC_ARRAY_DESCRIPTOR(1, index_type) shape_type; |
typedef GFC_ARRAY_DESCRIPTOR(GFC_MAX_DIMENSIONS, char) parray; |
|
static void |
reshape_internal (parray *ret, parray *source, shape_type *shape, |
parray *pad, shape_type *order, index_type size) |
{ |
/* r.* indicates the return array. */ |
index_type rcount[GFC_MAX_DIMENSIONS]; |
index_type rextent[GFC_MAX_DIMENSIONS]; |
index_type rstride[GFC_MAX_DIMENSIONS]; |
index_type rstride0; |
index_type rdim; |
index_type rsize; |
index_type rs; |
index_type rex; |
char * restrict rptr; |
/* s.* indicates the source array. */ |
index_type scount[GFC_MAX_DIMENSIONS]; |
index_type sextent[GFC_MAX_DIMENSIONS]; |
index_type sstride[GFC_MAX_DIMENSIONS]; |
index_type sstride0; |
index_type sdim; |
index_type ssize; |
const char *sptr; |
/* p.* indicates the pad array. */ |
index_type pcount[GFC_MAX_DIMENSIONS]; |
index_type pextent[GFC_MAX_DIMENSIONS]; |
index_type pstride[GFC_MAX_DIMENSIONS]; |
index_type pdim; |
index_type psize; |
const char *pptr; |
|
const char *src; |
int n; |
int dim; |
int sempty, pempty, shape_empty; |
index_type shape_data[GFC_MAX_DIMENSIONS]; |
|
rdim = GFC_DESCRIPTOR_EXTENT(shape,0); |
if (rdim != GFC_DESCRIPTOR_RANK(ret)) |
runtime_error("rank of return array incorrect in RESHAPE intrinsic"); |
|
shape_empty = 0; |
|
for (n = 0; n < rdim; n++) |
{ |
shape_data[n] = shape->data[n * GFC_DESCRIPTOR_STRIDE(shape,0)]; |
if (shape_data[n] <= 0) |
{ |
shape_data[n] = 0; |
shape_empty = 1; |
} |
} |
|
if (ret->data == NULL) |
{ |
index_type alloc_size; |
|
rs = 1; |
for (n = 0; n < rdim; n++) |
{ |
rex = shape_data[n]; |
|
GFC_DIMENSION_SET(ret->dim[n],0,rex - 1,rs); |
|
rs *= rex; |
} |
ret->offset = 0; |
|
if (unlikely (rs < 1)) |
alloc_size = 1; |
else |
alloc_size = rs * size; |
|
ret->data = internal_malloc_size (alloc_size); |
|
ret->dtype = (source->dtype & ~GFC_DTYPE_RANK_MASK) | rdim; |
} |
|
if (shape_empty) |
return; |
|
if (pad) |
{ |
pdim = GFC_DESCRIPTOR_RANK (pad); |
psize = 1; |
pempty = 0; |
for (n = 0; n < pdim; n++) |
{ |
pcount[n] = 0; |
pstride[n] = GFC_DESCRIPTOR_STRIDE(pad,n); |
pextent[n] = GFC_DESCRIPTOR_EXTENT(pad,n); |
if (pextent[n] <= 0) |
{ |
pempty = 1; |
pextent[n] = 0; |
} |
|
if (psize == pstride[n]) |
psize *= pextent[n]; |
else |
psize = 0; |
} |
pptr = pad->data; |
} |
else |
{ |
pdim = 0; |
psize = 1; |
pempty = 1; |
pptr = NULL; |
} |
|
if (unlikely (compile_options.bounds_check)) |
{ |
index_type ret_extent, source_extent; |
|
rs = 1; |
for (n = 0; n < rdim; n++) |
{ |
rs *= shape_data[n]; |
ret_extent = GFC_DESCRIPTOR_EXTENT(ret,n); |
if (ret_extent != shape_data[n]) |
runtime_error("Incorrect extent in return value of RESHAPE" |
" intrinsic in dimension %ld: is %ld," |
" should be %ld", (long int) n+1, |
(long int) ret_extent, (long int) shape_data[n]); |
} |
|
source_extent = 1; |
sdim = GFC_DESCRIPTOR_RANK (source); |
for (n = 0; n < sdim; n++) |
{ |
index_type se; |
se = GFC_DESCRIPTOR_EXTENT(source,n); |
source_extent *= se > 0 ? se : 0; |
} |
|
if (rs > source_extent && (!pad || pempty)) |
runtime_error("Incorrect size in SOURCE argument to RESHAPE" |
" intrinsic: is %ld, should be %ld", |
(long int) source_extent, (long int) rs); |
|
if (order) |
{ |
int seen[GFC_MAX_DIMENSIONS]; |
index_type v; |
|
for (n = 0; n < rdim; n++) |
seen[n] = 0; |
|
for (n = 0; n < rdim; n++) |
{ |
v = order->data[n * GFC_DESCRIPTOR_STRIDE(order,0)] - 1; |
|
if (v < 0 || v >= rdim) |
runtime_error("Value %ld out of range in ORDER argument" |
" to RESHAPE intrinsic", (long int) v + 1); |
|
if (seen[v] != 0) |
runtime_error("Duplicate value %ld in ORDER argument to" |
" RESHAPE intrinsic", (long int) v + 1); |
|
seen[v] = 1; |
} |
} |
} |
|
rsize = 1; |
for (n = 0; n < rdim; n++) |
{ |
if (order) |
dim = order->data[n * GFC_DESCRIPTOR_STRIDE(order,0)] - 1; |
else |
dim = n; |
|
rcount[n] = 0; |
rstride[n] = GFC_DESCRIPTOR_STRIDE(ret,dim); |
rextent[n] = GFC_DESCRIPTOR_EXTENT(ret,dim); |
|
if (rextent[n] != shape_data[dim]) |
runtime_error ("shape and target do not conform"); |
|
if (rsize == rstride[n]) |
rsize *= rextent[n]; |
else |
rsize = 0; |
if (rextent[n] <= 0) |
return; |
} |
|
sdim = GFC_DESCRIPTOR_RANK (source); |
ssize = 1; |
sempty = 0; |
for (n = 0; n < sdim; n++) |
{ |
scount[n] = 0; |
sstride[n] = GFC_DESCRIPTOR_STRIDE(source,n); |
sextent[n] = GFC_DESCRIPTOR_EXTENT(source,n); |
if (sextent[n] <= 0) |
{ |
sempty = 1; |
sextent[n] = 0; |
} |
|
if (ssize == sstride[n]) |
ssize *= sextent[n]; |
else |
ssize = 0; |
} |
|
if (rsize != 0 && ssize != 0 && psize != 0) |
{ |
rsize *= size; |
ssize *= size; |
psize *= size; |
reshape_packed (ret->data, rsize, source->data, ssize, |
pad ? pad->data : NULL, psize); |
return; |
} |
rptr = ret->data; |
src = sptr = source->data; |
rstride0 = rstride[0] * size; |
sstride0 = sstride[0] * size; |
|
if (sempty && pempty) |
abort (); |
|
if (sempty) |
{ |
/* Pretend we are using the pad array the first time around, too. */ |
src = pptr; |
sptr = pptr; |
sdim = pdim; |
for (dim = 0; dim < pdim; dim++) |
{ |
scount[dim] = pcount[dim]; |
sextent[dim] = pextent[dim]; |
sstride[dim] = pstride[dim]; |
sstride0 = pstride[0] * size; |
} |
} |
|
while (rptr) |
{ |
/* Select between the source and pad arrays. */ |
memcpy(rptr, src, size); |
/* Advance to the next element. */ |
rptr += rstride0; |
src += sstride0; |
rcount[0]++; |
scount[0]++; |
|
/* Advance to the next destination element. */ |
n = 0; |
while (rcount[n] == rextent[n]) |
{ |
/* When we get to the end of a dimension, reset it and increment |
the next dimension. */ |
rcount[n] = 0; |
/* We could precalculate these products, but this is a less |
frequently used path so probably not worth it. */ |
rptr -= rstride[n] * rextent[n] * size; |
n++; |
if (n == rdim) |
{ |
/* Break out of the loop. */ |
rptr = NULL; |
break; |
} |
else |
{ |
rcount[n]++; |
rptr += rstride[n] * size; |
} |
} |
|
/* Advance to the next source element. */ |
n = 0; |
while (scount[n] == sextent[n]) |
{ |
/* When we get to the end of a dimension, reset it and increment |
the next dimension. */ |
scount[n] = 0; |
/* We could precalculate these products, but this is a less |
frequently used path so probably not worth it. */ |
src -= sstride[n] * sextent[n] * size; |
n++; |
if (n == sdim) |
{ |
if (sptr && pad) |
{ |
/* Switch to the pad array. */ |
sptr = NULL; |
sdim = pdim; |
for (dim = 0; dim < pdim; dim++) |
{ |
scount[dim] = pcount[dim]; |
sextent[dim] = pextent[dim]; |
sstride[dim] = pstride[dim]; |
sstride0 = sstride[0] * size; |
} |
} |
/* We now start again from the beginning of the pad array. */ |
src = pptr; |
break; |
} |
else |
{ |
scount[n]++; |
src += sstride[n] * size; |
} |
} |
} |
} |
|
extern void reshape (parray *, parray *, shape_type *, parray *, shape_type *); |
export_proto(reshape); |
|
void |
reshape (parray *ret, parray *source, shape_type *shape, parray *pad, |
shape_type *order) |
{ |
reshape_internal (ret, source, shape, pad, order, |
GFC_DESCRIPTOR_SIZE (source)); |
} |
|
|
extern void reshape_char (parray *, gfc_charlen_type, parray *, shape_type *, |
parray *, shape_type *, gfc_charlen_type, |
gfc_charlen_type); |
export_proto(reshape_char); |
|
void |
reshape_char (parray *ret, gfc_charlen_type ret_length __attribute__((unused)), |
parray *source, shape_type *shape, parray *pad, |
shape_type *order, gfc_charlen_type source_length, |
gfc_charlen_type pad_length __attribute__((unused))) |
{ |
reshape_internal (ret, source, shape, pad, order, source_length); |
} |
|
|
extern void reshape_char4 (parray *, gfc_charlen_type, parray *, shape_type *, |
parray *, shape_type *, gfc_charlen_type, |
gfc_charlen_type); |
export_proto(reshape_char4); |
|
void |
reshape_char4 (parray *ret, gfc_charlen_type ret_length __attribute__((unused)), |
parray *source, shape_type *shape, parray *pad, |
shape_type *order, gfc_charlen_type source_length, |
gfc_charlen_type pad_length __attribute__((unused))) |
{ |
reshape_internal (ret, source, shape, pad, order, |
source_length * sizeof (gfc_char4_t)); |
} |
/eoshift2.c
0,0 → 1,324
/* Generic implementation of the EOSHIFT intrinsic |
Copyright 2002, 2005, 2007, 2009 Free Software Foundation, Inc. |
Contributed by Paul Brook <paul@nowt.org> |
|
This file is part of the GNU Fortran 95 runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Ligbfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
#include <stdlib.h> |
#include <assert.h> |
#include <string.h> |
|
/* TODO: make this work for large shifts when |
sizeof(int) < sizeof (index_type). */ |
|
static void |
eoshift2 (gfc_array_char *ret, const gfc_array_char *array, |
int shift, const gfc_array_char *bound, int which, |
const char *filler, index_type filler_len) |
{ |
/* r.* indicates the return array. */ |
index_type rstride[GFC_MAX_DIMENSIONS]; |
index_type rstride0; |
index_type roffset; |
char * restrict rptr; |
char *dest; |
/* s.* indicates the source array. */ |
index_type sstride[GFC_MAX_DIMENSIONS]; |
index_type sstride0; |
index_type soffset; |
const char *sptr; |
const char *src; |
/* b.* indicates the bound array. */ |
index_type bstride[GFC_MAX_DIMENSIONS]; |
index_type bstride0; |
const char *bptr; |
|
index_type count[GFC_MAX_DIMENSIONS]; |
index_type extent[GFC_MAX_DIMENSIONS]; |
index_type dim; |
index_type len; |
index_type n; |
index_type arraysize; |
index_type size; |
|
/* The compiler cannot figure out that these are set, initialize |
them to avoid warnings. */ |
len = 0; |
soffset = 0; |
roffset = 0; |
|
size = GFC_DESCRIPTOR_SIZE (array); |
|
arraysize = size0 ((array_t *) array); |
|
if (ret->data == NULL) |
{ |
int i; |
|
ret->offset = 0; |
ret->dtype = array->dtype; |
for (i = 0; i < GFC_DESCRIPTOR_RANK (array); i++) |
{ |
index_type ub, str; |
|
ub = GFC_DESCRIPTOR_EXTENT(array,i) - 1; |
|
if (i == 0) |
str = 1; |
else |
str = GFC_DESCRIPTOR_EXTENT(ret,i-1) |
* GFC_DESCRIPTOR_STRIDE(ret,i-1); |
|
GFC_DIMENSION_SET(ret->dim[i], 0, ub, str); |
|
/* internal_malloc_size allocates a single byte for zero size. */ |
ret->data = internal_malloc_size (size * arraysize); |
|
} |
} |
else if (unlikely (compile_options.bounds_check)) |
{ |
bounds_equal_extents ((array_t *) ret, (array_t *) array, |
"return value", "EOSHIFT"); |
} |
|
if (arraysize == 0) |
return; |
|
which = which - 1; |
|
extent[0] = 1; |
count[0] = 0; |
sstride[0] = -1; |
rstride[0] = -1; |
bstride[0] = -1; |
n = 0; |
for (dim = 0; dim < GFC_DESCRIPTOR_RANK (array); dim++) |
{ |
if (dim == which) |
{ |
roffset = GFC_DESCRIPTOR_STRIDE_BYTES(ret,dim); |
if (roffset == 0) |
roffset = size; |
soffset = GFC_DESCRIPTOR_STRIDE_BYTES(array,dim); |
if (soffset == 0) |
soffset = size; |
len = GFC_DESCRIPTOR_EXTENT(array,dim); |
} |
else |
{ |
count[n] = 0; |
extent[n] = GFC_DESCRIPTOR_EXTENT(array,dim); |
rstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(ret,dim); |
sstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(array,dim); |
if (bound) |
bstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(bound,n); |
else |
bstride[n] = 0; |
n++; |
} |
} |
if (sstride[0] == 0) |
sstride[0] = size; |
if (rstride[0] == 0) |
rstride[0] = size; |
if (bound && bstride[0] == 0) |
bstride[0] = size; |
|
dim = GFC_DESCRIPTOR_RANK (array); |
rstride0 = rstride[0]; |
sstride0 = sstride[0]; |
bstride0 = bstride[0]; |
rptr = ret->data; |
sptr = array->data; |
|
if ((shift >= 0 ? shift : -shift ) > len) |
{ |
shift = len; |
len = 0; |
} |
else |
{ |
if (shift > 0) |
len = len - shift; |
else |
len = len + shift; |
} |
|
if (bound) |
bptr = bound->data; |
else |
bptr = NULL; |
|
while (rptr) |
{ |
/* Do the shift for this dimension. */ |
if (shift > 0) |
{ |
src = &sptr[shift * soffset]; |
dest = rptr; |
} |
else |
{ |
src = sptr; |
dest = &rptr[-shift * roffset]; |
} |
for (n = 0; n < len; n++) |
{ |
memcpy (dest, src, size); |
dest += roffset; |
src += soffset; |
} |
if (shift >= 0) |
{ |
n = shift; |
} |
else |
{ |
dest = rptr; |
n = -shift; |
} |
|
if (bptr) |
while (n--) |
{ |
memcpy (dest, bptr, size); |
dest += roffset; |
} |
else |
while (n--) |
{ |
index_type i; |
|
if (filler_len == 1) |
memset (dest, filler[0], size); |
else |
for (i = 0; i < size ; i += filler_len) |
memcpy (&dest[i], filler, filler_len); |
|
dest += roffset; |
} |
|
/* Advance to the next section. */ |
rptr += rstride0; |
sptr += sstride0; |
bptr += bstride0; |
count[0]++; |
n = 0; |
while (count[n] == extent[n]) |
{ |
/* When we get to the end of a dimension, reset it and increment |
the next dimension. */ |
count[n] = 0; |
/* We could precalculate these products, but this is a less |
frequently used path so probably not worth it. */ |
rptr -= rstride[n] * extent[n]; |
sptr -= sstride[n] * extent[n]; |
bptr -= bstride[n] * extent[n]; |
n++; |
if (n >= dim - 1) |
{ |
/* Break out of the loop. */ |
rptr = NULL; |
break; |
} |
else |
{ |
count[n]++; |
rptr += rstride[n]; |
sptr += sstride[n]; |
bptr += bstride[n]; |
} |
} |
} |
} |
|
|
#define DEFINE_EOSHIFT(N) \ |
extern void eoshift2_##N (gfc_array_char *, const gfc_array_char *, \ |
const GFC_INTEGER_##N *, const gfc_array_char *, \ |
const GFC_INTEGER_##N *); \ |
export_proto(eoshift2_##N); \ |
\ |
void \ |
eoshift2_##N (gfc_array_char *ret, const gfc_array_char *array, \ |
const GFC_INTEGER_##N *pshift, const gfc_array_char *pbound, \ |
const GFC_INTEGER_##N *pdim) \ |
{ \ |
eoshift2 (ret, array, *pshift, pbound, pdim ? *pdim : 1, \ |
"\0", 1); \ |
} \ |
\ |
extern void eoshift2_##N##_char (gfc_array_char *, GFC_INTEGER_4, \ |
const gfc_array_char *, \ |
const GFC_INTEGER_##N *, \ |
const gfc_array_char *, \ |
const GFC_INTEGER_##N *, \ |
GFC_INTEGER_4, GFC_INTEGER_4); \ |
export_proto(eoshift2_##N##_char); \ |
\ |
void \ |
eoshift2_##N##_char (gfc_array_char *ret, \ |
GFC_INTEGER_4 ret_length __attribute__((unused)), \ |
const gfc_array_char *array, \ |
const GFC_INTEGER_##N *pshift, \ |
const gfc_array_char *pbound, \ |
const GFC_INTEGER_##N *pdim, \ |
GFC_INTEGER_4 array_length __attribute__((unused)), \ |
GFC_INTEGER_4 bound_length __attribute__((unused))) \ |
{ \ |
eoshift2 (ret, array, *pshift, pbound, pdim ? *pdim : 1, \ |
" ", 1); \ |
} \ |
\ |
extern void eoshift2_##N##_char4 (gfc_array_char *, GFC_INTEGER_4, \ |
const gfc_array_char *, \ |
const GFC_INTEGER_##N *, \ |
const gfc_array_char *, \ |
const GFC_INTEGER_##N *, \ |
GFC_INTEGER_4, GFC_INTEGER_4); \ |
export_proto(eoshift2_##N##_char4); \ |
\ |
void \ |
eoshift2_##N##_char4 (gfc_array_char *ret, \ |
GFC_INTEGER_4 ret_length __attribute__((unused)), \ |
const gfc_array_char *array, \ |
const GFC_INTEGER_##N *pshift, \ |
const gfc_array_char *pbound, \ |
const GFC_INTEGER_##N *pdim, \ |
GFC_INTEGER_4 array_length __attribute__((unused)), \ |
GFC_INTEGER_4 bound_length __attribute__((unused))) \ |
{ \ |
static const gfc_char4_t space = (unsigned char) ' '; \ |
eoshift2 (ret, array, *pshift, pbound, pdim ? *pdim : 1, \ |
(const char *) &space, \ |
sizeof (gfc_char4_t)); \ |
} |
|
DEFINE_EOSHIFT (1); |
DEFINE_EOSHIFT (2); |
DEFINE_EOSHIFT (4); |
DEFINE_EOSHIFT (8); |
#ifdef HAVE_GFC_INTEGER_16 |
DEFINE_EOSHIFT (16); |
#endif |
/time_1.h
0,0 → 1,218
/* Wrappers for platform timing functions. |
Copyright (C) 2003, 2007, 2009, 2011 Free Software Foundation, Inc. |
|
This file is part of the GNU Fortran runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#ifndef LIBGFORTRAN_TIME_H |
#define LIBGFORTRAN_TIME_H |
|
#ifdef HAVE_UNISTD_H |
#include <unistd.h> |
#endif |
|
#include <errno.h> |
|
/* The time related intrinsics (DTIME, ETIME, CPU_TIME) to "compare |
different algorithms on the same computer or discover which parts |
are the most expensive", need a way to get the CPU time with the |
finest resolution possible. We can only be accurate up to |
microseconds. |
|
As usual with UNIX systems, unfortunately no single way is |
available for all systems. */ |
|
#ifdef HAVE_SYS_TIME_H |
#include <sys/time.h> |
#endif |
|
#include <time.h> |
|
#ifdef HAVE_SYS_TYPES_H |
#include <sys/types.h> |
#endif |
|
/* The most accurate way to get the CPU time is getrusage (). */ |
#if defined (HAVE_GETRUSAGE) && defined (HAVE_SYS_RESOURCE_H) |
# include <sys/resource.h> |
#endif /* HAVE_GETRUSAGE && HAVE_SYS_RESOURCE_H */ |
|
/* The most accurate way to get the CPU time is getrusage (). |
If we have times(), that's good enough, too. */ |
#if !defined (HAVE_GETRUSAGE) || !defined (HAVE_SYS_RESOURCE_H) |
/* For times(), we _must_ know the number of clock ticks per second. */ |
# if defined (HAVE_TIMES) && (defined (HZ) || defined (_SC_CLK_TCK) || defined (CLK_TCK)) |
# ifdef HAVE_SYS_PARAM_H |
# include <sys/param.h> |
# endif |
# if defined (HAVE_SYS_TIMES_H) |
# include <sys/times.h> |
# endif |
# ifndef HZ |
# if defined _SC_CLK_TCK |
# define HZ sysconf(_SC_CLK_TCK) |
# else |
# define HZ CLK_TCK |
# endif |
# endif |
# endif /* HAVE_TIMES etc. */ |
#endif /* !HAVE_GETRUSAGE || !HAVE_SYS_RESOURCE_H */ |
|
|
/* If the re-entrant version of localtime is not available, provide a |
fallback implementation. On some targets where the _r version is |
not available, localtime uses thread-local storage so it's |
threadsafe. */ |
|
#ifndef HAVE_LOCALTIME_R |
/* If _POSIX is defined localtime_r gets defined by mingw-w64 headers. */ |
#ifdef localtime_r |
#undef localtime_r |
#endif |
|
static inline struct tm * |
localtime_r (const time_t * timep, struct tm * result) |
{ |
*result = *localtime (timep); |
return result; |
} |
#endif |
|
|
/* Helper function for the actual implementation of the DTIME, ETIME and |
CPU_TIME intrinsics. Returns 0 for success or -1 if no |
CPU time could be computed. */ |
|
#ifdef __MINGW32__ |
|
#define WIN32_LEAN_AND_MEAN |
#include <windows.h> |
|
static inline int |
gf_cputime (long *user_sec, long *user_usec, long *system_sec, long *system_usec) |
{ |
union { |
FILETIME ft; |
unsigned long long ulltime; |
} kernel_time, user_time; |
|
FILETIME unused1, unused2; |
|
/* No support for Win9x. The high order bit of the DWORD |
returned by GetVersion is 0 for NT and higher. */ |
if (GetVersion () >= 0x80000000) |
{ |
*user_sec = *system_sec = 0; |
*user_usec = *system_usec = 0; |
return -1; |
} |
|
/* The FILETIME structs filled in by GetProcessTimes represent |
time in 100 nanosecond units. */ |
GetProcessTimes (GetCurrentProcess (), &unused1, &unused2, |
&kernel_time.ft, &user_time.ft); |
|
*user_sec = user_time.ulltime / 10000000; |
*user_usec = (user_time.ulltime % 10000000) / 10; |
|
*system_sec = kernel_time.ulltime / 10000000; |
*system_usec = (kernel_time.ulltime % 10000000) / 10; |
return 0; |
} |
|
#else |
|
static inline int |
gf_cputime (long *user_sec, long *user_usec, long *system_sec, long *system_usec) |
{ |
#if defined (HAVE_GETRUSAGE) && defined (HAVE_SYS_RESOURCE_H) |
struct rusage usage; |
int err; |
err = getrusage (RUSAGE_SELF, &usage); |
|
*user_sec = usage.ru_utime.tv_sec; |
*user_usec = usage.ru_utime.tv_usec; |
*system_sec = usage.ru_stime.tv_sec; |
*system_usec = usage.ru_stime.tv_usec; |
return err; |
|
#elif defined HAVE_TIMES |
struct tms buf; |
clock_t err; |
err = times (&buf); |
*user_sec = buf.tms_utime / HZ; |
*user_usec = buf.tms_utime % HZ * (1000000. / HZ); |
*system_sec = buf.tms_stime / HZ; |
*system_usec = buf.tms_stime % HZ * (1000000. / HZ); |
if ((err == (clock_t) -1) && errno != 0) |
return -1; |
return 0; |
|
#else |
clock_t c = clock (); |
*user_sec = c / CLOCKS_PER_SEC; |
*user_usec = c % CLOCKS_PER_SEC * (1000000. / CLOCKS_PER_SEC); |
*system_sec = *system_usec = 0; |
if (c == (clock_t) -1) |
return -1; |
return 0; |
|
#endif |
} |
|
#endif |
|
|
/* Realtime clock with microsecond resolution, falling back to less |
precise functions if the target does not support gettimeofday(). |
|
Arguments: |
secs - OUTPUT, seconds |
usecs - OUTPUT, microseconds |
|
The OUTPUT arguments shall represent the number of seconds and |
nanoseconds since the Epoch. |
|
Return value: 0 for success, -1 for error. In case of error, errno |
is set. |
*/ |
static inline int |
gf_gettime (time_t * secs, long * usecs) |
{ |
#ifdef HAVE_GETTIMEOFDAY |
struct timeval tv; |
int err; |
err = gettimeofday (&tv, NULL); |
*secs = tv.tv_sec; |
*usecs = tv.tv_usec; |
return err; |
#else |
time_t t = time (NULL); |
*secs = t; |
*usecs = 0; |
if (t == ((time_t)-1)) |
return -1; |
return 0; |
#endif |
} |
|
|
#endif /* LIBGFORTRAN_TIME_H */ |
/system.c
0,0 → 1,61
/* Implementation of the SYSTEM intrinsic. |
Copyright (C) 2004, 2007, 2009, 2011 Free Software Foundation, Inc. |
Contributed by Tobias Schlüter. |
|
This file is part of the GNU Fortran runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or modify it under |
the terms of the GNU General Public License as published by the Free |
Software Foundation; either version 3, or (at your option) any later |
version. |
|
Libgfortran is distributed in the hope that it will be useful, but WITHOUT |
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
#include <string.h> |
#include <stdlib.h> |
|
extern void system_sub (const char *fcmd, GFC_INTEGER_4 * status, |
gfc_charlen_type cmd_len); |
iexport_proto(system_sub); |
|
void |
system_sub (const char *fcmd, GFC_INTEGER_4 *status, gfc_charlen_type cmd_len) |
{ |
char cmd[cmd_len + 1]; |
int stat; |
|
/* Flush all I/O units before executing the command. */ |
flush_all_units(); |
|
memcpy (cmd, fcmd, cmd_len); |
cmd[cmd_len] = '\0'; |
|
stat = system (cmd); |
if (status) |
*status = stat; |
} |
iexport(system_sub); |
|
extern GFC_INTEGER_4 PREFIX(system) (const char *, gfc_charlen_type); |
export_proto_np(PREFIX(system)); |
|
GFC_INTEGER_4 |
PREFIX(system) (const char *fcmd, gfc_charlen_type cmd_len) |
{ |
GFC_INTEGER_4 stat; |
system_sub (fcmd, &stat, cmd_len); |
return stat; |
} |
/iso_c_binding.c
0,0 → 1,189
/* Implementation of the ISO_C_BINDING library helper functions. |
Copyright (C) 2007, 2009, 2010 Free Software Foundation, Inc. |
Contributed by Christopher Rickett. |
|
This file is part of the GNU Fortran 95 runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
|
/* Implement the functions and subroutines provided by the intrinsic |
iso_c_binding module. */ |
|
#include "libgfortran.h" |
#include "iso_c_binding.h" |
|
#include <stdlib.h> |
|
|
/* Set the fields of a Fortran pointer descriptor to point to the |
given C address. It uses c_f_pointer_u0 for the common |
fields, and will set up the information necessary if this C address |
is to an array (i.e., offset, type, element size). The parameter |
c_ptr_in represents the C address to have Fortran point to. The |
parameter f_ptr_out is the Fortran pointer to associate with the C |
address. The parameter shape is a one-dimensional array of integers |
specifying the upper bound(s) of the array pointed to by the given C |
address, if applicable. The shape parameter is optional in Fortran, |
which will cause it to come in here as NULL. The parameter type is |
the type of the data being pointed to (i.e.,libgfortran.h). The |
elem_size parameter is the size, in bytes, of the data element being |
pointed to. If the address is for an array, then the size needs to |
be the size of a single element (i.e., for an array of doubles, it |
needs to be the number of bytes for the size of one double). */ |
|
void |
ISO_C_BINDING_PREFIX (c_f_pointer) (void *c_ptr_in, |
gfc_array_void *f_ptr_out, |
const array_t *shape, |
int type, int elemSize) |
{ |
if (shape != NULL) |
{ |
f_ptr_out->offset = 0; |
|
/* Set the necessary dtype field for all pointers. */ |
f_ptr_out->dtype = 0; |
|
/* Put in the element size. */ |
f_ptr_out->dtype = f_ptr_out->dtype | (elemSize << GFC_DTYPE_SIZE_SHIFT); |
|
/* Set the data type (e.g., BT_INTEGER). */ |
f_ptr_out->dtype = f_ptr_out->dtype | (type << GFC_DTYPE_TYPE_SHIFT); |
} |
|
/* Use the generic version of c_f_pointer to set common fields. */ |
ISO_C_BINDING_PREFIX (c_f_pointer_u0) (c_ptr_in, f_ptr_out, shape); |
} |
|
|
/* A generic function to set the common fields of all descriptors, no |
matter whether it's to a scalar or an array. Access is via the array |
descrptor macros. Parameter shape is a rank 1 array of integers |
containing the upper bound of each dimension of what f_ptr_out |
points to. The length of this array must be EXACTLY the rank of |
what f_ptr_out points to, as required by the draft (J3/04-007). If |
f_ptr_out points to a scalar, then this parameter will be NULL. */ |
|
void |
ISO_C_BINDING_PREFIX (c_f_pointer_u0) (void *c_ptr_in, |
gfc_array_void *f_ptr_out, |
const array_t *shape) |
{ |
int i = 0; |
int shapeSize = 0; |
|
GFC_DESCRIPTOR_DATA (f_ptr_out) = c_ptr_in; |
|
if (shape != NULL) |
{ |
index_type source_stride, size; |
index_type str = 1; |
char *p; |
|
f_ptr_out->offset = str; |
shapeSize = 0; |
p = shape->data; |
size = GFC_DESCRIPTOR_SIZE(shape); |
|
source_stride = GFC_DESCRIPTOR_STRIDE_BYTES(shape,0); |
|
/* shape's length (rank of the output array) */ |
shapeSize = GFC_DESCRIPTOR_EXTENT(shape,0); |
for (i = 0; i < shapeSize; i++) |
{ |
index_type ub; |
|
/* Have to allow for the SHAPE array to be any valid kind for |
an INTEGER type. */ |
switch (size) |
{ |
#ifdef HAVE_GFC_INTEGER_1 |
case 1: |
ub = *((GFC_INTEGER_1 *) p); |
break; |
#endif |
#ifdef HAVE_GFC_INTEGER_2 |
case 2: |
ub = *((GFC_INTEGER_2 *) p); |
break; |
#endif |
#ifdef HAVE_GFC_INTEGER_4 |
case 4: |
ub = *((GFC_INTEGER_4 *) p); |
break; |
#endif |
#ifdef HAVE_GFC_INTEGER_8 |
case 8: |
ub = *((GFC_INTEGER_8 *) p); |
break; |
#endif |
#ifdef HAVE_GFC_INTEGER_16 |
case 16: |
ub = *((GFC_INTEGER_16 *) p); |
break; |
#endif |
default: |
internal_error (NULL, "c_f_pointer_u0: Invalid size"); |
} |
p += source_stride; |
|
if (i != 0) |
{ |
str = str * GFC_DESCRIPTOR_EXTENT(f_ptr_out,i-1); |
f_ptr_out->offset += str; |
} |
|
/* Lower bound is 1, as specified by the draft. */ |
GFC_DIMENSION_SET(f_ptr_out->dim[i], 1, ub, str); |
} |
|
f_ptr_out->offset *= -1; |
|
/* All we know is the rank, so set it, leaving the rest alone. |
Make NO assumptions about the state of dtype coming in! If we |
shift right by TYPE_SHIFT bits we'll throw away the existing |
rank. Then, shift left by the same number to shift in zeros |
and or with the new rank. */ |
f_ptr_out->dtype = ((f_ptr_out->dtype >> GFC_DTYPE_TYPE_SHIFT) |
<< GFC_DTYPE_TYPE_SHIFT) | shapeSize; |
} |
} |
|
|
/* Sets the descriptor fields for a Fortran pointer to a derived type, |
using c_f_pointer_u0 for the majority of the work. */ |
|
void |
ISO_C_BINDING_PREFIX (c_f_pointer_d0) (void *c_ptr_in, |
gfc_array_void *f_ptr_out, |
const array_t *shape) |
{ |
/* Set the common fields. */ |
ISO_C_BINDING_PREFIX (c_f_pointer_u0) (c_ptr_in, f_ptr_out, shape); |
|
/* Preserve the size and rank bits, but reset the type. */ |
if (shape != NULL) |
{ |
f_ptr_out->dtype = f_ptr_out->dtype & (~GFC_DTYPE_TYPE_MASK); |
f_ptr_out->dtype = f_ptr_out->dtype |
| (BT_DERIVED << GFC_DTYPE_TYPE_SHIFT); |
} |
} |
/env.c
0,0 → 1,195
/* Implementation of the GETENV g77, and |
GET_ENVIRONMENT_VARIABLE F2003, intrinsics. |
Copyright (C) 2004, 2007, 2009 Free Software Foundation, Inc. |
Contributed by Janne Blomqvist. |
|
This file is part of the GNU Fortran 95 runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
#include <stdlib.h> |
#include <string.h> |
|
|
/* GETENV (NAME, VALUE), g77 intrinsic for retrieving the value of |
an environment variable. The name of the variable is specified in |
NAME, and the result is stored into VALUE. */ |
|
void PREFIX(getenv) (char *, char *, gfc_charlen_type, gfc_charlen_type); |
export_proto_np(PREFIX(getenv)); |
|
void |
PREFIX(getenv) (char * name, char * value, gfc_charlen_type name_len, |
gfc_charlen_type value_len) |
{ |
char *name_nt; |
char *res = NULL; |
int res_len; |
|
if (name == NULL || value == NULL) |
runtime_error ("Both arguments to getenv are mandatory."); |
|
if (value_len < 1 || name_len < 1) |
runtime_error ("Zero length string(s) passed to getenv."); |
else |
memset (value, ' ', value_len); /* Blank the string. */ |
|
/* Trim trailing spaces from name. */ |
while (name_len > 0 && name[name_len - 1] == ' ') |
name_len--; |
|
/* Make a null terminated copy of the string. */ |
name_nt = gfc_alloca (name_len + 1); |
memcpy (name_nt, name, name_len); |
name_nt[name_len] = '\0'; |
|
res = getenv(name_nt); |
|
/* If res is NULL, it means that the environment variable didn't |
exist, so just return. */ |
if (res == NULL) |
return; |
|
res_len = strlen(res); |
if (value_len < res_len) |
memcpy (value, res, value_len); |
else |
memcpy (value, res, res_len); |
} |
|
|
/* GET_ENVIRONMENT_VARIABLE (name, [value, length, status, trim_name]) |
is a F2003 intrinsic for getting an environment variable. */ |
|
/* Status codes specifyed by the standard. */ |
#define GFC_SUCCESS 0 |
#define GFC_VALUE_TOO_SHORT -1 |
#define GFC_NAME_DOES_NOT_EXIST 1 |
|
/* This is also specified by the standard and means that the |
processor doesn't support environment variables. At the moment, |
gfortran doesn't use it. */ |
#define GFC_NOT_SUPPORTED 2 |
|
/* Processor-specific failure code. */ |
#define GFC_FAILURE 42 |
|
extern void get_environment_variable_i4 (char *, char *, GFC_INTEGER_4 *, |
GFC_INTEGER_4 *, GFC_LOGICAL_4 *, |
gfc_charlen_type, gfc_charlen_type); |
iexport_proto(get_environment_variable_i4); |
|
void |
get_environment_variable_i4 (char *name, char *value, GFC_INTEGER_4 *length, |
GFC_INTEGER_4 *status, GFC_LOGICAL_4 *trim_name, |
gfc_charlen_type name_len, |
gfc_charlen_type value_len) |
{ |
int stat = GFC_SUCCESS, res_len = 0; |
char *name_nt; |
char *res; |
|
if (name == NULL) |
runtime_error ("Name is required for get_environment_variable."); |
|
if (value == NULL && length == NULL && status == NULL && trim_name == NULL) |
return; |
|
if (name_len < 1) |
runtime_error ("Zero-length string passed as name to " |
"get_environment_variable."); |
|
if (value != NULL) |
{ |
if (value_len < 1) |
runtime_error ("Zero-length string passed as value to " |
"get_environment_variable."); |
else |
memset (value, ' ', value_len); /* Blank the string. */ |
} |
|
if ((!trim_name) || *trim_name) |
{ |
/* Trim trailing spaces from name. */ |
while (name_len > 0 && name[name_len - 1] == ' ') |
name_len--; |
} |
/* Make a null terminated copy of the name. */ |
name_nt = gfc_alloca (name_len + 1); |
memcpy (name_nt, name, name_len); |
name_nt[name_len] = '\0'; |
|
res = getenv(name_nt); |
|
if (res == NULL) |
stat = GFC_NAME_DOES_NOT_EXIST; |
else |
{ |
res_len = strlen(res); |
if (value != NULL) |
{ |
if (value_len < res_len) |
{ |
memcpy (value, res, value_len); |
stat = GFC_VALUE_TOO_SHORT; |
} |
else |
memcpy (value, res, res_len); |
} |
} |
|
if (status != NULL) |
*status = stat; |
|
if (length != NULL) |
*length = res_len; |
} |
iexport(get_environment_variable_i4); |
|
|
/* INTEGER*8 wrapper for get_environment_variable. */ |
|
extern void get_environment_variable_i8 (char *, char *, GFC_INTEGER_8 *, |
GFC_INTEGER_8 *, GFC_LOGICAL_8 *, |
gfc_charlen_type, gfc_charlen_type); |
export_proto(get_environment_variable_i8); |
|
void |
get_environment_variable_i8 (char *name, char *value, GFC_INTEGER_8 *length, |
GFC_INTEGER_8 *status, GFC_LOGICAL_8 *trim_name, |
gfc_charlen_type name_len, |
gfc_charlen_type value_len) |
{ |
GFC_INTEGER_4 length4, status4; |
GFC_LOGICAL_4 trim_name4; |
|
if (trim_name) |
trim_name4 = *trim_name; |
|
get_environment_variable_i4 (name, value, &length4, &status4, |
&trim_name4, name_len, value_len); |
|
if (length) |
*length = length4; |
|
if (status) |
*status = status4; |
} |
/kill.c
0,0 → 1,92
/* Implementation of the KILL g77 intrinsic. |
Copyright (C) 2005, 2007, 2009, 2011 Free Software Foundation, Inc. |
Contributed by François-Xavier Coudert <coudert@clipper.ens.fr> |
|
This file is part of the GNU Fortran runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
#include <errno.h> |
#include <signal.h> |
|
|
/* SUBROUTINE KILL(PID, SIGNAL, STATUS) |
INTEGER, INTENT(IN) :: PID, SIGNAL |
INTEGER(KIND=1), INTENT(OUT), OPTIONAL :: STATUS |
|
INTEGER(KIND=1) FUNCTION KILL(PID, SIGNAL) |
INTEGER, INTENT(IN) :: PID, SIGNAL */ |
|
#ifdef HAVE_KILL |
extern void kill_i4_sub (GFC_INTEGER_4 *, GFC_INTEGER_4 *, GFC_INTEGER_4 *); |
iexport_proto(kill_i4_sub); |
|
void |
kill_i4_sub (GFC_INTEGER_4 *pid, GFC_INTEGER_4 *signal, |
GFC_INTEGER_4 *status) |
{ |
int val; |
|
val = kill (*pid, *signal); |
|
if (status != NULL) |
*status = (val == 0) ? 0 : errno; |
} |
iexport(kill_i4_sub); |
|
extern void kill_i8_sub (GFC_INTEGER_8 *, GFC_INTEGER_8 *, GFC_INTEGER_8 *); |
iexport_proto(kill_i8_sub); |
|
void |
kill_i8_sub (GFC_INTEGER_8 *pid, GFC_INTEGER_8 *signal, |
GFC_INTEGER_8 *status) |
{ |
int val; |
|
val = kill (*pid, *signal); |
|
if (status != NULL) |
*status = (val == 0) ? 0 : errno; |
} |
iexport(kill_i8_sub); |
|
extern GFC_INTEGER_4 kill_i4 (GFC_INTEGER_4 *, GFC_INTEGER_4 *); |
export_proto(kill_i4); |
|
GFC_INTEGER_4 |
kill_i4 (GFC_INTEGER_4 *pid, GFC_INTEGER_4 *signal) |
{ |
GFC_INTEGER_4 val; |
kill_i4_sub (pid, signal, &val); |
return val; |
} |
|
extern GFC_INTEGER_8 kill_i8 (GFC_INTEGER_8 *, GFC_INTEGER_8 *); |
export_proto(kill_i8); |
|
GFC_INTEGER_8 |
kill_i8 (GFC_INTEGER_8 *pid, GFC_INTEGER_8 *signal) |
{ |
GFC_INTEGER_8 val; |
kill_i8_sub (pid, signal, &val); |
return val; |
} |
#endif |
/iso_c_binding.h
0,0 → 1,55
/* Copyright (C) 2007, 2009 Free Software Foundation, Inc. |
Contributed by Christopher Rickett. |
|
This file is part of the GNU Fortran 95 runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 3, or (at your option) |
any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
|
/* Declarations for ISO_C_BINDING library helper functions. */ |
|
#ifndef GFOR_ISO_C_BINDING_H |
#define GFOR_ISO_C_BINDING_H |
|
#include "libgfortran.h" |
|
typedef struct c_ptr |
{ |
void *c_address; |
} |
c_ptr_t; |
|
typedef struct c_funptr |
{ |
void *c_address; |
} |
c_funptr_t; |
|
#define ISO_C_BINDING_PREFIX(a) __iso_c_binding_##a |
|
void ISO_C_BINDING_PREFIX(c_f_pointer)(void *, gfc_array_void *, |
const array_t *, int, int); |
|
void ISO_C_BINDING_PREFIX(c_f_pointer_u0) (void *, gfc_array_void *, |
const array_t *); |
void ISO_C_BINDING_PREFIX(c_f_pointer_d0) (void *, gfc_array_void *, |
const array_t *); |
|
#endif |
/reshape_packed.c
0,0 → 1,49
/* Implementation of the RESHAPE intrinsic for packed arrays |
Copyright 2002, 2007, 2009 Free Software Foundation, Inc. |
Contributed by Paul Brook <paul@nowt.org> |
|
This file is part of the GNU Fortran 95 runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Ligbfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
|
#include <string.h> |
|
/* Reshape function where all arrays are packed. Basically just memcpy. */ |
|
void |
reshape_packed (char * restrict ret, index_type rsize, const char * source, |
index_type ssize, const char * pad, index_type psize) |
{ |
index_type size; |
|
size = (rsize > ssize) ? ssize : rsize; |
memcpy (ret, source, size); |
ret += size; |
rsize -= size; |
while (rsize > 0) |
{ |
size = (rsize > psize) ? psize : rsize; |
memcpy (ret, pad, size); |
ret += size; |
rsize -= size; |
} |
} |
/fnum.c
0,0 → 1,48
/* Implementation of the FNUM intrinsics. |
Copyright (C) 2004, 2007, 2009 Free Software Foundation, Inc. |
Contributed by Steven G. Kargl <kargls@comcast.net>. |
|
This file is part of the GNU Fortran 95 runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
|
/* FUNCTION FNUM(UNIT) |
INTEGER FNUM |
INTEGER, INTENT(IN), :: UNIT */ |
|
extern GFC_INTEGER_4 fnum_i4 (GFC_INTEGER_4 *); |
export_proto(fnum_i4); |
|
GFC_INTEGER_4 |
fnum_i4 (GFC_INTEGER_4 *unit) |
{ |
return unit_to_fd (*unit); |
} |
|
extern GFC_INTEGER_8 fnum_i8 (GFC_INTEGER_8 *); |
export_proto(fnum_i8); |
|
GFC_INTEGER_8 |
fnum_i8 (GFC_INTEGER_8 * unit) |
{ |
return unit_to_fd (*unit); |
} |
/execute_command_line.c
0,0 → 1,180
/* Implementation of the EXECUTE_COMMAND_LINE intrinsic. |
Copyright (C) 2009, 2011 Free Software Foundation, Inc. |
Contributed by François-Xavier Coudert. |
|
This file is part of the GNU Fortran runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or modify it under |
the terms of the GNU General Public License as published by the Free |
Software Foundation; either version 3, or (at your option) any later |
version. |
|
Libgfortran is distributed in the hope that it will be useful, but WITHOUT |
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
#include <string.h> |
#include <stdbool.h> |
#include <stdlib.h> |
|
#ifdef HAVE_UNISTD_H |
#include <unistd.h> |
#endif |
#ifdef HAVE_SYS_WAIT_H |
#include <sys/wait.h> |
#endif |
|
|
enum { EXEC_SYNCHRONOUS = -2, EXEC_NOERROR = 0, EXEC_SYSTEMFAILED, |
EXEC_CHILDFAILED }; |
static const char *cmdmsg_values[] = |
{ "", |
"Termination status of the command-language interpreter cannot be obtained", |
"Execution of child process impossible" }; |
|
|
|
static void |
set_cmdstat (int *cmdstat, int value) |
{ |
if (cmdstat) |
*cmdstat = value; |
else if (value > EXEC_NOERROR) |
runtime_error ("Could not execute command line"); |
} |
|
|
static void |
execute_command_line (const char *command, bool wait, int *exitstat, |
int *cmdstat, char *cmdmsg, |
gfc_charlen_type command_len, |
gfc_charlen_type cmdmsg_len) |
{ |
/* Transform the Fortran string to a C string. */ |
char cmd[command_len + 1]; |
memcpy (cmd, command, command_len); |
cmd[command_len] = '\0'; |
|
/* Flush all I/O units before executing the command. */ |
flush_all_units(); |
|
#if defined(HAVE_FORK) |
if (!wait) |
{ |
/* Asynchronous execution. */ |
pid_t pid; |
|
set_cmdstat (cmdstat, EXEC_NOERROR); |
|
if ((pid = fork()) < 0) |
set_cmdstat (cmdstat, EXEC_CHILDFAILED); |
else if (pid == 0) |
{ |
/* Child process. */ |
int res = system (cmd); |
_exit (WIFEXITED(res) ? WEXITSTATUS(res) : res); |
} |
} |
else |
#endif |
{ |
/* Synchronous execution. */ |
int res = system (cmd); |
|
if (res == -1) |
set_cmdstat (cmdstat, EXEC_SYSTEMFAILED); |
else if (!wait) |
set_cmdstat (cmdstat, EXEC_SYNCHRONOUS); |
else |
set_cmdstat (cmdstat, EXEC_NOERROR); |
|
if (res != -1) |
{ |
#if defined(WEXITSTATUS) && defined(WIFEXITED) |
*exitstat = WIFEXITED(res) ? WEXITSTATUS(res) : res; |
#else |
*exitstat = res; |
#endif |
} |
} |
|
/* Now copy back to the Fortran string if needed. */ |
if (cmdstat && *cmdstat > EXEC_NOERROR) |
{ |
if (cmdmsg) |
fstrcpy (cmdmsg, cmdmsg_len, cmdmsg_values[*cmdstat], |
strlen (cmdmsg_values[*cmdstat])); |
else |
runtime_error ("Failure in EXECUTE_COMMAND_LINE: %s", |
cmdmsg_values[*cmdstat]); |
} |
} |
|
|
extern void |
execute_command_line_i4 (const char *command, GFC_LOGICAL_4 *wait, |
GFC_INTEGER_4 *exitstat, GFC_INTEGER_4 *cmdstat, |
char *cmdmsg, gfc_charlen_type command_len, |
gfc_charlen_type cmdmsg_len); |
export_proto(execute_command_line_i4); |
|
void |
execute_command_line_i4 (const char *command, GFC_LOGICAL_4 *wait, |
GFC_INTEGER_4 *exitstat, GFC_INTEGER_4 *cmdstat, |
char *cmdmsg, gfc_charlen_type command_len, |
gfc_charlen_type cmdmsg_len) |
{ |
bool w = wait ? *wait : true; |
int estat, estat_initial, cstat; |
|
if (exitstat) |
estat_initial = estat = *exitstat; |
|
execute_command_line (command, w, &estat, cmdstat ? &cstat : NULL, |
cmdmsg, command_len, cmdmsg_len); |
|
if (exitstat && estat != estat_initial) |
*exitstat = estat; |
if (cmdstat) |
*cmdstat = cstat; |
} |
|
|
extern void |
execute_command_line_i8 (const char *command, GFC_LOGICAL_8 *wait, |
GFC_INTEGER_8 *exitstat, GFC_INTEGER_8 *cmdstat, |
char *cmdmsg, gfc_charlen_type command_len, |
gfc_charlen_type cmdmsg_len); |
export_proto(execute_command_line_i8); |
|
void |
execute_command_line_i8 (const char *command, GFC_LOGICAL_8 *wait, |
GFC_INTEGER_8 *exitstat, GFC_INTEGER_8 *cmdstat, |
char *cmdmsg, gfc_charlen_type command_len, |
gfc_charlen_type cmdmsg_len) |
{ |
bool w = wait ? *wait : true; |
int estat, estat_initial, cstat; |
|
if (exitstat) |
estat_initial = estat = *exitstat; |
|
execute_command_line (command, w, &estat, cmdstat ? &cstat : NULL, |
cmdmsg, command_len, cmdmsg_len); |
|
if (exitstat && estat != estat_initial) |
*exitstat = estat; |
if (cmdstat) |
*cmdstat = cstat; |
} |
/size.c
0,0 → 1,61
/* Implementation of the size intrinsic. |
Copyright 2002, 2009 Free Software Foundation, Inc. |
Contributed by Paul Brook <paul@nowt.org> |
|
This file is part of the GNU Fortran 95 runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
|
index_type |
size0 (const array_t * array) |
{ |
int n; |
index_type size; |
index_type len; |
|
size = 1; |
for (n = 0; n < GFC_DESCRIPTOR_RANK (array); n++) |
{ |
len = GFC_DESCRIPTOR_EXTENT(array,n); |
if (len < 0) |
len = 0; |
size *= len; |
} |
return size; |
} |
iexport(size0); |
|
extern index_type size1 (const array_t * array, index_type dim); |
export_proto(size1); |
|
index_type |
size1 (const array_t * array, index_type dim) |
{ |
index_type size; |
|
dim--; |
|
size = GFC_DESCRIPTOR_EXTENT(array,dim); |
if (size < 0) |
size = 0; |
return size; |
} |
/symlnk.c
0,0 → 1,131
/* Implementation of the SYMLNK intrinsic. |
Copyright (C) 2005, 2007, 2009 Free Software Foundation, Inc. |
Contributed by François-Xavier Coudert <coudert@clipper.ens.fr> |
|
This file is part of the GNU Fortran 95 runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
|
#include <errno.h> |
#include <string.h> |
|
#ifdef HAVE_UNISTD_H |
#include <unistd.h> |
#endif |
|
/* SUBROUTINE SYMLNK(PATH1, PATH2, STATUS) |
CHARACTER(len=*), INTENT(IN) :: PATH1, PATH2 |
INTEGER, INTENT(OUT), OPTIONAL :: STATUS */ |
|
#ifdef HAVE_SYMLINK |
extern void symlnk_i4_sub (char *, char *, GFC_INTEGER_4 *, gfc_charlen_type, |
gfc_charlen_type); |
iexport_proto(symlnk_i4_sub); |
|
void |
symlnk_i4_sub (char *path1, char *path2, GFC_INTEGER_4 *status, |
gfc_charlen_type path1_len, gfc_charlen_type path2_len) |
{ |
int val; |
char *str1, *str2; |
|
/* Trim trailing spaces from paths. */ |
while (path1_len > 0 && path1[path1_len - 1] == ' ') |
path1_len--; |
while (path2_len > 0 && path2[path2_len - 1] == ' ') |
path2_len--; |
|
/* Make a null terminated copy of the strings. */ |
str1 = gfc_alloca (path1_len + 1); |
memcpy (str1, path1, path1_len); |
str1[path1_len] = '\0'; |
|
str2 = gfc_alloca (path2_len + 1); |
memcpy (str2, path2, path2_len); |
str2[path2_len] = '\0'; |
|
val = symlink (str1, str2); |
|
if (status != NULL) |
*status = (val == 0) ? 0 : errno; |
} |
iexport(symlnk_i4_sub); |
|
extern void symlnk_i8_sub (char *, char *, GFC_INTEGER_8 *, gfc_charlen_type, |
gfc_charlen_type); |
iexport_proto(symlnk_i8_sub); |
|
void |
symlnk_i8_sub (char *path1, char *path2, GFC_INTEGER_8 *status, |
gfc_charlen_type path1_len, gfc_charlen_type path2_len) |
{ |
int val; |
char *str1, *str2; |
|
/* Trim trailing spaces from paths. */ |
while (path1_len > 0 && path1[path1_len - 1] == ' ') |
path1_len--; |
while (path2_len > 0 && path2[path2_len - 1] == ' ') |
path2_len--; |
|
/* Make a null terminated copy of the strings. */ |
str1 = gfc_alloca (path1_len + 1); |
memcpy (str1, path1, path1_len); |
str1[path1_len] = '\0'; |
|
str2 = gfc_alloca (path2_len + 1); |
memcpy (str2, path2, path2_len); |
str2[path2_len] = '\0'; |
|
val = symlink (str1, str2); |
|
if (status != NULL) |
*status = (val == 0) ? 0 : errno; |
} |
iexport(symlnk_i8_sub); |
|
extern GFC_INTEGER_4 symlnk_i4 (char *, char *, gfc_charlen_type, |
gfc_charlen_type); |
export_proto(symlnk_i4); |
|
GFC_INTEGER_4 |
symlnk_i4 (char *path1, char *path2, gfc_charlen_type path1_len, |
gfc_charlen_type path2_len) |
{ |
GFC_INTEGER_4 val; |
symlnk_i4_sub (path1, path2, &val, path1_len, path2_len); |
return val; |
} |
|
extern GFC_INTEGER_8 symlnk_i8 (char *, char *, gfc_charlen_type, |
gfc_charlen_type); |
export_proto(symlnk_i8); |
|
GFC_INTEGER_8 |
symlnk_i8 (char *path1, char *path2, gfc_charlen_type path1_len, |
gfc_charlen_type path2_len) |
{ |
GFC_INTEGER_8 val; |
symlnk_i8_sub (path1, path2, &val, path1_len, path2_len); |
return val; |
} |
#endif |
/signal.c
0,0 → 1,229
/* Implementation of the SIGNAL and ALARM g77 intrinsics |
Copyright (C) 2005, 2007, 2009, 2011 Free Software Foundation, Inc. |
Contributed by François-Xavier Coudert <coudert@clipper.ens.fr> |
|
This file is part of the GNU Fortran runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
|
#ifdef HAVE_UNISTD_H |
#include <unistd.h> |
#endif |
|
#include <signal.h> |
|
#ifdef HAVE_INTTYPES_H |
#include <inttypes.h> |
#endif |
|
#include <errno.h> |
|
/* SIGNAL subroutine with PROCEDURE as handler */ |
extern void signal_sub (int *, void (*)(int), int *); |
iexport_proto(signal_sub); |
|
void |
signal_sub (int *number, void (*handler)(int), int *status) |
{ |
intptr_t ret; |
|
if (status != NULL) |
{ |
ret = (intptr_t) signal (*number, handler); |
*status = (int) ret; |
} |
else |
signal (*number, handler); |
} |
iexport(signal_sub); |
|
|
/* SIGNAL subroutine with INTEGER as handler */ |
extern void signal_sub_int (int *, int *, int *); |
iexport_proto(signal_sub_int); |
|
void |
signal_sub_int (int *number, int *handler, int *status) |
{ |
intptr_t ptr = *handler, ret; |
|
if (status != NULL) |
{ |
ret = (intptr_t) signal (*number, (void (*)(int)) ptr); |
*status = (int) ret; |
} |
else |
signal (*number, (void (*)(int)) ptr); |
} |
iexport(signal_sub_int); |
|
|
/* SIGNAL function with PROCEDURE as handler */ |
extern int signal_func (int *, void (*)(int)); |
iexport_proto(signal_func); |
|
int |
signal_func (int *number, void (*handler)(int)) |
{ |
int status; |
signal_sub (number, handler, &status); |
return status; |
} |
iexport(signal_func); |
|
|
/* SIGNAL function with INTEGER as handler */ |
extern int signal_func_int (int *, int *); |
iexport_proto(signal_func_int); |
|
int |
signal_func_int (int *number, int *handler) |
{ |
int status; |
signal_sub_int (number, handler, &status); |
return status; |
} |
iexport(signal_func_int); |
|
|
|
/* ALARM intrinsic with PROCEDURE as handler */ |
extern void alarm_sub_i4 (int *, void (*)(int), GFC_INTEGER_4 *); |
iexport_proto(alarm_sub_i4); |
|
void |
alarm_sub_i4 (int * seconds __attribute__ ((unused)), |
void (*handler)(int) __attribute__ ((unused)), |
GFC_INTEGER_4 *status) |
{ |
#if defined (SIGALRM) && defined (HAVE_ALARM) |
if (status != NULL) |
{ |
if (signal (SIGALRM, handler) == SIG_ERR) |
*status = -1; |
else |
*status = alarm (*seconds); |
} |
else |
{ |
signal (SIGALRM, handler); |
alarm (*seconds); |
} |
#else |
errno = ENOSYS; |
if (status != NULL) |
*status = -1; |
#endif |
} |
iexport(alarm_sub_i4); |
|
|
extern void alarm_sub_i8 (int *, void (*)(int), GFC_INTEGER_8 *); |
iexport_proto(alarm_sub_i8); |
|
void |
alarm_sub_i8 (int *seconds __attribute__ ((unused)), |
void (*handler)(int) __attribute__ ((unused)), |
GFC_INTEGER_8 *status) |
{ |
#if defined (SIGALRM) && defined (HAVE_ALARM) |
if (status != NULL) |
{ |
if (signal (SIGALRM, handler) == SIG_ERR) |
*status = -1; |
else |
*status = alarm (*seconds); |
} |
else |
{ |
signal (SIGALRM, handler); |
alarm (*seconds); |
} |
#else |
errno = ENOSYS; |
if (status != NULL) |
*status = -1; |
#endif |
} |
iexport(alarm_sub_i8); |
|
|
/* ALARM intrinsic with INTEGER as handler */ |
extern void alarm_sub_int_i4 (int *, int *, GFC_INTEGER_4 *); |
iexport_proto(alarm_sub_int_i4); |
|
void |
alarm_sub_int_i4 (int *seconds __attribute__ ((unused)), |
int *handler __attribute__ ((unused)), |
GFC_INTEGER_4 *status) |
{ |
#if defined (SIGALRM) && defined (HAVE_ALARM) |
if (status != NULL) |
{ |
if (signal (SIGALRM, (void (*)(int)) (intptr_t) *handler) == SIG_ERR) |
*status = -1; |
else |
*status = alarm (*seconds); |
} |
else |
{ |
signal (SIGALRM, (void (*)(int)) (intptr_t) *handler); |
alarm (*seconds); |
} |
#else |
errno = ENOSYS; |
if (status != NULL) |
*status = -1; |
#endif |
} |
iexport(alarm_sub_int_i4); |
|
|
extern void alarm_sub_int_i8 (int *, int *, GFC_INTEGER_8 *); |
iexport_proto(alarm_sub_int_i8); |
|
void |
alarm_sub_int_i8 (int *seconds __attribute__ ((unused)), |
int *handler __attribute__ ((unused)), |
GFC_INTEGER_8 *status) |
{ |
#if defined (SIGALRM) && defined (HAVE_ALARM) |
if (status != NULL) |
{ |
if (signal (SIGALRM, (void (*)(int)) (intptr_t) *handler) == SIG_ERR) |
*status = -1; |
else |
*status = alarm (*seconds); |
} |
else |
{ |
signal (SIGALRM, (void (*)(int)) (intptr_t) *handler); |
alarm (*seconds); |
} |
#else |
errno = ENOSYS; |
if (status != NULL) |
*status = -1; |
#endif |
} |
iexport(alarm_sub_int_i8); |
|
/random.c
0,0 → 1,798
/* Implementation of the RANDOM intrinsics |
Copyright 2002, 2004, 2005, 2006, 2007, 2009, 2010 |
Free Software Foundation, Inc. |
Contributed by Lars Segerlund <seger@linuxmail.org> |
and Steve Kargl. |
|
This file is part of the GNU Fortran 95 runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Ligbfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
#include <gthr.h> |
#include <string.h> |
|
extern void random_r4 (GFC_REAL_4 *); |
iexport_proto(random_r4); |
|
extern void random_r8 (GFC_REAL_8 *); |
iexport_proto(random_r8); |
|
extern void arandom_r4 (gfc_array_r4 *); |
export_proto(arandom_r4); |
|
extern void arandom_r8 (gfc_array_r8 *); |
export_proto(arandom_r8); |
|
#ifdef HAVE_GFC_REAL_10 |
|
extern void random_r10 (GFC_REAL_10 *); |
iexport_proto(random_r10); |
|
extern void arandom_r10 (gfc_array_r10 *); |
export_proto(arandom_r10); |
|
#endif |
|
#ifdef HAVE_GFC_REAL_16 |
|
extern void random_r16 (GFC_REAL_16 *); |
iexport_proto(random_r16); |
|
extern void arandom_r16 (gfc_array_r16 *); |
export_proto(arandom_r16); |
|
#endif |
|
#ifdef __GTHREAD_MUTEX_INIT |
static __gthread_mutex_t random_lock = __GTHREAD_MUTEX_INIT; |
#else |
static __gthread_mutex_t random_lock; |
#endif |
|
/* Helper routines to map a GFC_UINTEGER_* to the corresponding |
GFC_REAL_* types in the range of [0,1). If GFC_REAL_*_RADIX are 2 |
or 16, respectively, we mask off the bits that don't fit into the |
correct GFC_REAL_*, convert to the real type, then multiply by the |
correct offset. */ |
|
|
static void |
rnumber_4 (GFC_REAL_4 *f, GFC_UINTEGER_4 v) |
{ |
GFC_UINTEGER_4 mask; |
#if GFC_REAL_4_RADIX == 2 |
mask = ~ (GFC_UINTEGER_4) 0u << (32 - GFC_REAL_4_DIGITS); |
#elif GFC_REAL_4_RADIX == 16 |
mask = ~ (GFC_UINTEGER_4) 0u << ((8 - GFC_REAL_4_DIGITS) * 4); |
#else |
#error "GFC_REAL_4_RADIX has unknown value" |
#endif |
v = v & mask; |
*f = (GFC_REAL_4) v * GFC_REAL_4_LITERAL(0x1.p-32); |
} |
|
static void |
rnumber_8 (GFC_REAL_8 *f, GFC_UINTEGER_8 v) |
{ |
GFC_UINTEGER_8 mask; |
#if GFC_REAL_8_RADIX == 2 |
mask = ~ (GFC_UINTEGER_8) 0u << (64 - GFC_REAL_8_DIGITS); |
#elif GFC_REAL_8_RADIX == 16 |
mask = ~ (GFC_UINTEGER_8) 0u << (16 - GFC_REAL_8_DIGITS) * 4); |
#else |
#error "GFC_REAL_8_RADIX has unknown value" |
#endif |
v = v & mask; |
*f = (GFC_REAL_8) v * GFC_REAL_8_LITERAL(0x1.p-64); |
} |
|
#ifdef HAVE_GFC_REAL_10 |
|
static void |
rnumber_10 (GFC_REAL_10 *f, GFC_UINTEGER_8 v) |
{ |
GFC_UINTEGER_8 mask; |
#if GFC_REAL_10_RADIX == 2 |
mask = ~ (GFC_UINTEGER_8) 0u << (64 - GFC_REAL_10_DIGITS); |
#elif GFC_REAL_10_RADIX == 16 |
mask = ~ (GFC_UINTEGER_10) 0u << ((16 - GFC_REAL_10_DIGITS) * 4); |
#else |
#error "GFC_REAL_10_RADIX has unknown value" |
#endif |
v = v & mask; |
*f = (GFC_REAL_10) v * GFC_REAL_10_LITERAL(0x1.p-64); |
} |
#endif |
|
#ifdef HAVE_GFC_REAL_16 |
|
/* For REAL(KIND=16), we only need to mask off the lower bits. */ |
|
static void |
rnumber_16 (GFC_REAL_16 *f, GFC_UINTEGER_8 v1, GFC_UINTEGER_8 v2) |
{ |
GFC_UINTEGER_8 mask; |
#if GFC_REAL_16_RADIX == 2 |
mask = ~ (GFC_UINTEGER_8) 0u << (128 - GFC_REAL_16_DIGITS); |
#elif GFC_REAL_16_RADIX == 16 |
mask = ~ (GFC_UINTEGER_8) 0u << ((32 - GFC_REAL_16_DIGITS) * 4); |
#else |
#error "GFC_REAL_16_RADIX has unknown value" |
#endif |
v2 = v2 & mask; |
*f = (GFC_REAL_16) v1 * GFC_REAL_16_LITERAL(0x1.p-64) |
+ (GFC_REAL_16) v2 * GFC_REAL_16_LITERAL(0x1.p-128); |
} |
#endif |
/* libgfortran previously had a Mersenne Twister, taken from the paper: |
|
Mersenne Twister: 623-dimensionally equidistributed |
uniform pseudorandom generator. |
|
by Makoto Matsumoto & Takuji Nishimura |
which appeared in the: ACM Transactions on Modelling and Computer |
Simulations: Special Issue on Uniform Random Number |
Generation. ( Early in 1998 ). |
|
The Mersenne Twister code was replaced due to |
|
(1) Simple user specified seeds lead to really bad sequences for |
nearly 100000 random numbers. |
(2) open(), read(), and close() were not properly declared via header |
files. |
(3) The global index i was abused and caused unexpected behavior with |
GET and PUT. |
(4) See PR 15619. |
|
|
libgfortran currently uses George Marsaglia's KISS (Keep It Simple Stupid) |
random number generator. This PRNG combines: |
|
(1) The congruential generator x(n)=69069*x(n-1)+1327217885 with a period |
of 2^32, |
(2) A 3-shift shift-register generator with a period of 2^32-1, |
(3) Two 16-bit multiply-with-carry generators with a period of |
597273182964842497 > 2^59. |
|
The overall period exceeds 2^123. |
|
http://www.ciphersbyritter.com/NEWS4/RANDC.HTM#369F6FCA.74C7C041@stat.fsu.edu |
|
The above web site has an archive of a newsgroup posting from George |
Marsaglia with the statement: |
|
Subject: Random numbers for C: Improvements. |
Date: Fri, 15 Jan 1999 11:41:47 -0500 |
From: George Marsaglia <geo@stat.fsu.edu> |
Message-ID: <369F6FCA.74C7C041@stat.fsu.edu> |
References: <369B5E30.65A55FD1@stat.fsu.edu> |
Newsgroups: sci.stat.math,sci.math,sci.math.numer-analysis |
Lines: 93 |
|
As I hoped, several suggestions have led to |
improvements in the code for RNG's I proposed for |
use in C. (See the thread "Random numbers for C: Some |
suggestions" in previous postings.) The improved code |
is listed below. |
|
A question of copyright has also been raised. Unlike |
DIEHARD, there is no copyright on the code below. You |
are free to use it in any way you want, but you may |
wish to acknowledge the source, as a courtesy. |
|
"There is no copyright on the code below." included the original |
KISS algorithm. */ |
|
/* We use three KISS random number generators, with different |
seeds. |
As a matter of Quality of Implementation, the random numbers |
we generate for different REAL kinds, starting from the same |
seed, are always the same up to the precision of these types. |
We do this by using three generators with different seeds, the |
first one always for the most significant bits, the second one |
for bits 33..64 (if present in the REAL kind), and the third one |
(called twice) for REAL(16). */ |
|
#define GFC_SL(k, n) ((k)^((k)<<(n))) |
#define GFC_SR(k, n) ((k)^((k)>>(n))) |
|
/* Reference for the seed: |
From: "George Marsaglia" <g...@stat.fsu.edu> |
Newsgroups: sci.math |
Message-ID: <e7CcnWxczriWssCjXTWc3A@comcast.com> |
|
The KISS RNG uses four seeds, x, y, z, c, |
with 0<=x<2^32, 0<y<2^32, 0<=z<2^32, 0<=c<698769069 |
except that the two pairs |
z=0,c=0 and z=2^32-1,c=698769068 |
should be avoided. */ |
|
/* Any modifications to the seeds that change kiss_size below need to be |
reflected in check.c (gfc_check_random_seed) to enable correct |
compile-time checking of PUT size for the RANDOM_SEED intrinsic. */ |
|
#define KISS_DEFAULT_SEED_1 123456789, 362436069, 521288629, 316191069 |
#define KISS_DEFAULT_SEED_2 987654321, 458629013, 582859209, 438195021 |
#ifdef HAVE_GFC_REAL_16 |
#define KISS_DEFAULT_SEED_3 573658661, 185639104, 582619469, 296736107 |
#endif |
|
static GFC_UINTEGER_4 kiss_seed[] = { |
KISS_DEFAULT_SEED_1, |
KISS_DEFAULT_SEED_2, |
#ifdef HAVE_GFC_REAL_16 |
KISS_DEFAULT_SEED_3 |
#endif |
}; |
|
static GFC_UINTEGER_4 kiss_default_seed[] = { |
KISS_DEFAULT_SEED_1, |
KISS_DEFAULT_SEED_2, |
#ifdef HAVE_GFC_REAL_16 |
KISS_DEFAULT_SEED_3 |
#endif |
}; |
|
static const GFC_INTEGER_4 kiss_size = sizeof(kiss_seed)/sizeof(kiss_seed[0]); |
|
static GFC_UINTEGER_4 * const kiss_seed_1 = kiss_seed; |
static GFC_UINTEGER_4 * const kiss_seed_2 = kiss_seed + 4; |
|
#ifdef HAVE_GFC_REAL_16 |
static GFC_UINTEGER_4 * const kiss_seed_3 = kiss_seed + 8; |
#endif |
|
/* kiss_random_kernel() returns an integer value in the range of |
(0, GFC_UINTEGER_4_HUGE]. The distribution of pseudorandom numbers |
should be uniform. */ |
|
static GFC_UINTEGER_4 |
kiss_random_kernel(GFC_UINTEGER_4 * seed) |
{ |
GFC_UINTEGER_4 kiss; |
|
seed[0] = 69069 * seed[0] + 1327217885; |
seed[1] = GFC_SL(GFC_SR(GFC_SL(seed[1],13),17),5); |
seed[2] = 18000 * (seed[2] & 65535) + (seed[2] >> 16); |
seed[3] = 30903 * (seed[3] & 65535) + (seed[3] >> 16); |
kiss = seed[0] + seed[1] + (seed[2] << 16) + seed[3]; |
|
return kiss; |
} |
|
/* This function produces a REAL(4) value from the uniform distribution |
with range [0,1). */ |
|
void |
random_r4 (GFC_REAL_4 *x) |
{ |
GFC_UINTEGER_4 kiss; |
|
__gthread_mutex_lock (&random_lock); |
kiss = kiss_random_kernel (kiss_seed_1); |
rnumber_4 (x, kiss); |
__gthread_mutex_unlock (&random_lock); |
} |
iexport(random_r4); |
|
/* This function produces a REAL(8) value from the uniform distribution |
with range [0,1). */ |
|
void |
random_r8 (GFC_REAL_8 *x) |
{ |
GFC_UINTEGER_8 kiss; |
|
__gthread_mutex_lock (&random_lock); |
kiss = ((GFC_UINTEGER_8) kiss_random_kernel (kiss_seed_1)) << 32; |
kiss += kiss_random_kernel (kiss_seed_2); |
rnumber_8 (x, kiss); |
__gthread_mutex_unlock (&random_lock); |
} |
iexport(random_r8); |
|
#ifdef HAVE_GFC_REAL_10 |
|
/* This function produces a REAL(10) value from the uniform distribution |
with range [0,1). */ |
|
void |
random_r10 (GFC_REAL_10 *x) |
{ |
GFC_UINTEGER_8 kiss; |
|
__gthread_mutex_lock (&random_lock); |
kiss = ((GFC_UINTEGER_8) kiss_random_kernel (kiss_seed_1)) << 32; |
kiss += kiss_random_kernel (kiss_seed_2); |
rnumber_10 (x, kiss); |
__gthread_mutex_unlock (&random_lock); |
} |
iexport(random_r10); |
|
#endif |
|
/* This function produces a REAL(16) value from the uniform distribution |
with range [0,1). */ |
|
#ifdef HAVE_GFC_REAL_16 |
|
void |
random_r16 (GFC_REAL_16 *x) |
{ |
GFC_UINTEGER_8 kiss1, kiss2; |
|
__gthread_mutex_lock (&random_lock); |
kiss1 = ((GFC_UINTEGER_8) kiss_random_kernel (kiss_seed_1)) << 32; |
kiss1 += kiss_random_kernel (kiss_seed_2); |
|
kiss2 = ((GFC_UINTEGER_8) kiss_random_kernel (kiss_seed_3)) << 32; |
kiss2 += kiss_random_kernel (kiss_seed_3); |
|
rnumber_16 (x, kiss1, kiss2); |
__gthread_mutex_unlock (&random_lock); |
} |
iexport(random_r16); |
|
|
#endif |
/* This function fills a REAL(4) array with values from the uniform |
distribution with range [0,1). */ |
|
void |
arandom_r4 (gfc_array_r4 *x) |
{ |
index_type count[GFC_MAX_DIMENSIONS]; |
index_type extent[GFC_MAX_DIMENSIONS]; |
index_type stride[GFC_MAX_DIMENSIONS]; |
index_type stride0; |
index_type dim; |
GFC_REAL_4 *dest; |
GFC_UINTEGER_4 kiss; |
int n; |
|
dest = x->data; |
|
dim = GFC_DESCRIPTOR_RANK (x); |
|
for (n = 0; n < dim; n++) |
{ |
count[n] = 0; |
stride[n] = GFC_DESCRIPTOR_STRIDE(x,n); |
extent[n] = GFC_DESCRIPTOR_EXTENT(x,n); |
if (extent[n] <= 0) |
return; |
} |
|
stride0 = stride[0]; |
|
__gthread_mutex_lock (&random_lock); |
|
while (dest) |
{ |
/* random_r4 (dest); */ |
kiss = kiss_random_kernel (kiss_seed_1); |
rnumber_4 (dest, kiss); |
|
/* Advance to the next element. */ |
dest += stride0; |
count[0]++; |
/* Advance to the next source element. */ |
n = 0; |
while (count[n] == extent[n]) |
{ |
/* When we get to the end of a dimension, reset it and increment |
the next dimension. */ |
count[n] = 0; |
/* We could precalculate these products, but this is a less |
frequently used path so probably not worth it. */ |
dest -= stride[n] * extent[n]; |
n++; |
if (n == dim) |
{ |
dest = NULL; |
break; |
} |
else |
{ |
count[n]++; |
dest += stride[n]; |
} |
} |
} |
__gthread_mutex_unlock (&random_lock); |
} |
|
/* This function fills a REAL(8) array with values from the uniform |
distribution with range [0,1). */ |
|
void |
arandom_r8 (gfc_array_r8 *x) |
{ |
index_type count[GFC_MAX_DIMENSIONS]; |
index_type extent[GFC_MAX_DIMENSIONS]; |
index_type stride[GFC_MAX_DIMENSIONS]; |
index_type stride0; |
index_type dim; |
GFC_REAL_8 *dest; |
GFC_UINTEGER_8 kiss; |
int n; |
|
dest = x->data; |
|
dim = GFC_DESCRIPTOR_RANK (x); |
|
for (n = 0; n < dim; n++) |
{ |
count[n] = 0; |
stride[n] = GFC_DESCRIPTOR_STRIDE(x,n); |
extent[n] = GFC_DESCRIPTOR_EXTENT(x,n); |
if (extent[n] <= 0) |
return; |
} |
|
stride0 = stride[0]; |
|
__gthread_mutex_lock (&random_lock); |
|
while (dest) |
{ |
/* random_r8 (dest); */ |
kiss = ((GFC_UINTEGER_8) kiss_random_kernel (kiss_seed_1)) << 32; |
kiss += kiss_random_kernel (kiss_seed_2); |
rnumber_8 (dest, kiss); |
|
/* Advance to the next element. */ |
dest += stride0; |
count[0]++; |
/* Advance to the next source element. */ |
n = 0; |
while (count[n] == extent[n]) |
{ |
/* When we get to the end of a dimension, reset it and increment |
the next dimension. */ |
count[n] = 0; |
/* We could precalculate these products, but this is a less |
frequently used path so probably not worth it. */ |
dest -= stride[n] * extent[n]; |
n++; |
if (n == dim) |
{ |
dest = NULL; |
break; |
} |
else |
{ |
count[n]++; |
dest += stride[n]; |
} |
} |
} |
__gthread_mutex_unlock (&random_lock); |
} |
|
#ifdef HAVE_GFC_REAL_10 |
|
/* This function fills a REAL(10) array with values from the uniform |
distribution with range [0,1). */ |
|
void |
arandom_r10 (gfc_array_r10 *x) |
{ |
index_type count[GFC_MAX_DIMENSIONS]; |
index_type extent[GFC_MAX_DIMENSIONS]; |
index_type stride[GFC_MAX_DIMENSIONS]; |
index_type stride0; |
index_type dim; |
GFC_REAL_10 *dest; |
GFC_UINTEGER_8 kiss; |
int n; |
|
dest = x->data; |
|
dim = GFC_DESCRIPTOR_RANK (x); |
|
for (n = 0; n < dim; n++) |
{ |
count[n] = 0; |
stride[n] = GFC_DESCRIPTOR_STRIDE(x,n); |
extent[n] = GFC_DESCRIPTOR_EXTENT(x,n); |
if (extent[n] <= 0) |
return; |
} |
|
stride0 = stride[0]; |
|
__gthread_mutex_lock (&random_lock); |
|
while (dest) |
{ |
/* random_r10 (dest); */ |
kiss = ((GFC_UINTEGER_8) kiss_random_kernel (kiss_seed_1)) << 32; |
kiss += kiss_random_kernel (kiss_seed_2); |
rnumber_10 (dest, kiss); |
|
/* Advance to the next element. */ |
dest += stride0; |
count[0]++; |
/* Advance to the next source element. */ |
n = 0; |
while (count[n] == extent[n]) |
{ |
/* When we get to the end of a dimension, reset it and increment |
the next dimension. */ |
count[n] = 0; |
/* We could precalculate these products, but this is a less |
frequently used path so probably not worth it. */ |
dest -= stride[n] * extent[n]; |
n++; |
if (n == dim) |
{ |
dest = NULL; |
break; |
} |
else |
{ |
count[n]++; |
dest += stride[n]; |
} |
} |
} |
__gthread_mutex_unlock (&random_lock); |
} |
|
#endif |
|
#ifdef HAVE_GFC_REAL_16 |
|
/* This function fills a REAL(16) array with values from the uniform |
distribution with range [0,1). */ |
|
void |
arandom_r16 (gfc_array_r16 *x) |
{ |
index_type count[GFC_MAX_DIMENSIONS]; |
index_type extent[GFC_MAX_DIMENSIONS]; |
index_type stride[GFC_MAX_DIMENSIONS]; |
index_type stride0; |
index_type dim; |
GFC_REAL_16 *dest; |
GFC_UINTEGER_8 kiss1, kiss2; |
int n; |
|
dest = x->data; |
|
dim = GFC_DESCRIPTOR_RANK (x); |
|
for (n = 0; n < dim; n++) |
{ |
count[n] = 0; |
stride[n] = GFC_DESCRIPTOR_STRIDE(x,n); |
extent[n] = GFC_DESCRIPTOR_EXTENT(x,n); |
if (extent[n] <= 0) |
return; |
} |
|
stride0 = stride[0]; |
|
__gthread_mutex_lock (&random_lock); |
|
while (dest) |
{ |
/* random_r16 (dest); */ |
kiss1 = ((GFC_UINTEGER_8) kiss_random_kernel (kiss_seed_1)) << 32; |
kiss1 += kiss_random_kernel (kiss_seed_2); |
|
kiss2 = ((GFC_UINTEGER_8) kiss_random_kernel (kiss_seed_3)) << 32; |
kiss2 += kiss_random_kernel (kiss_seed_3); |
|
rnumber_16 (dest, kiss1, kiss2); |
|
/* Advance to the next element. */ |
dest += stride0; |
count[0]++; |
/* Advance to the next source element. */ |
n = 0; |
while (count[n] == extent[n]) |
{ |
/* When we get to the end of a dimension, reset it and increment |
the next dimension. */ |
count[n] = 0; |
/* We could precalculate these products, but this is a less |
frequently used path so probably not worth it. */ |
dest -= stride[n] * extent[n]; |
n++; |
if (n == dim) |
{ |
dest = NULL; |
break; |
} |
else |
{ |
count[n]++; |
dest += stride[n]; |
} |
} |
} |
__gthread_mutex_unlock (&random_lock); |
} |
|
#endif |
|
|
|
static void |
scramble_seed (unsigned char *dest, unsigned char *src, int size) |
{ |
int i; |
|
for (i = 0; i < size; i++) |
dest[(i % 2) * (size / 2) + i / 2] = src[i]; |
} |
|
|
static void |
unscramble_seed (unsigned char *dest, unsigned char *src, int size) |
{ |
int i; |
|
for (i = 0; i < size; i++) |
dest[i] = src[(i % 2) * (size / 2) + i / 2]; |
} |
|
|
|
/* random_seed is used to seed the PRNG with either a default |
set of seeds or user specified set of seeds. random_seed |
must be called with no argument or exactly one argument. */ |
|
void |
random_seed_i4 (GFC_INTEGER_4 *size, gfc_array_i4 *put, gfc_array_i4 *get) |
{ |
int i; |
unsigned char seed[4*kiss_size]; |
|
__gthread_mutex_lock (&random_lock); |
|
/* Check that we only have one argument present. */ |
if ((size ? 1 : 0) + (put ? 1 : 0) + (get ? 1 : 0) > 1) |
runtime_error ("RANDOM_SEED should have at most one argument present."); |
|
/* From the standard: "If no argument is present, the processor assigns |
a processor-dependent value to the seed." */ |
if (size == NULL && put == NULL && get == NULL) |
for (i = 0; i < kiss_size; i++) |
kiss_seed[i] = kiss_default_seed[i]; |
|
if (size != NULL) |
*size = kiss_size; |
|
if (put != NULL) |
{ |
/* If the rank of the array is not 1, abort. */ |
if (GFC_DESCRIPTOR_RANK (put) != 1) |
runtime_error ("Array rank of PUT is not 1."); |
|
/* If the array is too small, abort. */ |
if (GFC_DESCRIPTOR_EXTENT(put,0) < kiss_size) |
runtime_error ("Array size of PUT is too small."); |
|
/* We copy the seed given by the user. */ |
for (i = 0; i < kiss_size; i++) |
memcpy (seed + i * sizeof(GFC_UINTEGER_4), |
&(put->data[(kiss_size - 1 - i) * GFC_DESCRIPTOR_STRIDE(put,0)]), |
sizeof(GFC_UINTEGER_4)); |
|
/* We put it after scrambling the bytes, to paper around users who |
provide seeds with quality only in the lower or upper part. */ |
scramble_seed ((unsigned char *) kiss_seed, seed, 4*kiss_size); |
} |
|
/* Return the seed to GET data. */ |
if (get != NULL) |
{ |
/* If the rank of the array is not 1, abort. */ |
if (GFC_DESCRIPTOR_RANK (get) != 1) |
runtime_error ("Array rank of GET is not 1."); |
|
/* If the array is too small, abort. */ |
if (GFC_DESCRIPTOR_EXTENT(get,0) < kiss_size) |
runtime_error ("Array size of GET is too small."); |
|
/* Unscramble the seed. */ |
unscramble_seed (seed, (unsigned char *) kiss_seed, 4*kiss_size); |
|
/* Then copy it back to the user variable. */ |
for (i = 0; i < kiss_size; i++) |
memcpy (&(get->data[(kiss_size - 1 - i) * GFC_DESCRIPTOR_STRIDE(get,0)]), |
seed + i * sizeof(GFC_UINTEGER_4), |
sizeof(GFC_UINTEGER_4)); |
} |
|
__gthread_mutex_unlock (&random_lock); |
} |
iexport(random_seed_i4); |
|
|
void |
random_seed_i8 (GFC_INTEGER_8 *size, gfc_array_i8 *put, gfc_array_i8 *get) |
{ |
int i; |
|
__gthread_mutex_lock (&random_lock); |
|
/* Check that we only have one argument present. */ |
if ((size ? 1 : 0) + (put ? 1 : 0) + (get ? 1 : 0) > 1) |
runtime_error ("RANDOM_SEED should have at most one argument present."); |
|
/* From the standard: "If no argument is present, the processor assigns |
a processor-dependent value to the seed." */ |
if (size == NULL && put == NULL && get == NULL) |
for (i = 0; i < kiss_size; i++) |
kiss_seed[i] = kiss_default_seed[i]; |
|
if (size != NULL) |
*size = kiss_size / 2; |
|
if (put != NULL) |
{ |
/* If the rank of the array is not 1, abort. */ |
if (GFC_DESCRIPTOR_RANK (put) != 1) |
runtime_error ("Array rank of PUT is not 1."); |
|
/* If the array is too small, abort. */ |
if (GFC_DESCRIPTOR_EXTENT(put,0) < kiss_size / 2) |
runtime_error ("Array size of PUT is too small."); |
|
/* This code now should do correct strides. */ |
for (i = 0; i < kiss_size / 2; i++) |
memcpy (&kiss_seed[2*i], &(put->data[i * GFC_DESCRIPTOR_STRIDE(put,0)]), |
sizeof (GFC_UINTEGER_8)); |
} |
|
/* Return the seed to GET data. */ |
if (get != NULL) |
{ |
/* If the rank of the array is not 1, abort. */ |
if (GFC_DESCRIPTOR_RANK (get) != 1) |
runtime_error ("Array rank of GET is not 1."); |
|
/* If the array is too small, abort. */ |
if (GFC_DESCRIPTOR_EXTENT(get,0) < kiss_size / 2) |
runtime_error ("Array size of GET is too small."); |
|
/* This code now should do correct strides. */ |
for (i = 0; i < kiss_size / 2; i++) |
memcpy (&(get->data[i * GFC_DESCRIPTOR_STRIDE(get,0)]), &kiss_seed[2*i], |
sizeof (GFC_UINTEGER_8)); |
} |
|
__gthread_mutex_unlock (&random_lock); |
} |
iexport(random_seed_i8); |
|
|
#ifndef __GTHREAD_MUTEX_INIT |
static void __attribute__((constructor)) |
init (void) |
{ |
__GTHREAD_MUTEX_INIT_FUNCTION (&random_lock); |
} |
#endif |
/rand.c
0,0 → 1,136
/* Implementation of the IRAND, RAND, and SRAND intrinsics. |
Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc. |
Contributed by Steven G. Kargl <kargls@comcast.net>. |
|
This file is part of the GNU Fortran 95 runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
/* Simple multiplicative congruent algorithm. |
The period of this generator is approximately 2^31-1, which means that |
it should not be used for anything serious. The implementation here |
is based of an algorithm from S.K. Park and K.W. Miller, Comm. ACM, |
31, 1192-1201 (1988). It is also provided solely for compatibility |
with G77. */ |
|
#include "libgfortran.h" |
#include <gthr.h> |
|
#define GFC_RAND_A 16807 |
#define GFC_RAND_M 2147483647 |
#define GFC_RAND_M1 (GFC_RAND_M - 1) |
|
static GFC_UINTEGER_8 rand_seed = 1; |
#ifdef __GTHREAD_MUTEX_INIT |
static __gthread_mutex_t rand_seed_lock = __GTHREAD_MUTEX_INIT; |
#else |
static __gthread_mutex_t rand_seed_lock; |
#endif |
|
|
/* Set the seed of the irand generator. Note 0 is a bad seed. */ |
|
static void |
srand_internal (GFC_INTEGER_8 i) |
{ |
rand_seed = i ? i : 123459876; |
} |
|
extern void PREFIX(srand) (GFC_INTEGER_4 *i); |
export_proto_np(PREFIX(srand)); |
|
void |
PREFIX(srand) (GFC_INTEGER_4 *i) |
{ |
__gthread_mutex_lock (&rand_seed_lock); |
srand_internal (*i); |
__gthread_mutex_unlock (&rand_seed_lock); |
} |
|
/* Return an INTEGER in the range [1,GFC_RAND_M-1]. */ |
|
extern GFC_INTEGER_4 irand (GFC_INTEGER_4 *); |
iexport_proto(irand); |
|
GFC_INTEGER_4 |
irand (GFC_INTEGER_4 *i) |
{ |
GFC_INTEGER_4 j; |
if (i) |
j = *i; |
else |
j = 0; |
|
__gthread_mutex_lock (&rand_seed_lock); |
|
switch (j) |
{ |
/* Return the next RN. */ |
case 0: |
break; |
|
/* Reset the RN sequence to system-dependent sequence and return the |
first value. */ |
case 1: |
srand_internal (0); |
break; |
|
/* Seed the RN sequence with j and return the first value. */ |
default: |
srand_internal (j); |
break; |
} |
|
rand_seed = GFC_RAND_A * rand_seed % GFC_RAND_M; |
j = (GFC_INTEGER_4) rand_seed; |
|
__gthread_mutex_unlock (&rand_seed_lock); |
|
return j; |
} |
iexport(irand); |
|
|
/* Return a random REAL in the range [0,1). */ |
|
extern GFC_REAL_4 PREFIX(rand) (GFC_INTEGER_4 *i); |
export_proto_np(PREFIX(rand)); |
|
GFC_REAL_4 |
PREFIX(rand) (GFC_INTEGER_4 *i) |
{ |
GFC_UINTEGER_4 mask; |
#if GFC_REAL_4_RADIX == 2 |
mask = ~ (GFC_UINTEGER_4) 0u << (32 - GFC_REAL_4_DIGITS + 1); |
#elif GFC_REAL_4_RADIX == 16 |
mask = ~ (GFC_UINTEGER_4) 0u << ((8 - GFC_REAL_4_DIGITS) * 4 + 1); |
#else |
#error "GFC_REAL_4_RADIX has unknown value" |
#endif |
return ((GFC_UINTEGER_4) (irand(i) -1) & mask) * (GFC_REAL_4) 0x1.p-31f; |
} |
|
#ifndef __GTHREAD_MUTEX_INIT |
static void __attribute__((constructor)) |
init (void) |
{ |
__GTHREAD_MUTEX_INIT_FUNCTION (&rand_seed_lock); |
} |
#endif |
/getXid.c
0,0 → 1,67
/* Wrapper for the unix get{g,p,u}id functions. |
Copyright (C) 2004, 2007, 2009 Free Software Foundation, Inc. |
|
This file is part of the GNU Fortran 95 runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
|
#if HAVE_UNISTD_H |
#include <unistd.h> |
#endif |
|
#ifdef __MINGW32__ |
#define HAVE_GETPID 1 |
#include <process.h> |
#endif |
|
#ifdef HAVE_GETGID |
extern GFC_INTEGER_4 PREFIX(getgid) (void); |
export_proto_np(PREFIX(getgid)); |
|
GFC_INTEGER_4 |
PREFIX(getgid) (void) |
{ |
return getgid (); |
} |
#endif |
|
#ifdef HAVE_GETPID |
extern GFC_INTEGER_4 PREFIX(getpid) (void); |
export_proto_np(PREFIX(getpid)); |
|
GFC_INTEGER_4 |
PREFIX(getpid) (void) |
{ |
return getpid (); |
} |
#endif |
|
#ifdef HAVE_GETUID |
extern GFC_INTEGER_4 PREFIX(getuid) (void); |
export_proto_np(PREFIX(getuid)); |
|
GFC_INTEGER_4 |
PREFIX(getuid) (void) |
{ |
return getuid (); |
} |
#endif |
/chdir.c
0,0 → 1,111
/* Implementation of the CHDIR intrinsic. |
Copyright (C) 2005, 2007, 2009 Free Software Foundation, Inc. |
Contributed by François-Xavier Coudert <coudert@clipper.ens.fr> |
|
This file is part of the GNU Fortran 95 runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
|
#include <errno.h> |
#include <string.h> |
|
#ifdef HAVE_UNISTD_H |
#include <unistd.h> |
#endif |
|
/* SUBROUTINE CHDIR(DIR, STATUS) |
CHARACTER(len=*), INTENT(IN) :: DIR |
INTEGER, INTENT(OUT), OPTIONAL :: STATUS */ |
|
#ifdef HAVE_CHDIR |
extern void chdir_i4_sub (char *, GFC_INTEGER_4 *, gfc_charlen_type); |
iexport_proto(chdir_i4_sub); |
|
void |
chdir_i4_sub (char *dir, GFC_INTEGER_4 *status, gfc_charlen_type dir_len) |
{ |
int val; |
char *str; |
|
/* Trim trailing spaces from paths. */ |
while (dir_len > 0 && dir[dir_len - 1] == ' ') |
dir_len--; |
|
/* Make a null terminated copy of the strings. */ |
str = gfc_alloca (dir_len + 1); |
memcpy (str, dir, dir_len); |
str[dir_len] = '\0'; |
|
val = chdir (str); |
|
if (status != NULL) |
*status = (val == 0) ? 0 : errno; |
} |
iexport(chdir_i4_sub); |
|
extern void chdir_i8_sub (char *, GFC_INTEGER_8 *, gfc_charlen_type); |
iexport_proto(chdir_i8_sub); |
|
void |
chdir_i8_sub (char *dir, GFC_INTEGER_8 *status, gfc_charlen_type dir_len) |
{ |
int val; |
char *str; |
|
/* Trim trailing spaces from paths. */ |
while (dir_len > 0 && dir[dir_len - 1] == ' ') |
dir_len--; |
|
/* Make a null terminated copy of the strings. */ |
str = gfc_alloca (dir_len + 1); |
memcpy (str, dir, dir_len); |
str[dir_len] = '\0'; |
|
val = chdir (str); |
|
if (status != NULL) |
*status = (val == 0) ? 0 : errno; |
} |
iexport(chdir_i8_sub); |
|
extern GFC_INTEGER_4 chdir_i4 (char *, gfc_charlen_type); |
export_proto(chdir_i4); |
|
GFC_INTEGER_4 |
chdir_i4 (char *dir, gfc_charlen_type dir_len) |
{ |
GFC_INTEGER_4 val; |
chdir_i4_sub (dir, &val, dir_len); |
return val; |
} |
|
extern GFC_INTEGER_8 chdir_i8 (char *, gfc_charlen_type); |
export_proto(chdir_i8); |
|
GFC_INTEGER_8 |
chdir_i8 (char *dir, gfc_charlen_type dir_len) |
{ |
GFC_INTEGER_8 val; |
chdir_i8_sub (dir, &val, dir_len); |
return val; |
} |
#endif |
/clock.c
0,0 → 1,52
/* Implementation of the MCLOCK and MCLOCK8 g77 intrinsics. |
Copyright (C) 2006, 2007, 2009, 2011 Free Software Foundation, Inc. |
Contributed by François-Xavier Coudert <coudert@clipper.ens.fr> |
|
This file is part of the GNU Fortran runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
#include <time.h> |
|
|
/* INTEGER(KIND=4) FUNCTION MCLOCK() */ |
|
extern GFC_INTEGER_4 mclock (void); |
export_proto(mclock); |
|
GFC_INTEGER_4 |
mclock (void) |
{ |
return (GFC_INTEGER_4) clock (); |
} |
|
|
/* INTEGER(KIND=8) FUNCTION MCLOCK8() */ |
|
extern GFC_INTEGER_8 mclock8 (void); |
export_proto(mclock8); |
|
GFC_INTEGER_8 |
mclock8 (void) |
{ |
return (GFC_INTEGER_8) clock (); |
} |
|
/args.c
0,0 → 1,270
/* Implementation of the GETARG and IARGC g77, and |
corresponding F2003, intrinsics. |
Copyright (C) 2004, 2005, 2007, 2009, 2010 |
Free Software Foundation, Inc. |
Contributed by Bud Davis and Janne Blomqvist. |
|
This file is part of the GNU Fortran 95 runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
#include <string.h> |
|
|
/* Get a commandline argument. */ |
|
extern void getarg_i4 (GFC_INTEGER_4 *, char *, gfc_charlen_type); |
iexport_proto(getarg_i4); |
|
void |
getarg_i4 (GFC_INTEGER_4 *pos, char *val, gfc_charlen_type val_len) |
{ |
int argc; |
int arglen; |
char **argv; |
|
get_args (&argc, &argv); |
|
if (val_len < 1 || !val ) |
return; /* something is wrong , leave immediately */ |
|
memset (val, ' ', val_len); |
|
if ((*pos) + 1 <= argc && *pos >=0 ) |
{ |
arglen = strlen (argv[*pos]); |
if (arglen > val_len) |
arglen = val_len; |
memcpy (val, argv[*pos], arglen); |
} |
} |
iexport(getarg_i4); |
|
|
/* INTEGER*8 wrapper of getarg. */ |
|
extern void getarg_i8 (GFC_INTEGER_8 *, char *, gfc_charlen_type); |
export_proto (getarg_i8); |
|
void |
getarg_i8 (GFC_INTEGER_8 *pos, char *val, gfc_charlen_type val_len) |
{ |
GFC_INTEGER_4 pos4 = (GFC_INTEGER_4) *pos; |
getarg_i4 (&pos4, val, val_len); |
} |
|
|
/* Return the number of commandline arguments. The g77 info page |
states that iargc does not include the specification of the |
program name itself. */ |
|
extern GFC_INTEGER_4 iargc (void); |
export_proto(iargc); |
|
GFC_INTEGER_4 |
iargc (void) |
{ |
int argc; |
char **argv; |
|
get_args (&argc, &argv); |
|
return (argc - 1); |
} |
|
|
/* F2003 intrinsic functions and subroutines related to command line |
arguments. |
|
- function command_argument_count() is converted to iargc by the compiler. |
|
- subroutine get_command([command, length, status]). |
|
- subroutine get_command_argument(number, [value, length, status]). |
*/ |
|
/* These two status codes are specified in the standard. */ |
#define GFC_GC_SUCCESS 0 |
#define GFC_GC_VALUE_TOO_SHORT -1 |
|
/* Processor-specific status failure code. */ |
#define GFC_GC_FAILURE 42 |
|
|
extern void get_command_argument_i4 (GFC_INTEGER_4 *, char *, GFC_INTEGER_4 *, |
GFC_INTEGER_4 *, gfc_charlen_type); |
iexport_proto(get_command_argument_i4); |
|
/* Get a single commandline argument. */ |
|
void |
get_command_argument_i4 (GFC_INTEGER_4 *number, char *value, |
GFC_INTEGER_4 *length, GFC_INTEGER_4 *status, |
gfc_charlen_type value_len) |
{ |
int argc, arglen = 0, stat_flag = GFC_GC_SUCCESS; |
char **argv; |
|
if (number == NULL ) |
/* Should never happen. */ |
runtime_error ("Missing argument to get_command_argument"); |
|
if (value == NULL && length == NULL && status == NULL) |
return; /* No need to do anything. */ |
|
get_args (&argc, &argv); |
|
if (*number < 0 || *number >= argc) |
stat_flag = GFC_GC_FAILURE; |
else |
arglen = strlen(argv[*number]); |
|
if (value != NULL) |
{ |
if (value_len < 1) |
stat_flag = GFC_GC_FAILURE; |
else |
memset (value, ' ', value_len); |
} |
|
if (value != NULL && stat_flag != GFC_GC_FAILURE) |
{ |
if (arglen > value_len) |
stat_flag = GFC_GC_VALUE_TOO_SHORT; |
|
memcpy (value, argv[*number], arglen <= value_len ? arglen : value_len); |
} |
|
if (length != NULL) |
*length = arglen; |
|
if (status != NULL) |
*status = stat_flag; |
} |
iexport(get_command_argument_i4); |
|
|
/* INTEGER*8 wrapper for get_command_argument. */ |
|
extern void get_command_argument_i8 (GFC_INTEGER_8 *, char *, GFC_INTEGER_8 *, |
GFC_INTEGER_8 *, gfc_charlen_type); |
export_proto(get_command_argument_i8); |
|
void |
get_command_argument_i8 (GFC_INTEGER_8 *number, char *value, |
GFC_INTEGER_8 *length, GFC_INTEGER_8 *status, |
gfc_charlen_type value_len) |
{ |
GFC_INTEGER_4 number4; |
GFC_INTEGER_4 length4; |
GFC_INTEGER_4 status4; |
|
number4 = (GFC_INTEGER_4) *number; |
get_command_argument_i4 (&number4, value, &length4, &status4, value_len); |
if (length) |
*length = length4; |
if (status) |
*status = status4; |
} |
|
|
/* Return the whole commandline. */ |
|
extern void get_command_i4 (char *, GFC_INTEGER_4 *, GFC_INTEGER_4 *, |
gfc_charlen_type); |
iexport_proto(get_command_i4); |
|
void |
get_command_i4 (char *command, GFC_INTEGER_4 *length, GFC_INTEGER_4 *status, |
gfc_charlen_type command_len) |
{ |
int i, argc, arglen, thisarg; |
int stat_flag = GFC_GC_SUCCESS; |
int tot_len = 0; |
char **argv; |
|
if (command == NULL && length == NULL && status == NULL) |
return; /* No need to do anything. */ |
|
get_args (&argc, &argv); |
|
if (command != NULL) |
{ |
/* Initialize the string to blanks. */ |
if (command_len < 1) |
stat_flag = GFC_GC_FAILURE; |
else |
memset (command, ' ', command_len); |
} |
|
for (i = 0; i < argc ; i++) |
{ |
arglen = strlen(argv[i]); |
|
if (command != NULL && stat_flag == GFC_GC_SUCCESS) |
{ |
thisarg = arglen; |
if (tot_len + thisarg > command_len) |
{ |
thisarg = command_len - tot_len; /* Truncate. */ |
stat_flag = GFC_GC_VALUE_TOO_SHORT; |
} |
/* Also a space before the next arg. */ |
else if (i != argc - 1 && tot_len + arglen == command_len) |
stat_flag = GFC_GC_VALUE_TOO_SHORT; |
|
memcpy (&command[tot_len], argv[i], thisarg); |
} |
|
/* Add the legth of the argument. */ |
tot_len += arglen; |
if (i != argc - 1) |
tot_len++; |
} |
|
if (length != NULL) |
*length = tot_len; |
|
if (status != NULL) |
*status = stat_flag; |
} |
iexport(get_command_i4); |
|
|
/* INTEGER*8 wrapper for get_command. */ |
|
extern void get_command_i8 (char *, GFC_INTEGER_8 *, GFC_INTEGER_8 *, |
gfc_charlen_type); |
export_proto(get_command_i8); |
|
void |
get_command_i8 (char *command, GFC_INTEGER_8 *length, GFC_INTEGER_8 *status, |
gfc_charlen_type command_len) |
{ |
GFC_INTEGER_4 length4; |
GFC_INTEGER_4 status4; |
|
get_command_i4 (command, &length4, &status4, command_len); |
if (length) |
*length = length4; |
if (status) |
*status = status4; |
} |
/link.c
0,0 → 1,131
/* Implementation of the LINK intrinsic. |
Copyright (C) 2005, 2007, 2009 Free Software Foundation, Inc. |
Contributed by François-Xavier Coudert <coudert@clipper.ens.fr> |
|
This file is part of the GNU Fortran 95 runtime library (libgfortran). |
|
Libgfortran is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public |
License as published by the Free Software Foundation; either |
version 3 of the License, or (at your option) any later version. |
|
Libgfortran is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
|
Under Section 7 of GPL version 3, you are granted additional |
permissions described in the GCC Runtime Library Exception, version |
3.1, as published by the Free Software Foundation. |
|
You should have received a copy of the GNU General Public License and |
a copy of the GCC Runtime Library Exception along with this program; |
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
<http://www.gnu.org/licenses/>. */ |
|
#include "libgfortran.h" |
|
#include <errno.h> |
#include <string.h> |
|
#ifdef HAVE_UNISTD_H |
#include <unistd.h> |
#endif |
|
/* SUBROUTINE LINK(PATH1, PATH2, STATUS) |
CHARACTER(len=*), INTENT(IN) :: PATH1, PATH2 |
INTEGER, INTENT(OUT), OPTIONAL :: STATUS */ |
|
#ifdef HAVE_LINK |
extern void link_i4_sub (char *, char *, GFC_INTEGER_4 *, gfc_charlen_type, |
gfc_charlen_type); |
iexport_proto(link_i4_sub); |
|
void |
link_i4_sub (char *path1, char *path2, GFC_INTEGER_4 *status, |
gfc_charlen_type path1_len, gfc_charlen_type path2_len) |
{ |
int val; |
char *str1, *str2; |
|
/* Trim trailing spaces from paths. */ |
while (path1_len > 0 && path1[path1_len - 1] == ' ') |
path1_len--; |
while (path2_len > 0 && path2[path2_len - 1] == ' ') |
path2_len--; |
|
/* Make a null terminated copy of the strings. */ |
str1 = gfc_alloca (path1_len + 1); |
memcpy (str1, path1, path1_len); |
str1[path1_len] = '\0'; |
|
str2 = gfc_alloca (path2_len + 1); |
memcpy (str2, path2, path2_len); |
str2[path2_len] = '\0'; |
|
val = link (str1, str2); |
|
if (status != NULL) |
*status = (val == 0) ? 0 : errno; |
} |
iexport(link_i4_sub); |
|
extern void link_i8_sub (char *, char *, GFC_INTEGER_8 *, gfc_charlen_type, |
gfc_charlen_type); |
iexport_proto(link_i8_sub); |
|
void |
link_i8_sub (char *path1, char *path2, GFC_INTEGER_8 *status, |
gfc_charlen_type path1_len, gfc_charlen_type path2_len) |
{ |
int val; |
char *str1, *str2; |
|
/* Trim trailing spaces from paths. */ |
while (path1_len > 0 && path1[path1_len - 1] == ' ') |
path1_len--; |
while (path2_len > 0 && path2[path2_len - 1] == ' ') |
path2_len--; |
|
/* Make a null terminated copy of the strings. */ |
str1 = gfc_alloca (path1_len + 1); |
memcpy (str1, path1, path1_len); |
str1[path1_len] = '\0'; |
|
str2 = gfc_alloca (path2_len + 1); |
memcpy (str2, path2, path2_len); |
str2[path2_len] = '\0'; |
|
val = link (str1, str2); |
|
if (status != NULL) |
*status = (val == 0) ? 0 : errno; |
} |
iexport(link_i8_sub); |
|
extern GFC_INTEGER_4 link_i4 (char *, char *, gfc_charlen_type, |
gfc_charlen_type); |
export_proto(link_i4); |
|
GFC_INTEGER_4 |
link_i4 (char *path1, char *path2, gfc_charlen_type path1_len, |
gfc_charlen_type path2_len) |
{ |
GFC_INTEGER_4 val; |
link_i4_sub (path1, path2, &val, path1_len, path2_len); |
return val; |
} |
|
extern GFC_INTEGER_8 link_i8 (char *, char *, gfc_charlen_type, |
gfc_charlen_type); |
export_proto(link_i8); |
|
GFC_INTEGER_8 |
link_i8 (char *path1, char *path2, gfc_charlen_type path1_len, |
gfc_charlen_type path2_len) |
{ |
GFC_INTEGER_8 val; |
link_i8_sub (path1, path2, &val, path1_len, path2_len); |
return val; |
} |
#endif |