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/runtime
- from Rev 733 to Rev 783
- ↔ Reverse comparison
Rev 733 → Rev 783
/in_pack_generic.c
0,0 → 1,218
/* Generic helper function for repacking arrays. |
Copyright 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. |
|
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> |
|
extern void *internal_pack (gfc_array_char *); |
export_proto(internal_pack); |
|
void * |
internal_pack (gfc_array_char * source) |
{ |
index_type count[GFC_MAX_DIMENSIONS]; |
index_type extent[GFC_MAX_DIMENSIONS]; |
index_type stride[GFC_MAX_DIMENSIONS]; |
index_type stride0; |
index_type dim; |
index_type ssize; |
const char *src; |
char *dest; |
void *destptr; |
int n; |
int packed; |
index_type size; |
index_type type_size; |
|
type_size = GFC_DTYPE_TYPE_SIZE(source); |
size = GFC_DESCRIPTOR_SIZE (source); |
switch (type_size) |
{ |
case GFC_DTYPE_INTEGER_1: |
case GFC_DTYPE_LOGICAL_1: |
case GFC_DTYPE_DERIVED_1: |
return internal_pack_1 ((gfc_array_i1 *) source); |
|
case GFC_DTYPE_INTEGER_2: |
case GFC_DTYPE_LOGICAL_2: |
return internal_pack_2 ((gfc_array_i2 *) source); |
|
case GFC_DTYPE_INTEGER_4: |
case GFC_DTYPE_LOGICAL_4: |
return internal_pack_4 ((gfc_array_i4 *) source); |
|
case GFC_DTYPE_INTEGER_8: |
case GFC_DTYPE_LOGICAL_8: |
return internal_pack_8 ((gfc_array_i8 *) source); |
|
#if defined(HAVE_GFC_INTEGER_16) |
case GFC_DTYPE_INTEGER_16: |
case GFC_DTYPE_LOGICAL_16: |
return internal_pack_16 ((gfc_array_i16 *) source); |
#endif |
case GFC_DTYPE_REAL_4: |
return internal_pack_r4 ((gfc_array_r4 *) source); |
|
case GFC_DTYPE_REAL_8: |
return internal_pack_r8 ((gfc_array_r8 *) source); |
|
/* 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) |
# if defined (HAVE_GFC_REAL_10) |
case GFC_DTYPE_REAL_10: |
return internal_pack_r10 ((gfc_array_r10 *) source); |
# endif |
|
# if defined (HAVE_GFC_REAL_16) |
case GFC_DTYPE_REAL_16: |
return internal_pack_r16 ((gfc_array_r16 *) source); |
# endif |
#endif |
|
case GFC_DTYPE_COMPLEX_4: |
return internal_pack_c4 ((gfc_array_c4 *) source); |
|
case GFC_DTYPE_COMPLEX_8: |
return internal_pack_c8 ((gfc_array_c8 *) source); |
|
/* 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) |
# if defined (HAVE_GFC_COMPLEX_10) |
case GFC_DTYPE_COMPLEX_10: |
return internal_pack_c10 ((gfc_array_c10 *) source); |
# endif |
|
# if defined (HAVE_GFC_COMPLEX_16) |
case GFC_DTYPE_COMPLEX_16: |
return internal_pack_c16 ((gfc_array_c16 *) source); |
# endif |
#endif |
|
case GFC_DTYPE_DERIVED_2: |
if (GFC_UNALIGNED_2(source->data)) |
break; |
else |
return internal_pack_2 ((gfc_array_i2 *) source); |
|
case GFC_DTYPE_DERIVED_4: |
if (GFC_UNALIGNED_4(source->data)) |
break; |
else |
return internal_pack_4 ((gfc_array_i4 *) source); |
|
case GFC_DTYPE_DERIVED_8: |
if (GFC_UNALIGNED_8(source->data)) |
break; |
else |
return internal_pack_8 ((gfc_array_i8 *) source); |
|
#ifdef HAVE_GFC_INTEGER_16 |
case GFC_DTYPE_DERIVED_16: |
if (GFC_UNALIGNED_16(source->data)) |
break; |
else |
return internal_pack_16 ((gfc_array_i16 *) source); |
#endif |
|
default: |
break; |
} |
|
dim = GFC_DESCRIPTOR_RANK (source); |
ssize = 1; |
packed = 1; |
for (n = 0; n < dim; n++) |
{ |
count[n] = 0; |
stride[n] = GFC_DESCRIPTOR_STRIDE(source,n); |
extent[n] = GFC_DESCRIPTOR_EXTENT(source,n); |
if (extent[n] <= 0) |
{ |
/* Do nothing. */ |
packed = 1; |
break; |
} |
|
if (ssize != stride[n]) |
packed = 0; |
|
ssize *= extent[n]; |
} |
|
if (packed) |
return source->data; |
|
/* Allocate storage for the destination. */ |
destptr = internal_malloc_size (ssize * size); |
dest = (char *)destptr; |
src = source->data; |
stride0 = stride[0] * size; |
|
while (src) |
{ |
/* Copy the data. */ |
memcpy(dest, src, size); |
/* Advance to the next element. */ |
dest += size; |
src += 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. */ |
src -= stride[n] * extent[n] * size; |
n++; |
if (n == dim) |
{ |
src = NULL; |
break; |
} |
else |
{ |
count[n]++; |
src += stride[n] * size; |
} |
} |
} |
return destptr; |
} |
/in_unpack_generic.c
0,0 → 1,242
/* Generic helper function for repacking arrays. |
Copyright 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. |
|
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> |
|
extern void internal_unpack (gfc_array_char *, const void *); |
export_proto(internal_unpack); |
|
void |
internal_unpack (gfc_array_char * d, const void * s) |
{ |
index_type count[GFC_MAX_DIMENSIONS]; |
index_type extent[GFC_MAX_DIMENSIONS]; |
index_type stride[GFC_MAX_DIMENSIONS]; |
index_type stride0; |
index_type dim; |
index_type dsize; |
char *dest; |
const char *src; |
int n; |
int size; |
int type_size; |
|
dest = d->data; |
/* This check may be redundant, but do it anyway. */ |
if (s == dest || !s) |
return; |
|
type_size = GFC_DTYPE_TYPE_SIZE (d); |
switch (type_size) |
{ |
case GFC_DTYPE_INTEGER_1: |
case GFC_DTYPE_LOGICAL_1: |
case GFC_DTYPE_DERIVED_1: |
internal_unpack_1 ((gfc_array_i1 *) d, (const GFC_INTEGER_1 *) s); |
return; |
|
case GFC_DTYPE_INTEGER_2: |
case GFC_DTYPE_LOGICAL_2: |
internal_unpack_2 ((gfc_array_i2 *) d, (const GFC_INTEGER_2 *) s); |
return; |
|
case GFC_DTYPE_INTEGER_4: |
case GFC_DTYPE_LOGICAL_4: |
internal_unpack_4 ((gfc_array_i4 *) d, (const GFC_INTEGER_4 *) s); |
return; |
|
case GFC_DTYPE_INTEGER_8: |
case GFC_DTYPE_LOGICAL_8: |
internal_unpack_8 ((gfc_array_i8 *) d, (const GFC_INTEGER_8 *) s); |
return; |
|
#if defined (HAVE_GFC_INTEGER_16) |
case GFC_DTYPE_INTEGER_16: |
case GFC_DTYPE_LOGICAL_16: |
internal_unpack_16 ((gfc_array_i16 *) d, (const GFC_INTEGER_16 *) s); |
return; |
#endif |
|
case GFC_DTYPE_REAL_4: |
internal_unpack_r4 ((gfc_array_r4 *) d, (const GFC_REAL_4 *) s); |
return; |
|
case GFC_DTYPE_REAL_8: |
internal_unpack_r8 ((gfc_array_r8 *) d, (const GFC_REAL_8 *) s); |
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) |
# if defined(HAVE_GFC_REAL_10) |
case GFC_DTYPE_REAL_10: |
internal_unpack_r10 ((gfc_array_r10 *) d, (const GFC_REAL_10 *) s); |
return; |
# endif |
|
# if defined(HAVE_GFC_REAL_16) |
case GFC_DTYPE_REAL_16: |
internal_unpack_r16 ((gfc_array_r16 *) d, (const GFC_REAL_16 *) s); |
return; |
# endif |
#endif |
|
case GFC_DTYPE_COMPLEX_4: |
internal_unpack_c4 ((gfc_array_c4 *)d, (const GFC_COMPLEX_4 *)s); |
return; |
|
case GFC_DTYPE_COMPLEX_8: |
internal_unpack_c8 ((gfc_array_c8 *)d, (const GFC_COMPLEX_8 *)s); |
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) |
# if defined(HAVE_GFC_COMPLEX_10) |
case GFC_DTYPE_COMPLEX_10: |
internal_unpack_c10 ((gfc_array_c10 *) d, (const GFC_COMPLEX_10 *) s); |
return; |
# endif |
|
# if defined(HAVE_GFC_COMPLEX_16) |
case GFC_DTYPE_COMPLEX_16: |
internal_unpack_c16 ((gfc_array_c16 *) d, (const GFC_COMPLEX_16 *) s); |
return; |
# endif |
#endif |
|
case GFC_DTYPE_DERIVED_2: |
if (GFC_UNALIGNED_2(d->data) || GFC_UNALIGNED_2(s)) |
break; |
else |
{ |
internal_unpack_2 ((gfc_array_i2 *) d, (const GFC_INTEGER_2 *) s); |
return; |
} |
case GFC_DTYPE_DERIVED_4: |
if (GFC_UNALIGNED_4(d->data) || GFC_UNALIGNED_4(s)) |
break; |
else |
{ |
internal_unpack_4 ((gfc_array_i4 *) d, (const GFC_INTEGER_4 *) s); |
return; |
} |
|
case GFC_DTYPE_DERIVED_8: |
if (GFC_UNALIGNED_8(d->data) || GFC_UNALIGNED_8(s)) |
break; |
else |
{ |
internal_unpack_8 ((gfc_array_i8 *) d, (const GFC_INTEGER_8 *) s); |
return; |
} |
|
#ifdef HAVE_GFC_INTEGER_16 |
case GFC_DTYPE_DERIVED_16: |
if (GFC_UNALIGNED_16(d->data) || GFC_UNALIGNED_16(s)) |
break; |
else |
{ |
internal_unpack_16 ((gfc_array_i16 *) d, (const GFC_INTEGER_16 *) s); |
return; |
} |
#endif |
|
default: |
break; |
} |
|
size = GFC_DESCRIPTOR_SIZE (d); |
|
dim = GFC_DESCRIPTOR_RANK (d); |
dsize = 1; |
for (n = 0; n < dim; n++) |
{ |
count[n] = 0; |
stride[n] = GFC_DESCRIPTOR_STRIDE(d,n); |
extent[n] = GFC_DESCRIPTOR_EXTENT(d,n); |
if (extent[n] <= 0) |
return; |
|
if (dsize == stride[n]) |
dsize *= extent[n]; |
else |
dsize = 0; |
} |
|
src = s; |
|
if (dsize != 0) |
{ |
memcpy (dest, src, dsize * size); |
return; |
} |
|
stride0 = stride[0] * size; |
|
while (dest) |
{ |
/* Copy the data. */ |
memcpy (dest, src, size); |
/* Advance to the next element. */ |
src += size; |
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] * size; |
n++; |
if (n == dim) |
{ |
dest = NULL; |
break; |
} |
else |
{ |
count[n]++; |
dest += stride[n] * size; |
} |
} |
} |
} |
/compile_options.c
0,0 → 1,277
/* Handling of compile-time options that influence the library. |
Copyright (C) 2005, 2007, 2009, 2010, 2011, 2012 |
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, 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 <signal.h> |
|
|
/* Useful compile-time options will be stored in here. */ |
compile_options_t compile_options; |
|
|
volatile sig_atomic_t fatal_error_in_progress = 0; |
|
|
/* Helper function for backtrace_handler to write information about the |
received signal to stderr before actually giving the backtrace. */ |
static void |
show_signal (int signum) |
{ |
const char * name = NULL, * desc = NULL; |
|
switch (signum) |
{ |
#if defined(SIGQUIT) |
case SIGQUIT: |
name = "SIGQUIT"; |
desc = "Terminal quit signal"; |
break; |
#endif |
|
/* The following 4 signals are defined by C89. */ |
case SIGILL: |
name = "SIGILL"; |
desc = "Illegal instruction"; |
break; |
|
case SIGABRT: |
name = "SIGABRT"; |
desc = "Process abort signal"; |
break; |
|
case SIGFPE: |
name = "SIGFPE"; |
desc = "Floating-point exception - erroneous arithmetic operation"; |
break; |
|
case SIGSEGV: |
name = "SIGSEGV"; |
desc = "Segmentation fault - invalid memory reference"; |
break; |
|
#if defined(SIGBUS) |
case SIGBUS: |
name = "SIGBUS"; |
desc = "Access to an undefined portion of a memory object"; |
break; |
#endif |
|
#if defined(SIGSYS) |
case SIGSYS: |
name = "SIGSYS"; |
desc = "Bad system call"; |
break; |
#endif |
|
#if defined(SIGTRAP) |
case SIGTRAP: |
name = "SIGTRAP"; |
desc = "Trace/breakpoint trap"; |
break; |
#endif |
|
#if defined(SIGXCPU) |
case SIGXCPU: |
name = "SIGXCPU"; |
desc = "CPU time limit exceeded"; |
break; |
#endif |
|
#if defined(SIGXFSZ) |
case SIGXFSZ: |
name = "SIGXFSZ"; |
desc = "File size limit exceeded"; |
break; |
#endif |
} |
|
if (name) |
st_printf ("\nProgram received signal %s: %s.\n", name, desc); |
else |
st_printf ("\nProgram received signal %d.\n", signum); |
} |
|
|
/* A signal handler to allow us to output a backtrace. */ |
void |
backtrace_handler (int signum) |
{ |
/* Since this handler is established for more than one kind of signal, |
it might still get invoked recursively by delivery of some other kind |
of signal. Use a static variable to keep track of that. */ |
if (fatal_error_in_progress) |
raise (signum); |
fatal_error_in_progress = 1; |
|
show_signal (signum); |
show_backtrace(); |
|
/* Now reraise the signal. We reactivate the signal's |
default handling, which is to terminate the process. |
We could just call exit or abort, |
but reraising the signal sets the return status |
from the process correctly. */ |
signal (signum, SIG_DFL); |
raise (signum); |
} |
|
|
/* Helper function for set_options because we need to access the |
global variable options which is not seen in set_options. */ |
static void |
maybe_find_addr2line (void) |
{ |
if (options.backtrace == -1) |
find_addr2line (); |
} |
|
/* Set the usual compile-time options. */ |
extern void set_options (int , int []); |
export_proto(set_options); |
|
void |
set_options (int num, int options[]) |
{ |
if (num >= 1) |
compile_options.warn_std = options[0]; |
if (num >= 2) |
compile_options.allow_std = options[1]; |
if (num >= 3) |
compile_options.pedantic = options[2]; |
/* options[3] is the removed -fdump-core option. It's place in the |
options array is retained due to ABI compatibility. Remove when |
bumping the library ABI. */ |
if (num >= 5) |
compile_options.backtrace = options[4]; |
if (num >= 6) |
compile_options.sign_zero = options[5]; |
if (num >= 7) |
compile_options.bounds_check = options[6]; |
if (num >= 8) |
compile_options.range_check = options[7]; |
|
/* If backtrace is required, we set signal handlers on the POSIX |
2001 signals with core action. */ |
if (compile_options.backtrace) |
{ |
#if defined(SIGQUIT) |
signal (SIGQUIT, backtrace_handler); |
#endif |
|
/* The following 4 signals are defined by C89. */ |
signal (SIGILL, backtrace_handler); |
signal (SIGABRT, backtrace_handler); |
signal (SIGFPE, backtrace_handler); |
signal (SIGSEGV, backtrace_handler); |
|
#if defined(SIGBUS) |
signal (SIGBUS, backtrace_handler); |
#endif |
|
#if defined(SIGSYS) |
signal (SIGSYS, backtrace_handler); |
#endif |
|
#if defined(SIGTRAP) |
signal (SIGTRAP, backtrace_handler); |
#endif |
|
#if defined(SIGXCPU) |
signal (SIGXCPU, backtrace_handler); |
#endif |
|
#if defined(SIGXFSZ) |
signal (SIGXFSZ, backtrace_handler); |
#endif |
|
maybe_find_addr2line (); |
} |
} |
|
|
/* Default values for the compile-time options. Keep in sync with |
gcc/fortran/options.c (gfc_init_options). */ |
void |
init_compile_options (void) |
{ |
compile_options.warn_std = GFC_STD_F95_DEL | GFC_STD_LEGACY; |
compile_options.allow_std = GFC_STD_F95_OBS | GFC_STD_F95_DEL |
| GFC_STD_F2003 | GFC_STD_F2008 | GFC_STD_F95 | GFC_STD_F77 |
| GFC_STD_F2008_OBS | GFC_STD_GNU | GFC_STD_LEGACY; |
compile_options.pedantic = 0; |
compile_options.backtrace = 0; |
compile_options.sign_zero = 1; |
compile_options.range_check = 1; |
} |
|
/* Function called by the front-end to tell us the |
default for unformatted data conversion. */ |
|
extern void set_convert (int); |
export_proto (set_convert); |
|
void |
set_convert (int conv) |
{ |
compile_options.convert = conv; |
} |
|
extern void set_record_marker (int); |
export_proto (set_record_marker); |
|
|
void |
set_record_marker (int val) |
{ |
|
switch(val) |
{ |
case 4: |
compile_options.record_marker = sizeof (GFC_INTEGER_4); |
break; |
|
case 8: |
compile_options.record_marker = sizeof (GFC_INTEGER_8); |
break; |
|
default: |
runtime_error ("Invalid value for record marker"); |
break; |
} |
} |
|
extern void set_max_subrecord_length (int); |
export_proto (set_max_subrecord_length); |
|
void set_max_subrecord_length(int val) |
{ |
if (val > GFC_MAX_SUBRECORD_LENGTH || val < 1) |
{ |
runtime_error ("Invalid value for maximum subrecord length"); |
return; |
} |
|
compile_options.max_subrecord_length = val; |
} |
/string.c
0,0 → 1,112
/* Copyright (C) 2002, 2003, 2005, 2007, 2009, 2010 |
Free Software Foundation, Inc. |
Contributed by Paul Brook |
|
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/>. */ |
|
#include "libgfortran.h" |
#include <string.h> |
|
|
/* Given a fortran string, return its length exclusive of the trailing |
spaces. */ |
|
gfc_charlen_type |
fstrlen (const char *string, gfc_charlen_type len) |
{ |
for (; len > 0; len--) |
if (string[len-1] != ' ') |
break; |
|
return len; |
} |
|
|
/* Copy a Fortran string (not null-terminated, hence length arguments |
for both source and destination strings. Returns the non-padded |
length of the destination. */ |
|
gfc_charlen_type |
fstrcpy (char *dest, gfc_charlen_type destlen, |
const char *src, gfc_charlen_type srclen) |
{ |
if (srclen >= destlen) |
{ |
/* This will truncate if too long. */ |
memcpy (dest, src, destlen); |
return destlen; |
} |
else |
{ |
memcpy (dest, src, srclen); |
/* Pad with spaces. */ |
memset (&dest[srclen], ' ', destlen - srclen); |
return srclen; |
} |
} |
|
|
/* Copy a null-terminated C string to a non-null-terminated Fortran |
string. Returns the non-padded length of the destination string. */ |
|
gfc_charlen_type |
cf_strcpy (char *dest, gfc_charlen_type dest_len, const char *src) |
{ |
size_t src_len; |
|
src_len = strlen (src); |
|
if (src_len >= (size_t) dest_len) |
{ |
/* This will truncate if too long. */ |
memcpy (dest, src, dest_len); |
return dest_len; |
} |
else |
{ |
memcpy (dest, src, src_len); |
/* Pad with spaces. */ |
memset (&dest[src_len], ' ', dest_len - src_len); |
return src_len; |
} |
} |
|
|
/* Given a fortran string and an array of st_option structures, search through |
the array to find a match. If the option is not found, we generate an error |
if no default is provided. */ |
|
int |
find_option (st_parameter_common *cmp, const char *s1, gfc_charlen_type s1_len, |
const st_option * opts, const char *error_message) |
{ |
/* Strip trailing blanks from the Fortran string. */ |
size_t len = (size_t) fstrlen (s1, s1_len); |
|
for (; opts->name; opts++) |
if (len == strlen(opts->name) && strncasecmp (s1, opts->name, len) == 0) |
return opts->value; |
|
generate_error (cmp, LIBERROR_BAD_OPTION, error_message); |
|
return -1; |
} |
/memory.c
0,0 → 1,61
/* Memory management routines. |
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 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> |
|
/* If GFC_CLEAR_MEMORY is defined, the memory allocation routines will |
return memory that is guaranteed to be set to zero. This can have |
a severe efficiency penalty, so it should never be set if good |
performance is desired, but it can help when you're debugging code. */ |
/* #define GFC_CLEAR_MEMORY */ |
|
void * |
get_mem (size_t n) |
{ |
void *p; |
|
#ifdef GFC_CLEAR_MEMORY |
p = (void *) calloc (1, n); |
#else |
p = (void *) malloc (n); |
#endif |
if (p == NULL) |
os_error ("Memory allocation failed"); |
|
return p; |
} |
|
|
/* Allocate memory for internal (compiler generated) use. */ |
|
void * |
internal_malloc_size (size_t size) |
{ |
if (unlikely (size == 0)) |
size = 1; |
|
return get_mem (size); |
} |
/select_inc.c
0,0 → 1,133
/* Implement the SELECT statement for character variables. |
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, 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/>. */ |
|
#define select_string SUFFIX(select_string) |
#define select_struct SUFFIX(select_struct) |
#define compare_string SUFFIX(compare_string) |
|
typedef struct |
{ |
CHARTYPE *low; |
gfc_charlen_type low_len; |
CHARTYPE *high; |
gfc_charlen_type high_len; |
int address; |
} |
select_struct; |
|
extern int select_string (select_struct *table, int table_len, |
const CHARTYPE *selector, |
gfc_charlen_type selector_len); |
export_proto(select_string); |
|
|
/* select_string()-- Given a selector string and a table of |
* select_struct structures, return the address to jump to. */ |
|
int |
select_string (select_struct *table, int table_len, const CHARTYPE *selector, |
gfc_charlen_type selector_len) |
{ |
select_struct *t; |
int i, low, high, mid; |
int default_jump = -1; |
|
if (table_len == 0) |
return -1; |
|
/* Record the default address if present */ |
|
if (table->low == NULL && table->high == NULL) |
{ |
default_jump = table->address; |
|
table++; |
table_len--; |
if (table_len == 0) |
return default_jump; |
} |
|
/* Try the high and low bounds if present. */ |
|
if (table->low == NULL) |
{ |
if (compare_string (table->high_len, table->high, |
selector_len, selector) >= 0) |
return table->address; |
|
table++; |
table_len--; |
if (table_len == 0) |
return default_jump; |
} |
|
t = table + table_len - 1; |
|
if (t->high == NULL) |
{ |
if (compare_string (t->low_len, t->low, selector_len, selector) <= 0) |
return t->address; |
|
table_len--; |
if (table_len == 0) |
return default_jump; |
} |
|
/* At this point, the only table entries are bounded entries. Find |
the right entry with a binary chop. */ |
|
low = -1; |
high = table_len; |
|
while (low + 1 < high) |
{ |
mid = (low + high) / 2; |
|
t = table + mid; |
i = compare_string (t->low_len, t->low, selector_len, selector); |
|
if (i == 0) |
return t->address; |
|
if (i < 0) |
low = mid; |
else |
high = mid; |
} |
|
/* The string now lies between the low indeces of the now-adjacent |
high and low entries. Because it is less than the low entry of |
'high', it can't be that one. If low is still -1, then no |
entries match. Otherwise, we have to check the high entry of |
'low'. */ |
|
if (low == -1) |
return default_jump; |
|
t = table + low; |
if (compare_string (selector_len, selector, t->high_len, t->high) <= 0) |
return t->address; |
|
return default_jump; |
} |
/pause.c
0,0 → 1,70
/* Implementation of the PAUSE statement. |
Copyright 2002, 2005, 2007, 2009, 2010, 2011 Free Software Foundation, Inc. |
Contributed by Paul Brook <paul@nowt.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 <string.h> |
#include <unistd.h> |
|
static void |
do_pause (void) |
{ |
char buff[4]; |
estr_write ("To resume execution, type go. " |
"Other input will terminate the job.\n"); |
|
fgets(buff, 4, stdin); |
if (strncmp(buff, "go\n", 3) != 0) |
stop_string ('\0', 0); |
estr_write ("RESUMED\n"); |
} |
|
/* A numeric PAUSE statement. */ |
|
extern void pause_numeric (GFC_INTEGER_4); |
export_proto(pause_numeric); |
|
void |
pause_numeric (GFC_INTEGER_4 code) |
{ |
st_printf ("PAUSE %d\n", (int) code); |
do_pause (); |
} |
|
/* A character string or blank PAUSE statement. */ |
|
extern void pause_string (char *string, GFC_INTEGER_4 len); |
export_proto(pause_string); |
|
void |
pause_string (char *string, GFC_INTEGER_4 len) |
{ |
estr_write ("PAUSE "); |
ssize_t w = write (STDERR_FILENO, string, len); |
(void) sizeof (w); /* Avoid compiler warning about not using write |
return val. */ |
estr_write ("\n"); |
|
do_pause (); |
} |
/convert_char.c
0,0 → 1,69
/* Runtime conversion of strings from one character kind to another. |
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/>. */ |
|
#include "libgfortran.h" |
|
#include <stdlib.h> |
#include <string.h> |
|
|
extern void convert_char1_to_char4 (gfc_char4_t **, gfc_charlen_type, |
const unsigned char *); |
export_proto(convert_char1_to_char4); |
|
extern void convert_char4_to_char1 (unsigned char **, gfc_charlen_type, |
const gfc_char4_t *); |
export_proto(convert_char4_to_char1); |
|
|
void |
convert_char1_to_char4 (gfc_char4_t **dst, gfc_charlen_type len, |
const unsigned char *src) |
{ |
gfc_charlen_type i, l; |
|
l = len > 0 ? len : 0; |
*dst = get_mem ((l + 1) * sizeof (gfc_char4_t)); |
|
for (i = 0; i < l; i++) |
(*dst)[i] = src[i]; |
|
(*dst)[l] = '\0'; |
} |
|
|
void |
convert_char4_to_char1 (unsigned char **dst, gfc_charlen_type len, |
const gfc_char4_t *src) |
{ |
gfc_charlen_type i, l; |
|
l = len > 0 ? len : 0; |
*dst = get_mem ((l + 1) * sizeof (unsigned char)); |
|
for (i = 0; i < l; i++) |
(*dst)[i] = src[i]; |
|
(*dst)[l] = '\0'; |
} |
/select.c
0,0 → 1,46
/* Implement the SELECT statement for character variables. |
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/>. */ |
|
#include "libgfortran.h" |
|
|
/* The string selection function is defined using a few generic macros |
in select_inc.c, so we avoid code duplication between the various |
character type kinds. */ |
|
#undef CHARTYPE |
#define CHARTYPE char |
#undef SUFFIX |
#define SUFFIX(x) x |
|
#include "select_inc.c" |
|
|
#undef CHARTYPE |
#define CHARTYPE gfc_char4_t |
#undef SUFFIX |
#define SUFFIX(x) x ## _char4 |
|
#include "select_inc.c" |
|
/backtrace.c
0,0 → 1,279
/* Copyright (C) 2006, 2007, 2009, 2011, 2012 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 <stdlib.h> |
|
#ifdef HAVE_UNISTD_H |
#include <unistd.h> |
#endif |
|
#ifdef HAVE_SYS_WAIT_H |
#include <sys/wait.h> |
#endif |
|
#include <limits.h> |
|
#include "unwind.h" |
|
|
/* Macros for common sets of capabilities: can we fork and exec, and |
can we use pipes to communicate with the subprocess. */ |
#define CAN_FORK (defined(HAVE_FORK) && defined(HAVE_EXECVE) \ |
&& defined(HAVE_WAIT)) |
#define CAN_PIPE (CAN_FORK && defined(HAVE_PIPE) \ |
&& defined(HAVE_DUP2) && defined(HAVE_CLOSE)) |
|
#ifndef PATH_MAX |
#define PATH_MAX 4096 |
#endif |
|
|
/* GDB style #NUM index for each stack frame. */ |
|
static void |
bt_header (int num) |
{ |
st_printf ("#%d ", num); |
} |
|
|
/* fgets()-like function that reads a line from a fd, without |
needing to malloc() a buffer, and does not use locks, hence should |
be async-signal-safe. */ |
|
static char * |
fd_gets (char *s, int size, int fd) |
{ |
for (int i = 0; i < size; i++) |
{ |
char c; |
ssize_t nread = read (fd, &c, 1); |
if (nread == 1) |
{ |
s[i] = c; |
if (c == '\n') |
{ |
if (i + 1 < size) |
s[i+1] = '\0'; |
else |
s[i] = '\0'; |
break; |
} |
} |
else |
{ |
s[i] = '\0'; |
if (i == 0) |
return NULL; |
break; |
} |
} |
return s; |
} |
|
|
extern char *addr2line_path; |
|
/* Struct containing backtrace state. */ |
typedef struct |
{ |
int frame_number; |
int direct_output; |
int outfd; |
int infd; |
int error; |
} |
bt_state; |
|
static _Unwind_Reason_Code |
trace_function (struct _Unwind_Context *context, void *state_ptr) |
{ |
bt_state* state = (bt_state*) state_ptr; |
_Unwind_Ptr ip; |
#ifdef HAVE_GETIPINFO |
int ip_before_insn = 0; |
ip = _Unwind_GetIPInfo (context, &ip_before_insn); |
|
/* If the unwinder gave us a 'return' address, roll it back a little |
to ensure we get the correct line number for the call itself. */ |
if (! ip_before_insn) |
--ip; |
#else |
ip = _Unwind_GetIP (context); |
#endif |
|
if (state->direct_output) |
{ |
bt_header(state->frame_number); |
st_printf ("%p\n", (void*) ip); |
} |
else |
{ |
char addr_buf[GFC_XTOA_BUF_SIZE], func[1024], file[PATH_MAX]; |
char *p; |
const char* addr = gfc_xtoa (ip, addr_buf, sizeof (addr_buf)); |
write (state->outfd, addr, strlen (addr)); |
write (state->outfd, "\n", 1); |
|
if (! fd_gets (func, sizeof(func), state->infd)) |
{ |
state->error = 1; |
goto done; |
} |
if (! fd_gets (file, sizeof(file), state->infd)) |
{ |
state->error = 1; |
goto done; |
} |
|
for (p = func; *p != '\n' && *p != '\r'; p++) |
; |
*p = '\0'; |
|
/* _start is a setup routine that calls main(), and main() is |
the frontend routine that calls some setup stuff and then |
calls MAIN__, so at this point we should stop. */ |
if (strcmp (func, "_start") == 0 || strcmp (func, "main") == 0) |
return _URC_END_OF_STACK; |
|
bt_header (state->frame_number); |
estr_write ("0x"); |
estr_write (addr); |
|
if (func[0] != '?' && func[1] != '?') |
{ |
estr_write (" in "); |
estr_write (func); |
} |
|
if (strncmp (file, "??", 2) == 0) |
estr_write ("\n"); |
else |
{ |
estr_write (" at "); |
estr_write (file); |
} |
} |
|
done: |
|
state->frame_number++; |
|
return _URC_NO_REASON; |
} |
|
|
/* Display the backtrace. */ |
|
void |
show_backtrace (void) |
{ |
bt_state state; |
state.frame_number = 0; |
state.error = 0; |
|
estr_write ("\nBacktrace for this error:\n"); |
|
#if CAN_PIPE |
|
if (addr2line_path == NULL) |
goto fallback_noerr; |
|
/* We attempt to extract file and line information from addr2line. */ |
do |
{ |
/* Local variables. */ |
int f[2], pid, inp[2]; |
|
/* Don't output an error message if something goes wrong, we'll simply |
fall back to printing the addresses. */ |
if (pipe (f) != 0) |
break; |
if (pipe (inp) != 0) |
break; |
if ((pid = fork ()) == -1) |
break; |
|
if (pid == 0) |
{ |
/* Child process. */ |
#define NUM_FIXEDARGS 7 |
char *arg[NUM_FIXEDARGS]; |
char *newenv[] = { NULL }; |
|
close (f[0]); |
|
close (inp[1]); |
if (dup2 (inp[0], STDIN_FILENO) == -1) |
_exit (1); |
close (inp[0]); |
|
close (STDERR_FILENO); |
|
if (dup2 (f[1], STDOUT_FILENO) == -1) |
_exit (1); |
close (f[1]); |
|
arg[0] = addr2line_path; |
arg[1] = (char *) "-e"; |
arg[2] = full_exe_path (); |
arg[3] = (char *) "-f"; |
arg[4] = (char *) "-s"; |
arg[5] = (char *) "-C"; |
arg[6] = NULL; |
execve (addr2line_path, arg, newenv); |
_exit (1); |
#undef NUM_FIXEDARGS |
} |
|
/* Father process. */ |
close (f[1]); |
close (inp[0]); |
|
state.outfd = inp[1]; |
state.infd = f[0]; |
state.direct_output = 0; |
_Unwind_Backtrace (trace_function, &state); |
if (state.error) |
goto fallback; |
close (inp[1]); |
wait (NULL); |
return; |
|
fallback: |
estr_write ("** Something went wrong while running addr2line. **\n" |
"** Falling back to a simpler backtrace scheme. **\n"); |
} |
while (0); |
|
#endif /* CAN_PIPE */ |
|
fallback_noerr: |
/* Fallback to the simple backtrace without addr2line. */ |
state.direct_output = 1; |
_Unwind_Backtrace (trace_function, &state); |
} |
/environ.c
0,0 → 1,830
/* Copyright (C) 2002, 2003, 2005, 2007, 2009 Free Software Foundation, Inc. |
Contributed by Andy Vaught |
|
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/>. */ |
|
#include "libgfortran.h" |
|
#include <string.h> |
#include <stdlib.h> |
#include <ctype.h> |
|
|
/* Environment scanner. Examine the environment for controlling minor |
* aspects of the program's execution. Our philosophy here that the |
* environment should not prevent the program from running, so an |
* environment variable with a messed-up value will be interpreted in |
* the default way. |
* |
* Most of the environment is checked early in the startup sequence, |
* but other variables are checked during execution of the user's |
* program. */ |
|
options_t options; |
|
|
typedef struct variable |
{ |
const char *name; |
int value, *var; |
void (*init) (struct variable *); |
void (*show) (struct variable *); |
const char *desc; |
int bad; |
} |
variable; |
|
static void init_unformatted (variable *); |
|
/* print_spaces()-- Print a particular number of spaces. */ |
|
static void |
print_spaces (int n) |
{ |
char buffer[80]; |
int i; |
|
if (n <= 0) |
return; |
|
for (i = 0; i < n; i++) |
buffer[i] = ' '; |
|
buffer[i] = '\0'; |
|
estr_write (buffer); |
} |
|
|
/* var_source()-- Return a string that describes where the value of a |
* variable comes from */ |
|
static const char * |
var_source (variable * v) |
{ |
if (getenv (v->name) == NULL) |
return "Default"; |
|
if (v->bad) |
return "Bad "; |
|
return "Set "; |
} |
|
|
/* init_integer()-- Initialize an integer environment variable. */ |
|
static void |
init_integer (variable * v) |
{ |
char *p, *q; |
|
p = getenv (v->name); |
if (p == NULL) |
goto set_default; |
|
for (q = p; *q; q++) |
if (!isdigit (*q) && (p != q || *q != '-')) |
{ |
v->bad = 1; |
goto set_default; |
} |
|
*v->var = atoi (p); |
return; |
|
set_default: |
*v->var = v->value; |
return; |
} |
|
|
/* init_unsigned_integer()-- Initialize an integer environment variable |
which has to be positive. */ |
|
static void |
init_unsigned_integer (variable * v) |
{ |
char *p, *q; |
|
p = getenv (v->name); |
if (p == NULL) |
goto set_default; |
|
for (q = p; *q; q++) |
if (!isdigit (*q)) |
{ |
v->bad = 1; |
goto set_default; |
} |
|
*v->var = atoi (p); |
return; |
|
set_default: |
*v->var = v->value; |
return; |
} |
|
|
/* show_integer()-- Show an integer environment variable */ |
|
static void |
show_integer (variable * v) |
{ |
st_printf ("%s %d\n", var_source (v), *v->var); |
} |
|
|
/* init_boolean()-- Initialize a boolean environment variable. We |
* only look at the first letter of the variable. */ |
|
static void |
init_boolean (variable * v) |
{ |
char *p; |
|
p = getenv (v->name); |
if (p == NULL) |
goto set_default; |
|
if (*p == '1' || *p == 'Y' || *p == 'y') |
{ |
*v->var = 1; |
return; |
} |
|
if (*p == '0' || *p == 'N' || *p == 'n') |
{ |
*v->var = 0; |
return; |
} |
|
v->bad = 1; |
|
set_default: |
*v->var = v->value; |
return; |
} |
|
|
/* show_boolean()-- Show a boolean environment variable */ |
|
static void |
show_boolean (variable * v) |
{ |
st_printf ("%s %s\n", var_source (v), *v->var ? "Yes" : "No"); |
} |
|
|
static void |
init_sep (variable * v) |
{ |
int seen_comma; |
char *p; |
|
p = getenv (v->name); |
if (p == NULL) |
goto set_default; |
|
v->bad = 1; |
options.separator = p; |
options.separator_len = strlen (p); |
|
/* Make sure the separator is valid */ |
|
if (options.separator_len == 0) |
goto set_default; |
seen_comma = 0; |
|
while (*p) |
{ |
if (*p == ',') |
{ |
if (seen_comma) |
goto set_default; |
seen_comma = 1; |
p++; |
continue; |
} |
|
if (*p++ != ' ') |
goto set_default; |
} |
|
v->bad = 0; |
return; |
|
set_default: |
options.separator = " "; |
options.separator_len = 1; |
} |
|
|
static void |
show_sep (variable * v) |
{ |
st_printf ("%s \"%s\"\n", var_source (v), options.separator); |
} |
|
|
static void |
init_string (variable * v __attribute__ ((unused))) |
{ |
} |
|
static void |
show_string (variable * v) |
{ |
const char *p; |
|
p = getenv (v->name); |
if (p == NULL) |
p = ""; |
|
estr_write (var_source (v)); |
estr_write (" \""); |
estr_write (p); |
estr_write ("\"\n"); |
} |
|
|
static variable variable_table[] = { |
{"GFORTRAN_STDIN_UNIT", GFC_STDIN_UNIT_NUMBER, &options.stdin_unit, |
init_integer, show_integer, |
"Unit number that will be preconnected to standard input\n" |
"(No preconnection if negative)", 0}, |
|
{"GFORTRAN_STDOUT_UNIT", GFC_STDOUT_UNIT_NUMBER, &options.stdout_unit, |
init_integer, show_integer, |
"Unit number that will be preconnected to standard output\n" |
"(No preconnection if negative)", 0}, |
|
{"GFORTRAN_STDERR_UNIT", GFC_STDERR_UNIT_NUMBER, &options.stderr_unit, |
init_integer, show_integer, |
"Unit number that will be preconnected to standard error\n" |
"(No preconnection if negative)", 0}, |
|
{"GFORTRAN_TMPDIR", 0, NULL, init_string, show_string, |
"Directory for scratch files. Overrides the TMP environment variable\n" |
"If TMP is not set " DEFAULT_TEMPDIR " is used.", 0}, |
|
{"GFORTRAN_UNBUFFERED_ALL", 0, &options.all_unbuffered, init_boolean, |
show_boolean, |
"If TRUE, all output is unbuffered. This will slow down large writes " |
"but can be\nuseful for forcing data to be displayed immediately.", 0}, |
|
{"GFORTRAN_UNBUFFERED_PRECONNECTED", 0, &options.unbuffered_preconnected, |
init_boolean, show_boolean, |
"If TRUE, output to preconnected units is unbuffered.", 0}, |
|
{"GFORTRAN_SHOW_LOCUS", 1, &options.locus, init_boolean, show_boolean, |
"If TRUE, print filename and line number where runtime errors happen.", 0}, |
|
{"GFORTRAN_OPTIONAL_PLUS", 0, &options.optional_plus, init_boolean, show_boolean, |
"Print optional plus signs in numbers where permitted. Default FALSE.", 0}, |
|
{"GFORTRAN_DEFAULT_RECL", DEFAULT_RECL, &options.default_recl, |
init_unsigned_integer, show_integer, |
"Default maximum record length for sequential files. Most useful for\n" |
"adjusting line length of preconnected units. Default " |
stringize (DEFAULT_RECL), 0}, |
|
{"GFORTRAN_LIST_SEPARATOR", 0, NULL, init_sep, show_sep, |
"Separator to use when writing list output. May contain any number of " |
"spaces\nand at most one comma. Default is a single space.", 0}, |
|
/* GFORTRAN_CONVERT_UNIT - Set the default data conversion for |
unformatted I/O. */ |
{"GFORTRAN_CONVERT_UNIT", 0, 0, init_unformatted, show_string, |
"Set format for unformatted files", 0}, |
|
{"GFORTRAN_ERROR_BACKTRACE", -1, &options.backtrace, |
init_boolean, show_boolean, |
"Print out a backtrace (if possible) on runtime error", -1}, |
|
{NULL, 0, NULL, NULL, NULL, NULL, 0} |
}; |
|
|
/* init_variables()-- Initialize most runtime variables from |
* environment variables. */ |
|
void |
init_variables (void) |
{ |
variable *v; |
|
for (v = variable_table; v->name; v++) |
v->init (v); |
} |
|
|
void |
show_variables (void) |
{ |
variable *v; |
int n; |
|
/* TODO: print version number. */ |
estr_write ("GNU Fortran runtime library version " |
"UNKNOWN" "\n\n"); |
|
estr_write ("Environment variables:\n"); |
estr_write ("----------------------\n"); |
|
for (v = variable_table; v->name; v++) |
{ |
n = estr_write (v->name); |
print_spaces (25 - n); |
|
if (v->show == show_integer) |
estr_write ("Integer "); |
else if (v->show == show_boolean) |
estr_write ("Boolean "); |
else |
estr_write ("String "); |
|
v->show (v); |
estr_write (v->desc); |
estr_write ("\n\n"); |
} |
|
/* System error codes */ |
|
estr_write ("\nRuntime error codes:"); |
estr_write ("\n--------------------\n"); |
|
for (n = LIBERROR_FIRST + 1; n < LIBERROR_LAST; n++) |
if (n < 0 || n > 9) |
st_printf ("%d %s\n", n, translate_error (n)); |
else |
st_printf (" %d %s\n", n, translate_error (n)); |
|
estr_write ("\nCommand line arguments:\n"); |
estr_write (" --help Print this list\n"); |
|
exit (0); |
} |
|
/* This is the handling of the GFORTRAN_CONVERT_UNITS environment variable. |
It is called from environ.c to parse this variable, and from |
open.c to determine if the user specified a default for an |
unformatted file. |
The syntax of the environment variable is, in bison grammar: |
|
GFORTRAN_CONVERT_UNITS: mode | mode ';' exception ; |
mode: 'native' | 'swap' | 'big_endian' | 'little_endian' ; |
exception: mode ':' unit_list | unit_list ; |
unit_list: unit_spec | unit_list unit_spec ; |
unit_spec: INTEGER | INTEGER '-' INTEGER ; |
*/ |
|
/* Defines for the tokens. Other valid tokens are ',', ':', '-'. */ |
|
|
#define NATIVE 257 |
#define SWAP 258 |
#define BIG 259 |
#define LITTLE 260 |
/* Some space for additional tokens later. */ |
#define INTEGER 273 |
#define END (-1) |
#define ILLEGAL (-2) |
|
typedef struct |
{ |
int unit; |
unit_convert conv; |
} exception_t; |
|
|
static char *p; /* Main character pointer for parsing. */ |
static char *lastpos; /* Auxiliary pointer, for backing up. */ |
static int unit_num; /* The last unit number read. */ |
static int unit_count; /* The number of units found. */ |
static int do_count; /* Parsing is done twice - first to count the number |
of units, then to fill in the table. This |
variable controls what to do. */ |
static exception_t *elist; /* The list of exceptions to the default. This is |
sorted according to unit number. */ |
static int n_elist; /* Number of exceptions to the default. */ |
|
static unit_convert endian; /* Current endianness. */ |
|
static unit_convert def; /* Default as specified (if any). */ |
|
/* Search for a unit number, using a binary search. The |
first argument is the unit number to search for. The second argument |
is a pointer to an index. |
If the unit number is found, the function returns 1, and the index |
is that of the element. |
If the unit number is not found, the function returns 0, and the |
index is the one where the element would be inserted. */ |
|
static int |
search_unit (int unit, int *ip) |
{ |
int low, high, mid; |
|
low = -1; |
high = n_elist; |
while (high - low > 1) |
{ |
mid = (low + high) / 2; |
if (unit <= elist[mid].unit) |
high = mid; |
else |
low = mid; |
} |
*ip = high; |
if (elist[high].unit == unit) |
return 1; |
else |
return 0; |
} |
|
/* This matches a keyword. If it is found, return the token supplied, |
otherwise return ILLEGAL. */ |
|
static int |
match_word (const char *word, int tok) |
{ |
int res; |
|
if (strncasecmp (p, word, strlen (word)) == 0) |
{ |
p += strlen (word); |
res = tok; |
} |
else |
res = ILLEGAL; |
return res; |
|
} |
|
/* Match an integer and store its value in unit_num. This only works |
if p actually points to the start of an integer. The caller has |
to ensure this. */ |
|
static int |
match_integer (void) |
{ |
unit_num = 0; |
while (isdigit (*p)) |
unit_num = unit_num * 10 + (*p++ - '0'); |
return INTEGER; |
|
} |
|
/* This reads the next token from the GFORTRAN_CONVERT_UNITS variable. |
Returned values are the different tokens. */ |
|
static int |
next_token (void) |
{ |
int result; |
|
lastpos = p; |
switch (*p) |
{ |
case '\0': |
result = END; |
break; |
|
case ':': |
case ',': |
case '-': |
case ';': |
result = *p; |
p++; |
break; |
|
case 'b': |
case 'B': |
result = match_word ("big_endian", BIG); |
break; |
|
case 'l': |
case 'L': |
result = match_word ("little_endian", LITTLE); |
break; |
|
case 'n': |
case 'N': |
result = match_word ("native", NATIVE); |
break; |
|
case 's': |
case 'S': |
result = match_word ("swap", SWAP); |
break; |
|
case '1': case '2': case '3': case '4': case '5': |
case '6': case '7': case '8': case '9': |
result = match_integer (); |
break; |
|
default: |
result = ILLEGAL; |
break; |
} |
return result; |
} |
|
/* Back up the last token by setting back the character pointer. */ |
|
static void |
push_token (void) |
{ |
p = lastpos; |
} |
|
/* This is called when a unit is identified. If do_count is nonzero, |
increment the number of units by one. If do_count is zero, |
put the unit into the table. */ |
|
static void |
mark_single (int unit) |
{ |
int i,j; |
|
if (do_count) |
{ |
unit_count++; |
return; |
} |
if (search_unit (unit, &i)) |
{ |
elist[unit].conv = endian; |
} |
else |
{ |
for (j=n_elist; j>=i; j--) |
elist[j+1] = elist[j]; |
|
n_elist += 1; |
elist[i].unit = unit; |
elist[i].conv = endian; |
} |
} |
|
/* This is called when a unit range is identified. If do_count is |
nonzero, increase the number of units. If do_count is zero, |
put the unit into the table. */ |
|
static void |
mark_range (int unit1, int unit2) |
{ |
int i; |
if (do_count) |
unit_count += abs (unit2 - unit1) + 1; |
else |
{ |
if (unit2 < unit1) |
for (i=unit2; i<=unit1; i++) |
mark_single (i); |
else |
for (i=unit1; i<=unit2; i++) |
mark_single (i); |
} |
} |
|
/* Parse the GFORTRAN_CONVERT_UNITS variable. This is called |
twice, once to count the units and once to actually mark them in |
the table. When counting, we don't check for double occurrences |
of units. */ |
|
static int |
do_parse (void) |
{ |
int tok; |
int unit1; |
int continue_ulist; |
char *start; |
|
unit_count = 0; |
|
start = p; |
|
/* Parse the string. First, let's look for a default. */ |
tok = next_token (); |
switch (tok) |
{ |
case NATIVE: |
endian = GFC_CONVERT_NATIVE; |
break; |
|
case SWAP: |
endian = GFC_CONVERT_SWAP; |
break; |
|
case BIG: |
endian = GFC_CONVERT_BIG; |
break; |
|
case LITTLE: |
endian = GFC_CONVERT_LITTLE; |
break; |
|
case INTEGER: |
/* A leading digit means that we are looking at an exception. |
Reset the position to the beginning, and continue processing |
at the exception list. */ |
p = start; |
goto exceptions; |
break; |
|
case END: |
goto end; |
break; |
|
default: |
goto error; |
break; |
} |
|
tok = next_token (); |
switch (tok) |
{ |
case ';': |
def = endian; |
break; |
|
case ':': |
/* This isn't a default after all. Reset the position to the |
beginning, and continue processing at the exception list. */ |
p = start; |
goto exceptions; |
break; |
|
case END: |
def = endian; |
goto end; |
break; |
|
default: |
goto error; |
break; |
} |
|
exceptions: |
|
/* Loop over all exceptions. */ |
while(1) |
{ |
tok = next_token (); |
switch (tok) |
{ |
case NATIVE: |
if (next_token () != ':') |
goto error; |
endian = GFC_CONVERT_NATIVE; |
break; |
|
case SWAP: |
if (next_token () != ':') |
goto error; |
endian = GFC_CONVERT_SWAP; |
break; |
|
case LITTLE: |
if (next_token () != ':') |
goto error; |
endian = GFC_CONVERT_LITTLE; |
break; |
|
case BIG: |
if (next_token () != ':') |
goto error; |
endian = GFC_CONVERT_BIG; |
break; |
|
case INTEGER: |
push_token (); |
break; |
|
case END: |
goto end; |
break; |
|
default: |
goto error; |
break; |
} |
/* We arrive here when we want to parse a list of |
numbers. */ |
continue_ulist = 1; |
do |
{ |
tok = next_token (); |
if (tok != INTEGER) |
goto error; |
|
unit1 = unit_num; |
tok = next_token (); |
/* The number can be followed by a - and another number, |
which means that this is a unit range, a comma |
or a semicolon. */ |
if (tok == '-') |
{ |
if (next_token () != INTEGER) |
goto error; |
|
mark_range (unit1, unit_num); |
tok = next_token (); |
if (tok == END) |
goto end; |
else if (tok == ';') |
continue_ulist = 0; |
else if (tok != ',') |
goto error; |
} |
else |
{ |
mark_single (unit1); |
switch (tok) |
{ |
case ';': |
continue_ulist = 0; |
break; |
|
case ',': |
break; |
|
case END: |
goto end; |
break; |
|
default: |
goto error; |
} |
} |
} while (continue_ulist); |
} |
end: |
return 0; |
error: |
def = GFC_CONVERT_NONE; |
return -1; |
} |
|
void init_unformatted (variable * v) |
{ |
char *val; |
val = getenv (v->name); |
def = GFC_CONVERT_NONE; |
n_elist = 0; |
|
if (val == NULL) |
return; |
do_count = 1; |
p = val; |
do_parse (); |
if (do_count <= 0) |
{ |
n_elist = 0; |
elist = NULL; |
} |
else |
{ |
elist = get_mem (unit_count * sizeof (exception_t)); |
do_count = 0; |
p = val; |
do_parse (); |
} |
} |
|
/* Get the default conversion for for an unformatted unit. */ |
|
unit_convert |
get_unformatted_convert (int unit) |
{ |
int i; |
|
if (elist == NULL) |
return def; |
else if (search_unit (unit, &i)) |
return elist[i].conv; |
else |
return def; |
} |
/main.c
0,0 → 1,257
/* Copyright (C) 2002-2003, 2005, 2007, 2009, 2011 |
Free Software Foundation, Inc. |
Contributed by Andy Vaught and Paul Brook <paul@nowt.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, 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 <limits.h> |
|
|
#ifdef HAVE_UNISTD_H |
#include <unistd.h> |
#endif |
|
/* Stupid function to be sure the constructor is always linked in, even |
in the case of static linking. See PR libfortran/22298 for details. */ |
void |
stupid_function_name_for_static_linking (void) |
{ |
return; |
} |
|
/* This will be 0 for little-endian |
machines and 1 for big-endian machines. */ |
int big_endian = 0; |
|
|
/* Figure out endianness for this machine. */ |
|
static void |
determine_endianness (void) |
{ |
union |
{ |
GFC_LOGICAL_8 l8; |
GFC_LOGICAL_4 l4[2]; |
} u; |
|
u.l8 = 1; |
if (u.l4[0]) |
big_endian = 0; |
else if (u.l4[1]) |
big_endian = 1; |
else |
runtime_error ("Unable to determine machine endianness"); |
} |
|
|
static int argc_save; |
static char **argv_save; |
|
static const char *exe_path; |
static int please_free_exe_path_when_done; |
|
/* Save the path under which the program was called, for use in the |
backtrace routines. */ |
void |
store_exe_path (const char * argv0) |
{ |
#ifndef PATH_MAX |
#define PATH_MAX 1024 |
#endif |
|
#ifndef DIR_SEPARATOR |
#define DIR_SEPARATOR '/' |
#endif |
|
char buf[PATH_MAX], *path; |
const char *cwd; |
|
/* This can only happen if store_exe_path is called multiple times. */ |
if (please_free_exe_path_when_done) |
free ((char *) exe_path); |
|
/* Reading the /proc/self/exe symlink is Linux-specific(?), but if |
it works it gives the correct answer. */ |
#ifdef HAVE_READLINK |
int len; |
if ((len = readlink ("/proc/self/exe", buf, sizeof (buf) - 1)) != -1) |
{ |
buf[len] = '\0'; |
exe_path = strdup (buf); |
please_free_exe_path_when_done = 1; |
return; |
} |
#endif |
|
/* If the path is absolute or on a simulator where argv is not set. */ |
#ifdef __MINGW32__ |
if (argv0 == NULL |
|| ('A' <= argv0[0] && argv0[0] <= 'Z' && argv0[1] == ':') |
|| ('a' <= argv0[0] && argv0[0] <= 'z' && argv0[1] == ':') |
|| (argv0[0] == '/' && argv0[1] == '/') |
|| (argv0[0] == '\\' && argv0[1] == '\\')) |
#else |
if (argv0 == NULL || argv0[0] == DIR_SEPARATOR) |
#endif |
{ |
exe_path = argv0; |
please_free_exe_path_when_done = 0; |
return; |
} |
|
#ifdef HAVE_GETCWD |
cwd = getcwd (buf, sizeof (buf)); |
#else |
cwd = NULL; |
#endif |
|
if (!cwd) |
{ |
exe_path = argv0; |
please_free_exe_path_when_done = 0; |
return; |
} |
|
/* exe_path will be cwd + "/" + argv[0] + "\0". This will not work |
if the executable is not in the cwd, but at this point we're out |
of better ideas. */ |
size_t pathlen = strlen (cwd) + 1 + strlen (argv0) + 1; |
path = malloc (pathlen); |
snprintf (path, pathlen, "%s%c%s", cwd, DIR_SEPARATOR, argv0); |
exe_path = path; |
please_free_exe_path_when_done = 1; |
} |
|
|
/* Return the full path of the executable. */ |
char * |
full_exe_path (void) |
{ |
return (char *) exe_path; |
} |
|
|
char *addr2line_path; |
|
/* Find addr2line and store the path. */ |
|
void |
find_addr2line (void) |
{ |
#ifdef HAVE_ACCESS |
#define A2L_LEN 10 |
char *path = getenv ("PATH"); |
if (!path) |
return; |
size_t n = strlen (path); |
char ap[n + 1 + A2L_LEN]; |
size_t ai = 0; |
for (size_t i = 0; i < n; i++) |
{ |
if (path[i] != ':') |
ap[ai++] = path[i]; |
else |
{ |
ap[ai++] = '/'; |
memcpy (ap + ai, "addr2line", A2L_LEN); |
if (access (ap, R_OK|X_OK) == 0) |
{ |
addr2line_path = strdup (ap); |
return; |
} |
else |
ai = 0; |
} |
} |
#endif |
} |
|
|
/* Set the saved values of the command line arguments. */ |
|
void |
set_args (int argc, char **argv) |
{ |
argc_save = argc; |
argv_save = argv; |
store_exe_path (argv[0]); |
} |
iexport(set_args); |
|
|
/* Retrieve the saved values of the command line arguments. */ |
|
void |
get_args (int *argc, char ***argv) |
{ |
*argc = argc_save; |
*argv = argv_save; |
} |
|
|
/* Initialize the runtime library. */ |
|
static void __attribute__((constructor)) |
init (void) |
{ |
/* Figure out the machine endianness. */ |
determine_endianness (); |
|
/* Must be first */ |
init_variables (); |
|
init_units (); |
set_fpu (); |
init_compile_options (); |
|
#ifdef DEBUG |
/* Check for special command lines. */ |
|
if (argc > 1 && strcmp (argv[1], "--help") == 0) |
show_variables (); |
|
/* if (argc > 1 && strcmp(argv[1], "--resume") == 0) resume(); */ |
#endif |
|
if (options.backtrace == 1) |
find_addr2line (); |
|
random_seed_i4 (NULL, NULL, NULL); |
} |
|
|
/* Cleanup the runtime library. */ |
|
static void __attribute__((destructor)) |
cleanup (void) |
{ |
close_units (); |
|
if (please_free_exe_path_when_done) |
free ((char *) exe_path); |
|
free (addr2line_path); |
} |
/stop.c
0,0 → 1,109
/* Implementation of the STOP statement. |
Copyright 2002, 2005, 2007, 2009, 2010, 2011 Free Software Foundation, Inc. |
Contributed by Paul Brook <paul@nowt.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> |
#include <string.h> |
#include <unistd.h> |
|
/* A numeric STOP statement. */ |
|
extern void stop_numeric (GFC_INTEGER_4) |
__attribute__ ((noreturn)); |
export_proto(stop_numeric); |
|
void |
stop_numeric (GFC_INTEGER_4 code) |
{ |
if (code == -1) |
code = 0; |
else |
st_printf ("STOP %d\n", (int)code); |
|
exit (code); |
} |
|
|
/* A Fortran 2008 numeric STOP statement. */ |
|
extern void stop_numeric_f08 (GFC_INTEGER_4) |
__attribute__ ((noreturn)); |
export_proto(stop_numeric_f08); |
|
void |
stop_numeric_f08 (GFC_INTEGER_4 code) |
{ |
st_printf ("STOP %d\n", (int)code); |
exit (code); |
} |
|
|
/* A character string or blank STOP statement. */ |
|
void |
stop_string (const char *string, GFC_INTEGER_4 len) |
{ |
if (string) |
{ |
estr_write ("STOP "); |
(void) write (STDERR_FILENO, string, len); |
estr_write ("\n"); |
} |
exit (0); |
} |
|
|
/* Per Fortran 2008, section 8.4: "Execution of a STOP statement initiates |
normal termination of execution. Execution of an ERROR STOP statement |
initiates error termination of execution." Thus, error_stop_string returns |
a nonzero exit status code. */ |
|
extern void error_stop_string (const char *, GFC_INTEGER_4) |
__attribute__ ((noreturn)); |
export_proto(error_stop_string); |
|
void |
error_stop_string (const char *string, GFC_INTEGER_4 len) |
{ |
estr_write ("ERROR STOP "); |
(void) write (STDERR_FILENO, string, len); |
estr_write ("\n"); |
|
exit (1); |
} |
|
|
/* A numeric ERROR STOP statement. */ |
|
extern void error_stop_numeric (GFC_INTEGER_4) |
__attribute__ ((noreturn)); |
export_proto(error_stop_numeric); |
|
void |
error_stop_numeric (GFC_INTEGER_4 code) |
{ |
st_printf ("ERROR STOP %d\n", (int) code); |
exit (code); |
} |
/error.c
0,0 → 1,614
/* Copyright (C) 2002, 2003, 2005, 2006, 2007, 2009, 2010, 2011 |
Free Software Foundation, Inc. |
Contributed by Andy Vaught |
|
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 <assert.h> |
#include <string.h> |
#include <errno.h> |
#include <signal.h> |
|
#ifdef HAVE_UNISTD_H |
#include <unistd.h> |
#endif |
|
#include <stdlib.h> |
|
#ifdef HAVE_SYS_TIME_H |
#include <sys/time.h> |
#endif |
|
/* <sys/time.h> has to be included before <sys/resource.h> to work |
around PR 30518; otherwise, MacOS 10.3.9 headers are just broken. */ |
#ifdef HAVE_SYS_RESOURCE_H |
#include <sys/resource.h> |
#endif |
|
|
#ifdef __MINGW32__ |
#define HAVE_GETPID 1 |
#include <process.h> |
#endif |
|
|
/* Termination of a program: F2008 2.3.5 talks about "normal |
termination" and "error termination". Normal termination occurs as |
a result of e.g. executing the end program statement, and executing |
the STOP statement. It includes the effect of the C exit() |
function. |
|
Error termination is initiated when the ERROR STOP statement is |
executed, when ALLOCATE/DEALLOCATE fails without STAT= being |
specified, when some of the co-array synchronization statements |
fail without STAT= being specified, and some I/O errors if |
ERR/IOSTAT/END/EOR is not present, and finally EXECUTE_COMMAND_LINE |
failure without CMDSTAT=. |
|
2.3.5 also explains how co-images synchronize during termination. |
|
In libgfortran we have two ways of ending a program. exit(code) is |
a normal exit; calling exit() also causes open units to be |
closed. No backtrace or core dump is needed here. When something |
goes wrong, we have sys_abort() which tries to print the backtrace |
if -fbacktrace is enabled, and then dumps core; whether a core file |
is generated is system dependent. When aborting, we don't flush and |
close open units, as program memory might be corrupted and we'd |
rather risk losing dirty data in the buffers rather than corrupting |
files on disk. |
|
*/ |
|
/* Error conditions. The tricky part here is printing a message when |
* it is the I/O subsystem that is severely wounded. Our goal is to |
* try and print something making the fewest assumptions possible, |
* then try to clean up before actually exiting. |
* |
* The following exit conditions are defined: |
* 0 Normal program exit. |
* 1 Terminated because of operating system error. |
* 2 Error in the runtime library |
* 3 Internal error in runtime library |
* |
* Other error returns are reserved for the STOP statement with a numeric code. |
*/ |
|
|
/* Write a null-terminated C string to standard error. This function |
is async-signal-safe. */ |
|
ssize_t |
estr_write (const char *str) |
{ |
return write (STDERR_FILENO, str, strlen (str)); |
} |
|
|
/* st_vprintf()-- vsnprintf-like function for error output. We use a |
stack allocated buffer for formatting; since this function might be |
called from within a signal handler, printing directly to stderr |
with vfprintf is not safe since the stderr locking might lead to a |
deadlock. */ |
|
#define ST_VPRINTF_SIZE 512 |
|
int |
st_vprintf (const char *format, va_list ap) |
{ |
int written; |
char buffer[ST_VPRINTF_SIZE]; |
|
#ifdef HAVE_VSNPRINTF |
written = vsnprintf(buffer, ST_VPRINTF_SIZE, format, ap); |
#else |
written = vsprintf(buffer, format, ap); |
|
if (written >= ST_VPRINTF_SIZE - 1) |
{ |
/* The error message was longer than our buffer. Ouch. Because |
we may have messed up things badly, report the error and |
quit. */ |
#define ERROR_MESSAGE "Internal error: buffer overrun in st_vprintf()\n" |
write (STDERR_FILENO, buffer, ST_VPRINTF_SIZE - 1); |
write (STDERR_FILENO, ERROR_MESSAGE, strlen(ERROR_MESSAGE)); |
sys_abort (); |
#undef ERROR_MESSAGE |
|
} |
#endif |
|
written = write (STDERR_FILENO, buffer, written); |
return written; |
} |
|
|
int |
st_printf (const char * format, ...) |
{ |
int written; |
va_list ap; |
va_start (ap, format); |
written = st_vprintf (format, ap); |
va_end (ap); |
return written; |
} |
|
|
/* sys_abort()-- Terminate the program showing backtrace and dumping |
core. */ |
|
void |
sys_abort (void) |
{ |
/* If backtracing is enabled, print backtrace and disable signal |
handler for ABRT. */ |
if (options.backtrace == 1 |
|| (options.backtrace == -1 && compile_options.backtrace == 1)) |
{ |
show_backtrace (); |
signal (SIGABRT, SIG_DFL); |
} |
|
abort(); |
} |
|
|
/* gfc_xtoa()-- Integer to hexadecimal conversion. */ |
|
const char * |
gfc_xtoa (GFC_UINTEGER_LARGEST n, char *buffer, size_t len) |
{ |
int digit; |
char *p; |
|
assert (len >= GFC_XTOA_BUF_SIZE); |
|
if (n == 0) |
return "0"; |
|
p = buffer + GFC_XTOA_BUF_SIZE - 1; |
*p = '\0'; |
|
while (n != 0) |
{ |
digit = n & 0xF; |
if (digit > 9) |
digit += 'A' - '0' - 10; |
|
*--p = '0' + digit; |
n >>= 4; |
} |
|
return p; |
} |
|
|
/* Hopefully thread-safe wrapper for a strerror_r() style function. */ |
|
char * |
gf_strerror (int errnum, |
char * buf __attribute__((unused)), |
size_t buflen __attribute__((unused))) |
{ |
#ifdef HAVE_STRERROR_R |
return |
__builtin_choose_expr (__builtin_classify_type (strerror_r (0, buf, 0)) |
== 5, |
/* GNU strerror_r() */ |
strerror_r (errnum, buf, buflen), |
/* POSIX strerror_r () */ |
(strerror_r (errnum, buf, buflen), buf)); |
#else |
/* strerror () is not necessarily thread-safe, but should at least |
be available everywhere. */ |
return strerror (errnum); |
#endif |
} |
|
|
/* show_locus()-- Print a line number and filename describing where |
* something went wrong */ |
|
void |
show_locus (st_parameter_common *cmp) |
{ |
char *filename; |
|
if (!options.locus || cmp == NULL || cmp->filename == NULL) |
return; |
|
if (cmp->unit > 0) |
{ |
filename = filename_from_unit (cmp->unit); |
|
if (filename != NULL) |
{ |
st_printf ("At line %d of file %s (unit = %d, file = '%s')\n", |
(int) cmp->line, cmp->filename, (int) cmp->unit, filename); |
free (filename); |
} |
else |
{ |
st_printf ("At line %d of file %s (unit = %d)\n", |
(int) cmp->line, cmp->filename, (int) cmp->unit); |
} |
return; |
} |
|
st_printf ("At line %d of file %s\n", (int) cmp->line, cmp->filename); |
} |
|
|
/* recursion_check()-- It's possible for additional errors to occur |
* during fatal error processing. We detect this condition here and |
* exit with code 4 immediately. */ |
|
#define MAGIC 0x20DE8101 |
|
static void |
recursion_check (void) |
{ |
static int magic = 0; |
|
/* Don't even try to print something at this point */ |
if (magic == MAGIC) |
sys_abort (); |
|
magic = MAGIC; |
} |
|
|
#define STRERR_MAXSZ 256 |
|
/* os_error()-- Operating system error. We get a message from the |
* operating system, show it and leave. Some operating system errors |
* are caught and processed by the library. If not, we come here. */ |
|
void |
os_error (const char *message) |
{ |
char errmsg[STRERR_MAXSZ]; |
recursion_check (); |
estr_write ("Operating system error: "); |
estr_write (gf_strerror (errno, errmsg, STRERR_MAXSZ)); |
estr_write ("\n"); |
estr_write (message); |
estr_write ("\n"); |
exit (1); |
} |
iexport(os_error); |
|
|
/* void runtime_error()-- These are errors associated with an |
* invalid fortran program. */ |
|
void |
runtime_error (const char *message, ...) |
{ |
va_list ap; |
|
recursion_check (); |
estr_write ("Fortran runtime error: "); |
va_start (ap, message); |
st_vprintf (message, ap); |
va_end (ap); |
estr_write ("\n"); |
exit (2); |
} |
iexport(runtime_error); |
|
/* void runtime_error_at()-- These are errors associated with a |
* run time error generated by the front end compiler. */ |
|
void |
runtime_error_at (const char *where, const char *message, ...) |
{ |
va_list ap; |
|
recursion_check (); |
estr_write (where); |
estr_write ("\nFortran runtime error: "); |
va_start (ap, message); |
st_vprintf (message, ap); |
va_end (ap); |
estr_write ("\n"); |
exit (2); |
} |
iexport(runtime_error_at); |
|
|
void |
runtime_warning_at (const char *where, const char *message, ...) |
{ |
va_list ap; |
|
estr_write (where); |
estr_write ("\nFortran runtime warning: "); |
va_start (ap, message); |
st_vprintf (message, ap); |
va_end (ap); |
estr_write ("\n"); |
} |
iexport(runtime_warning_at); |
|
|
/* void internal_error()-- These are this-can't-happen errors |
* that indicate something deeply wrong. */ |
|
void |
internal_error (st_parameter_common *cmp, const char *message) |
{ |
recursion_check (); |
show_locus (cmp); |
estr_write ("Internal Error: "); |
estr_write (message); |
estr_write ("\n"); |
|
/* This function call is here to get the main.o object file included |
when linking statically. This works because error.o is supposed to |
be always linked in (and the function call is in internal_error |
because hopefully it doesn't happen too often). */ |
stupid_function_name_for_static_linking(); |
|
exit (3); |
} |
|
|
/* translate_error()-- Given an integer error code, return a string |
* describing the error. */ |
|
const char * |
translate_error (int code) |
{ |
const char *p; |
|
switch (code) |
{ |
case LIBERROR_EOR: |
p = "End of record"; |
break; |
|
case LIBERROR_END: |
p = "End of file"; |
break; |
|
case LIBERROR_OK: |
p = "Successful return"; |
break; |
|
case LIBERROR_OS: |
p = "Operating system error"; |
break; |
|
case LIBERROR_BAD_OPTION: |
p = "Bad statement option"; |
break; |
|
case LIBERROR_MISSING_OPTION: |
p = "Missing statement option"; |
break; |
|
case LIBERROR_OPTION_CONFLICT: |
p = "Conflicting statement options"; |
break; |
|
case LIBERROR_ALREADY_OPEN: |
p = "File already opened in another unit"; |
break; |
|
case LIBERROR_BAD_UNIT: |
p = "Unattached unit"; |
break; |
|
case LIBERROR_FORMAT: |
p = "FORMAT error"; |
break; |
|
case LIBERROR_BAD_ACTION: |
p = "Incorrect ACTION specified"; |
break; |
|
case LIBERROR_ENDFILE: |
p = "Read past ENDFILE record"; |
break; |
|
case LIBERROR_BAD_US: |
p = "Corrupt unformatted sequential file"; |
break; |
|
case LIBERROR_READ_VALUE: |
p = "Bad value during read"; |
break; |
|
case LIBERROR_READ_OVERFLOW: |
p = "Numeric overflow on read"; |
break; |
|
case LIBERROR_INTERNAL: |
p = "Internal error in run-time library"; |
break; |
|
case LIBERROR_INTERNAL_UNIT: |
p = "Internal unit I/O error"; |
break; |
|
case LIBERROR_DIRECT_EOR: |
p = "Write exceeds length of DIRECT access record"; |
break; |
|
case LIBERROR_SHORT_RECORD: |
p = "I/O past end of record on unformatted file"; |
break; |
|
case LIBERROR_CORRUPT_FILE: |
p = "Unformatted file structure has been corrupted"; |
break; |
|
default: |
p = "Unknown error code"; |
break; |
} |
|
return p; |
} |
|
|
/* generate_error()-- Come here when an error happens. This |
* subroutine is called if it is possible to continue on after the error. |
* If an IOSTAT or IOMSG variable exists, we set it. If IOSTAT or |
* ERR labels are present, we return, otherwise we terminate the program |
* after printing a message. The error code is always required but the |
* message parameter can be NULL, in which case a string describing |
* the most recent operating system error is used. */ |
|
void |
generate_error (st_parameter_common *cmp, int family, const char *message) |
{ |
char errmsg[STRERR_MAXSZ]; |
|
/* If there was a previous error, don't mask it with another |
error message, EOF or EOR condition. */ |
|
if ((cmp->flags & IOPARM_LIBRETURN_MASK) == IOPARM_LIBRETURN_ERROR) |
return; |
|
/* Set the error status. */ |
if ((cmp->flags & IOPARM_HAS_IOSTAT)) |
*cmp->iostat = (family == LIBERROR_OS) ? errno : family; |
|
if (message == NULL) |
message = |
(family == LIBERROR_OS) ? gf_strerror (errno, errmsg, STRERR_MAXSZ) : |
translate_error (family); |
|
if (cmp->flags & IOPARM_HAS_IOMSG) |
cf_strcpy (cmp->iomsg, cmp->iomsg_len, message); |
|
/* Report status back to the compiler. */ |
cmp->flags &= ~IOPARM_LIBRETURN_MASK; |
switch (family) |
{ |
case LIBERROR_EOR: |
cmp->flags |= IOPARM_LIBRETURN_EOR; |
if ((cmp->flags & IOPARM_EOR)) |
return; |
break; |
|
case LIBERROR_END: |
cmp->flags |= IOPARM_LIBRETURN_END; |
if ((cmp->flags & IOPARM_END)) |
return; |
break; |
|
default: |
cmp->flags |= IOPARM_LIBRETURN_ERROR; |
if ((cmp->flags & IOPARM_ERR)) |
return; |
break; |
} |
|
/* Return if the user supplied an iostat variable. */ |
if ((cmp->flags & IOPARM_HAS_IOSTAT)) |
return; |
|
/* Terminate the program */ |
|
recursion_check (); |
show_locus (cmp); |
estr_write ("Fortran runtime error: "); |
estr_write (message); |
estr_write ("\n"); |
exit (2); |
} |
iexport(generate_error); |
|
|
/* generate_warning()-- Similar to generate_error but just give a warning. */ |
|
void |
generate_warning (st_parameter_common *cmp, const char *message) |
{ |
if (message == NULL) |
message = " "; |
|
show_locus (cmp); |
estr_write ("Fortran runtime warning: "); |
estr_write (message); |
estr_write ("\n"); |
} |
|
|
/* Whether, for a feature included in a given standard set (GFC_STD_*), |
we should issue an error or a warning, or be quiet. */ |
|
notification |
notification_std (int std) |
{ |
int warning; |
|
if (!compile_options.pedantic) |
return NOTIFICATION_SILENT; |
|
warning = compile_options.warn_std & std; |
if ((compile_options.allow_std & std) != 0 && !warning) |
return NOTIFICATION_SILENT; |
|
return warning ? NOTIFICATION_WARNING : NOTIFICATION_ERROR; |
} |
|
|
/* Possibly issue a warning/error about use of a nonstandard (or deleted) |
feature. An error/warning will be issued if the currently selected |
standard does not contain the requested bits. */ |
|
try |
notify_std (st_parameter_common *cmp, int std, const char * message) |
{ |
int warning; |
|
if (!compile_options.pedantic) |
return SUCCESS; |
|
warning = compile_options.warn_std & std; |
if ((compile_options.allow_std & std) != 0 && !warning) |
return SUCCESS; |
|
if (!warning) |
{ |
recursion_check (); |
show_locus (cmp); |
estr_write ("Fortran runtime error: "); |
estr_write (message); |
estr_write ("\n"); |
exit (2); |
} |
else |
{ |
show_locus (cmp); |
estr_write ("Fortran runtime warning: "); |
estr_write (message); |
estr_write ("\n"); |
} |
return FAILURE; |
} |
/fpu.c
0,0 → 1,41
/* Set FPU mask. |
Copyright 2005 Free Software Foundation, Inc. |
Contributed by Francois-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" |
|
/* We include the platform-dependent code. */ |
#include "fpu-target.h" |
|
/* Function called by the front-end to tell us |
when a FPE should be raised. */ |
extern void set_fpe (int); |
export_proto(set_fpe); |
|
void |
set_fpe (int exceptions) |
{ |
options.fpe = exceptions; |
set_fpu (); |
} |
/bounds.c
0,0 → 1,272
/* Copyright (C) 2009 |
Free Software Foundation, Inc. |
Contributed by Thomas Koenig |
|
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 <assert.h> |
|
/* Auxiliary functions for bounds checking, mostly to reduce library size. */ |
|
/* Bounds checking for the return values of the iforeach functions (such |
as maxloc and minloc). The extent of ret_array must |
must match the rank of array. */ |
|
void |
bounds_iforeach_return (array_t *retarray, array_t *array, const char *name) |
{ |
index_type rank; |
index_type ret_rank; |
index_type ret_extent; |
|
ret_rank = GFC_DESCRIPTOR_RANK (retarray); |
|
if (ret_rank != 1) |
runtime_error ("Incorrect rank of return array in %s intrinsic:" |
"is %ld, should be 1", name, (long int) ret_rank); |
|
rank = GFC_DESCRIPTOR_RANK (array); |
ret_extent = GFC_DESCRIPTOR_EXTENT(retarray,0); |
if (ret_extent != rank) |
runtime_error ("Incorrect extent in return value of" |
" %s intrinsic: is %ld, should be %ld", |
name, (long int) ret_extent, (long int) rank); |
|
} |
|
/* Check the return of functions generated from ifunction.m4. |
We check the array descriptor "a" against the extents precomputed |
from ifunction.m4, and complain about the argument a_name in the |
intrinsic function. */ |
|
void |
bounds_ifunction_return (array_t * a, const index_type * extent, |
const char * a_name, const char * intrinsic) |
{ |
int empty; |
int n; |
int rank; |
index_type a_size; |
|
rank = GFC_DESCRIPTOR_RANK (a); |
a_size = size0 (a); |
|
empty = 0; |
for (n = 0; n < rank; n++) |
{ |
if (extent[n] == 0) |
empty = 1; |
} |
if (empty) |
{ |
if (a_size != 0) |
runtime_error ("Incorrect size in %s of %s" |
" intrinsic: should be zero-sized", |
a_name, intrinsic); |
} |
else |
{ |
if (a_size == 0) |
runtime_error ("Incorrect size of %s in %s" |
" intrinsic: should not be zero-sized", |
a_name, intrinsic); |
|
for (n = 0; n < rank; n++) |
{ |
index_type a_extent; |
a_extent = GFC_DESCRIPTOR_EXTENT(a, n); |
if (a_extent != extent[n]) |
runtime_error("Incorrect extent in %s of %s" |
" intrinsic in dimension %ld: is %ld," |
" should be %ld", a_name, intrinsic, (long int) n + 1, |
(long int) a_extent, (long int) extent[n]); |
|
} |
} |
} |
|
/* Check that two arrays have equal extents, or are both zero-sized. Abort |
with a runtime error if this is not the case. Complain that a has the |
wrong size. */ |
|
void |
bounds_equal_extents (array_t *a, array_t *b, const char *a_name, |
const char *intrinsic) |
{ |
index_type a_size, b_size, n; |
|
assert (GFC_DESCRIPTOR_RANK(a) == GFC_DESCRIPTOR_RANK(b)); |
|
a_size = size0 (a); |
b_size = size0 (b); |
|
if (b_size == 0) |
{ |
if (a_size != 0) |
runtime_error ("Incorrect size of %s in %s" |
" intrinsic: should be zero-sized", |
a_name, intrinsic); |
} |
else |
{ |
if (a_size == 0) |
runtime_error ("Incorrect size of %s of %s" |
" intrinsic: Should not be zero-sized", |
a_name, intrinsic); |
|
for (n = 0; n < GFC_DESCRIPTOR_RANK (b); n++) |
{ |
index_type a_extent, b_extent; |
|
a_extent = GFC_DESCRIPTOR_EXTENT(a, n); |
b_extent = GFC_DESCRIPTOR_EXTENT(b, n); |
if (a_extent != b_extent) |
runtime_error("Incorrect extent in %s of %s" |
" intrinsic in dimension %ld: is %ld," |
" should be %ld", a_name, intrinsic, (long int) n + 1, |
(long int) a_extent, (long int) b_extent); |
} |
} |
} |
|
/* Check that the extents of a and b agree, except that a has a missing |
dimension in argument which. Complain about a if anything is wrong. */ |
|
void |
bounds_reduced_extents (array_t *a, array_t *b, int which, const char *a_name, |
const char *intrinsic) |
{ |
|
index_type i, n, a_size, b_size; |
|
assert (GFC_DESCRIPTOR_RANK(a) == GFC_DESCRIPTOR_RANK(b) - 1); |
|
a_size = size0 (a); |
b_size = size0 (b); |
|
if (b_size == 0) |
{ |
if (a_size != 0) |
runtime_error ("Incorrect size in %s of %s" |
" intrinsic: should not be zero-sized", |
a_name, intrinsic); |
} |
else |
{ |
if (a_size == 0) |
runtime_error ("Incorrect size of %s of %s" |
" intrinsic: should be zero-sized", |
a_name, intrinsic); |
|
i = 0; |
for (n = 0; n < GFC_DESCRIPTOR_RANK (b); n++) |
{ |
index_type a_extent, b_extent; |
|
if (n != which) |
{ |
a_extent = GFC_DESCRIPTOR_EXTENT(a, i); |
b_extent = GFC_DESCRIPTOR_EXTENT(b, n); |
if (a_extent != b_extent) |
runtime_error("Incorrect extent in %s of %s" |
" intrinsic in dimension %ld: is %ld," |
" should be %ld", a_name, intrinsic, (long int) i + 1, |
(long int) a_extent, (long int) b_extent); |
i++; |
} |
} |
} |
} |
|
/* count_0 - count all the true elements in an array. The front |
end usually inlines this, we need this for bounds checking |
for unpack. */ |
|
index_type count_0 (const gfc_array_l1 * array) |
{ |
const GFC_LOGICAL_1 * restrict base; |
index_type rank; |
int kind; |
int continue_loop; |
index_type count[GFC_MAX_DIMENSIONS]; |
index_type extent[GFC_MAX_DIMENSIONS]; |
index_type sstride[GFC_MAX_DIMENSIONS]; |
index_type result; |
index_type n; |
|
rank = GFC_DESCRIPTOR_RANK (array); |
kind = GFC_DESCRIPTOR_SIZE (array); |
|
base = array->data; |
|
if (kind == 1 || kind == 2 || kind == 4 || kind == 8 |
#ifdef HAVE_GFC_LOGICAL_16 |
|| kind == 16 |
#endif |
) |
{ |
if (base) |
base = GFOR_POINTER_TO_L1 (base, kind); |
} |
else |
internal_error (NULL, "Funny sized logical array in count_0"); |
|
for (n = 0; n < rank; n++) |
{ |
sstride[n] = GFC_DESCRIPTOR_STRIDE_BYTES(array,n); |
extent[n] = GFC_DESCRIPTOR_EXTENT(array,n); |
count[n] = 0; |
|
if (extent[n] <= 0) |
return 0; |
} |
|
result = 0; |
continue_loop = 1; |
while (continue_loop) |
{ |
if (*base) |
result ++; |
|
count[0]++; |
base += sstride[0]; |
n = 0; |
while (count[n] == extent[n]) |
{ |
count[n] = 0; |
base -= sstride[n] * extent[n]; |
n++; |
if (n == rank) |
{ |
continue_loop = 0; |
break; |
} |
else |
{ |
count[n]++; |
base += sstride[n]; |
} |
} |
} |
return result; |
} |