init
This commit is contained in:
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
*.o
|
||||||
|
*.mod
|
||||||
|
.DS_Store
|
||||||
|
fortran_fcgi
|
||||||
|
*.c
|
||||||
|
*.a
|
||||||
17
Dockerfile
Normal file
17
Dockerfile
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
FROM ubuntu:trusty
|
||||||
|
|
||||||
|
# update Ubuntu
|
||||||
|
RUN apt-get update
|
||||||
|
|
||||||
|
RUN apt-get install -y gfortran make sqlite3 libsqlite3-dev nginx libfcgi-dev spawn-fcgi make
|
||||||
|
|
||||||
|
WORKDIR /fortran-machine
|
||||||
|
|
||||||
|
RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf
|
||||||
|
|
||||||
|
ADD . .
|
||||||
|
RUN make
|
||||||
|
|
||||||
|
ADD nginx.conf /etc/nginx/sites-enabled/default
|
||||||
|
|
||||||
|
CMD sh start.sh
|
||||||
25
LICENSE
Normal file
25
LICENSE
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
Copyright (c) 2016
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
Neither the name of the author nor the names of the contributors
|
||||||
|
may be used to endorse or promote products derived from this software
|
||||||
|
without specific prior written permission.
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
13
TODO.md
Normal file
13
TODO.md
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
models
|
||||||
|
- search is more flexible (LOWER function)
|
||||||
|
|
||||||
|
views
|
||||||
|
- spacing, commas, multiple params
|
||||||
|
- HTML escaping
|
||||||
|
- cool images for marsupial search
|
||||||
|
- spaces, commas, dots, hashes in attributes
|
||||||
|
|
||||||
|
docs
|
||||||
|
- testing?
|
||||||
|
- refresher / update
|
||||||
|
- figure out how to get the sqlite c file in place
|
||||||
1766
flibs-0.9/aa
Normal file
1766
flibs-0.9/aa
Normal file
File diff suppressed because it is too large
Load Diff
55
flibs-0.9/flibs/ChangeLog
Normal file
55
flibs-0.9/flibs/ChangeLog
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
2008-08-10 arjenmarkus@sourceforge.net
|
||||||
|
* chksys/chksysff.f90: added a test for the type of hexdecimal and binary constants/literals
|
||||||
|
|
||||||
|
2008-07-09 arjenmarkus@sourceforge.net
|
||||||
|
* tests/tools/check_reals.f90: drop the elemental keyword
|
||||||
|
|
||||||
|
2008-07-04 arjenmarkus@sourceforge.net
|
||||||
|
* src/tools: added a new program (editcode): specific preprocessing tasks
|
||||||
|
* tests/tools: small test for the preprocessing program
|
||||||
|
|
||||||
|
2008-05-04 arjenmarkus@sourceforge.net
|
||||||
|
* index.html: added the vstring and vstringlist modules, as well as finite_state and messages
|
||||||
|
* finite_state: updated the test program, wrote the documentation
|
||||||
|
* messages: updated the module and the test program
|
||||||
|
|
||||||
|
2008-03-16 arjenmarkus@sourceforge.net
|
||||||
|
* testmake: a complete application to create test programs
|
||||||
|
* chksys: a set of programs to check properties of the compiler
|
||||||
|
|
||||||
|
2008-03-13 arjenmarkus@sourceforge.net
|
||||||
|
|
||||||
|
* filedir: module for manipulating files and directories added (written by Michael Baudin)
|
||||||
|
* platform: module for basic identification of platform properties (written by Michael Baudin)
|
||||||
|
|
||||||
|
2008-01-27 arjenmarkus@sourceforge.net
|
||||||
|
|
||||||
|
* ftnunit.f90: added init and final routines, added assertions
|
||||||
|
* test_ftnunit.f90: added init and final routines
|
||||||
|
|
||||||
|
2008-01-26 arjenmarkus@sourceforge.net
|
||||||
|
|
||||||
|
* ftnunit.f90: moved the test subroutine
|
||||||
|
* ftnunit.man: updated documentation
|
||||||
|
* gentabletest.tcl: added facility
|
||||||
|
|
||||||
|
(ChangeLog was not kept up-to-date)
|
||||||
|
|
||||||
|
2006-06-25 arjenmarkus@sourceforge.net
|
||||||
|
|
||||||
|
* added pointsets.f90
|
||||||
|
* started with simple interval arithmetic
|
||||||
|
* added an implementation of text streams
|
||||||
|
* simple string manipulations
|
||||||
|
* experiment with integer programming
|
||||||
|
|
||||||
|
2006-04-11 arjenmarkus@sourceforge.net
|
||||||
|
|
||||||
|
* integer_set.f90: correction of one inconsistency (intent)
|
||||||
|
* func_qsort.f90: added to repository
|
||||||
|
* quantum.f90: added to repository
|
||||||
|
* quantum_computing.pdf: added to site docs
|
||||||
|
* index.html: description of experiments directory
|
||||||
|
* backtracking facilities
|
||||||
|
|
||||||
|
Note: no detailed record maintained before 11 april 2006
|
||||||
27
flibs-0.9/flibs/Copyright
Normal file
27
flibs-0.9/flibs/Copyright
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
Copyright (c) 2008, Arjen Markus
|
||||||
|
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
Neither the name of the author nor the names of the contributors
|
||||||
|
may be used to endorse or promote products derived from this software
|
||||||
|
without specific prior written permission.
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
|
||||||
108
flibs-0.9/flibs/README
Normal file
108
flibs-0.9/flibs/README
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
Flibs, version 0.9, december 2008
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
What is Flibs
|
||||||
|
-------------
|
||||||
|
Flibs is a collection of Fortran modules for various tasks:
|
||||||
|
- [cgi] facilitate web programming via CGI
|
||||||
|
- [checking] checking various aspects of the code via instrumentation
|
||||||
|
and static analysis
|
||||||
|
- [computing] computational tasks, such as automatic differentiation
|
||||||
|
- [controlstructures] flow control structures such as finite state machines
|
||||||
|
- [datastructures] support for implementing linked lists, dictionaries
|
||||||
|
and the like
|
||||||
|
- [filedir] OS-level tasks regarding files and directories
|
||||||
|
- [funit] a framework for unit testing, inspired by JUnit
|
||||||
|
- [ipc] inter-process communication
|
||||||
|
- [lemon] Lex/Yacc-like parser generation
|
||||||
|
- [platform] utilities to query the OS and the platform running the
|
||||||
|
program
|
||||||
|
- [reporting] tools for generating reports in various formats
|
||||||
|
(notably LaTex and HTML)
|
||||||
|
- [specs] tool to generate a robust reading routine from specifications,
|
||||||
|
geared to tabular input
|
||||||
|
- [sqlite] interface to the SQLite database management system (http//www.sqlite.org)
|
||||||
|
- [streams] modules to treat files as "streams" rather than record-oriented
|
||||||
|
- [strings] modules to manipulate strings (tokenizing, varying-length strings)
|
||||||
|
- [tools] preprocessor tool to manipulate the source code
|
||||||
|
- [wrapper] tool to generate Fortran 90 and Fortran 2003 interfaces to C
|
||||||
|
routines from the C header files
|
||||||
|
|
||||||
|
Furthermore:
|
||||||
|
- [app] a tool for generating makefile dependencies from the Fortran
|
||||||
|
source code and an experiment at "literate programming".
|
||||||
|
- [chksys] a collection of programs to probe the properties of the
|
||||||
|
Fortran compiler (with a similar program for C)
|
||||||
|
- [doc] documentation for the various modules (in HTML form) and several
|
||||||
|
articles.
|
||||||
|
- [experiments] various experiments with different programming
|
||||||
|
paradigms.
|
||||||
|
- [testmake] a program suite to generate test programs from
|
||||||
|
simple specifications.
|
||||||
|
|
||||||
|
Documentation is not complete, but most if not all modules and utilities
|
||||||
|
come with a comprehensive example/test case.
|
||||||
|
|
||||||
|
The Flibs project is located on SourceForge: http://flibs.sf.net
|
||||||
|
|
||||||
|
|
||||||
|
Building the modules
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
Each directory under the "src" directory contains one or more modules or
|
||||||
|
tools. The corresponding directory under "tests" contains the
|
||||||
|
test/example programs and makefiles (or in some case project files for
|
||||||
|
MS Developer Studio with Compaq Visual Fortran as the Fortran compiler).
|
||||||
|
Each set can be built on its own.
|
||||||
|
|
||||||
|
The makefiles are set up using macros to take care of differences in
|
||||||
|
compilers and compiler options. In principle it should not be necessary
|
||||||
|
to adapt the makefiles to your particular compiler, unless it is doing
|
||||||
|
things in a completely different way than:
|
||||||
|
- Compile the individual sources
|
||||||
|
- Link the resulting object files into an executable
|
||||||
|
|
||||||
|
The simple configuration system (configure.sh and configure.bat) helps
|
||||||
|
to set up the macros for the makefiles:
|
||||||
|
- configure.sh probes various compilers under Linux, Cygwin or MinGW
|
||||||
|
- configure.bat is meant for Windows
|
||||||
|
|
||||||
|
|
||||||
|
Status of the modules
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
Not all modules and utilities included in the 0.9 release are fully
|
||||||
|
functional yet. They have been included mainly for completeness and
|
||||||
|
as a reminder:
|
||||||
|
|
||||||
|
- the genetic_algorithms module typically converges too fast, so that
|
||||||
|
a suboptimal solution is returned.
|
||||||
|
- the tupleserver program is not quite finished yet, but as tuple spaces
|
||||||
|
are a very interesting construct to achieve concurrency, it is
|
||||||
|
included here.
|
||||||
|
- the fwrapper program, meant to generate C/C++ interfaces from Fortran
|
||||||
|
code is still in its infancy. The cwrap program (written in Tcl) is
|
||||||
|
functional though.
|
||||||
|
|
||||||
|
|
||||||
|
Tcl utilities
|
||||||
|
-------------
|
||||||
|
|
||||||
|
While most of the code is written in standard Fortran 90, as far as the
|
||||||
|
authors are aware, the collection also contains several utilities
|
||||||
|
written in Tcl. If you do not have a Tcl installation, you can either
|
||||||
|
get a full installation from www.activestate.com or you can use a
|
||||||
|
standalone runtime executable from www.equi4.com.
|
||||||
|
|
||||||
|
|
||||||
|
Copyright
|
||||||
|
---------
|
||||||
|
|
||||||
|
Most of the source files have been written by Arjen Markus. The modules
|
||||||
|
under "filedir", "platform" and several modules in other directories
|
||||||
|
have been written by Michael Baudin. The date/time module under
|
||||||
|
"computing" has been supplied by Arjan van Dijk.
|
||||||
|
|
||||||
|
All source code in this project is licensed via the BSD license (see
|
||||||
|
the "Copyright" file). Basically this means:
|
||||||
|
Do what you want with it, but do not claim it is your original work.
|
||||||
49
flibs-0.9/flibs/TODO
Normal file
49
flibs-0.9/flibs/TODO
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
TODO list
|
||||||
|
---------
|
||||||
|
|
||||||
|
dd. 16 december 2008
|
||||||
|
Add a simple module to interpret commands - Fibonaci-like
|
||||||
|
|
||||||
|
dd. 8 september 2008
|
||||||
|
Document the extensions to the automatic differentiation module
|
||||||
|
|
||||||
|
dd. 4 may 2008
|
||||||
|
Change the messages.f90 file: the definitions must be separated out,
|
||||||
|
like with the "finite state" module
|
||||||
|
Correct the documentation and interface for the ipc_file module - LUN
|
||||||
|
|
||||||
|
dd. 29 april 2008
|
||||||
|
Idea for exception handling - via a simple preprocessing
|
||||||
|
program (this can be used for preconditions and postconditions as well)
|
||||||
|
Done
|
||||||
|
|
||||||
|
dd. 21 april 2008
|
||||||
|
Add COPYRIGHT file
|
||||||
|
|
||||||
|
dd. 20 april 2008
|
||||||
|
Add module for simulated annealing
|
||||||
|
|
||||||
|
|
||||||
|
dd. 22 march 2008
|
||||||
|
Add report facilities to CVS + logging
|
||||||
|
|
||||||
|
|
||||||
|
dd. 1 february 2007
|
||||||
|
Add "indexsets"
|
||||||
|
Add utilities:
|
||||||
|
- find out the number of bytes for a record length unit
|
||||||
|
- find a list of files
|
||||||
|
Add applications and checks:
|
||||||
|
- varying-length strings
|
||||||
|
- merge and the like: different string lengths
|
||||||
|
- very long source lines
|
||||||
|
|
||||||
|
dd. 23 december 2005
|
||||||
|
linkedlist.f90:
|
||||||
|
- Support for empty lists
|
||||||
|
- Support for derived type with pointer components
|
||||||
|
|
||||||
|
globmatch.f90:
|
||||||
|
- Expand the test program with more cases
|
||||||
|
|
||||||
|
|
||||||
165
flibs-0.9/flibs/app/chktype.tcl
Normal file
165
flibs-0.9/flibs/app/chktype.tcl
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
# chktype.tcl --
|
||||||
|
# An attempt at literate programming
|
||||||
|
# See the generated file for the motivation
|
||||||
|
#
|
||||||
|
proc comment {text} {
|
||||||
|
global outfile
|
||||||
|
puts $outfile "! [join [split $text \n] "\n !"]"
|
||||||
|
}
|
||||||
|
proc code {text} {
|
||||||
|
global outfile
|
||||||
|
puts $outfile $text
|
||||||
|
}
|
||||||
|
# Hm, gencode is superfluous probably
|
||||||
|
proc gencode {name text} {
|
||||||
|
global outfile
|
||||||
|
puts $outfile "[string map [list NAME $name] $text]"
|
||||||
|
}
|
||||||
|
|
||||||
|
# main --
|
||||||
|
#
|
||||||
|
set outfile [open "chktype.f90" w]
|
||||||
|
|
||||||
|
comment {\
|
||||||
|
chktype.f90 --
|
||||||
|
|
||||||
|
The module chktype is meant to have the compiler check
|
||||||
|
as much as possible if the terms in an expression all
|
||||||
|
have the same precision. This can be used to find out
|
||||||
|
if there are expressions like "2.1*x" with x a double
|
||||||
|
precision value or "2.0*i/9" with i an integer.
|
||||||
|
|
||||||
|
Such statements cause serious problems:
|
||||||
|
- the constant 2.1 in the first example is used as
|
||||||
|
single precision whereas the expression as a whole
|
||||||
|
will be of double precision. The value is, however,
|
||||||
|
_not_ the same as 2.1d0*x.
|
||||||
|
- Evaluating 2.0*i/9 may result in a wrong answer:
|
||||||
|
set i to 1. If i/9 is computed first, then the result
|
||||||
|
is 0, not 2.0/9= 0.2222...
|
||||||
|
|
||||||
|
The module is not intended for use in an actual program,
|
||||||
|
it is merely meant for checking at run time
|
||||||
|
}
|
||||||
|
code {
|
||||||
|
module chktype
|
||||||
|
type real_
|
||||||
|
private
|
||||||
|
real :: v
|
||||||
|
endtype
|
||||||
|
type double_
|
||||||
|
private
|
||||||
|
real(kind=kind(1.0d0)) :: v
|
||||||
|
endtype
|
||||||
|
type integer_
|
||||||
|
private
|
||||||
|
integer :: v
|
||||||
|
endtype
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach {op name} {+ add - sub * mult / div ** expon > gt < lt >= ge <= le
|
||||||
|
== eq /= ne} {
|
||||||
|
gencode $op "
|
||||||
|
interface operator(NAME)
|
||||||
|
module procedure ${name}_real
|
||||||
|
module procedure ${name}_double
|
||||||
|
module procedure ${name}_integer
|
||||||
|
module procedure ${name}_real_tc
|
||||||
|
module procedure ${name}_double_tc
|
||||||
|
module procedure ${name}_integer_tc
|
||||||
|
module procedure ${name}_real_ct
|
||||||
|
module procedure ${name}_double_ct
|
||||||
|
module procedure ${name}_integer_ct
|
||||||
|
end interface"
|
||||||
|
}
|
||||||
|
code {
|
||||||
|
interface assignment(=)
|
||||||
|
module procedure assign_real
|
||||||
|
module procedure assign_double
|
||||||
|
module procedure assign_integer
|
||||||
|
module procedure assign_real_const
|
||||||
|
module procedure assign_double_const
|
||||||
|
module procedure assign_integer_const
|
||||||
|
end interface
|
||||||
|
}
|
||||||
|
code {
|
||||||
|
contains
|
||||||
|
}
|
||||||
|
|
||||||
|
array set T {real real double "real(kind=kind(1.0d0))" integer integer}
|
||||||
|
|
||||||
|
foreach type {real double integer} {
|
||||||
|
code "
|
||||||
|
elemental subroutine assign_${type}(x,y)
|
||||||
|
type(${type}_), intent(in) :: y
|
||||||
|
type(${type}_), intent(out) :: x
|
||||||
|
x%v = y%v
|
||||||
|
end subroutine"
|
||||||
|
code "
|
||||||
|
elemental subroutine assign_${type}_const(x,y)
|
||||||
|
$T($type), intent(in) :: y
|
||||||
|
type(${type}_), intent(out) :: x
|
||||||
|
x%v = y
|
||||||
|
end subroutine"
|
||||||
|
}
|
||||||
|
foreach {op name} {+ add - sub * mult / div ** expon } {
|
||||||
|
foreach type {real double integer} {
|
||||||
|
code "
|
||||||
|
elemental type(${type}_) function ${name}_${type}(x,y)
|
||||||
|
type(${type}_), intent(in) :: x,y
|
||||||
|
${name}_${type}%v = x%v $op y%v
|
||||||
|
end function
|
||||||
|
elemental type(${type}_) function ${name}_${type}_tc(x,y)
|
||||||
|
type(${type}_), intent(in) :: x
|
||||||
|
$T($type), intent(in) :: y
|
||||||
|
${name}_${type}_tc%v = x%v $op y
|
||||||
|
end function
|
||||||
|
elemental type(${type}_) function ${name}_${type}_ct(x,y)
|
||||||
|
$T($type), intent(in) :: x
|
||||||
|
type(${type}_), intent(in) :: y
|
||||||
|
${name}_${type}_ct%v = x $op y%v
|
||||||
|
end function"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach {op name} {> gt < lt >= ge <= le == eq /= ne} {
|
||||||
|
foreach type {real double integer} {
|
||||||
|
code "
|
||||||
|
elemental logical function ${name}_${type}(x,y)
|
||||||
|
type(${type}_), intent(in) :: x,y
|
||||||
|
${name}_${type} = x%v $op y%v
|
||||||
|
end function
|
||||||
|
elemental logical function ${name}_${type}_tc(x,y)
|
||||||
|
type(${type}_), intent(in) :: x
|
||||||
|
$T($type), intent(in) :: y
|
||||||
|
${name}_${type}_tc = x%v $op y
|
||||||
|
end function
|
||||||
|
elemental logical function ${name}_${type}_ct(x,y)
|
||||||
|
$T($type), intent(in) :: x
|
||||||
|
type(${type}_), intent(in) :: y
|
||||||
|
${name}_${type}_ct = x $op y%v
|
||||||
|
end function"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# TODO: sin, cos, ...
|
||||||
|
# TODO: max, min
|
||||||
|
# Do we want minval and friends as well?
|
||||||
|
# Also: huge(), tiny() ...?
|
||||||
|
|
||||||
|
|
||||||
|
code {
|
||||||
|
end module chktype}
|
||||||
|
|
||||||
|
# Add a small test program
|
||||||
|
code {
|
||||||
|
program aha
|
||||||
|
use chktype
|
||||||
|
|
||||||
|
type(real_) :: x
|
||||||
|
type(real_) :: y
|
||||||
|
|
||||||
|
y = 1.0d0
|
||||||
|
x = 11 * y
|
||||||
|
end program
|
||||||
|
}
|
||||||
|
close $outfile
|
||||||
141
flibs-0.9/flibs/app/dependencies.tcl
Normal file
141
flibs-0.9/flibs/app/dependencies.tcl
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
# dependencies.tcl
|
||||||
|
# Examine the available Fortran sources and set up a
|
||||||
|
# list of dependencies for use in make for instance
|
||||||
|
#
|
||||||
|
# Limitations:
|
||||||
|
# - include files are not examined
|
||||||
|
# - no directory information about where to find the include file
|
||||||
|
# is taken into account (that is: no -I options!)
|
||||||
|
# - include files with a Fortran-type extensions are examined
|
||||||
|
# as if they were ordinary source files, thus leading to
|
||||||
|
# too many source files in the dependency list
|
||||||
|
#
|
||||||
|
|
||||||
|
# getDependencyItems --
|
||||||
|
# Analyse the file and return a list of items
|
||||||
|
# Arguments:
|
||||||
|
# filename Name of the file to examine
|
||||||
|
# Result:
|
||||||
|
# A list of lists:
|
||||||
|
# - Element 1 is a list of modules defined in the file
|
||||||
|
# - Element 2 is a list of external modules referred to in the file
|
||||||
|
# - Element 3 is a list of include files
|
||||||
|
#
|
||||||
|
proc getDependencyItems {filename} {
|
||||||
|
set infile [open $filename r]
|
||||||
|
|
||||||
|
set provided {}
|
||||||
|
set required {}
|
||||||
|
set include {}
|
||||||
|
|
||||||
|
while { [gets $infile line] >= 0 } {
|
||||||
|
|
||||||
|
switch -re -- [string tolower $line] {
|
||||||
|
{ *include +['"]} {
|
||||||
|
lappend include [GetInclude $line]
|
||||||
|
}
|
||||||
|
{ *use +[a-z]} {
|
||||||
|
lappend required [GetUse $line]
|
||||||
|
}
|
||||||
|
{ *module +[a-z]} {
|
||||||
|
lappend provided [GetModule $line]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [list $provided $required $include]
|
||||||
|
}
|
||||||
|
|
||||||
|
# GetInclude, GetUse, GetModule --
|
||||||
|
# Extract the relevant information from the list
|
||||||
|
# Arguments:
|
||||||
|
# line Line of code
|
||||||
|
# Result:
|
||||||
|
# Name of a file or a module
|
||||||
|
#
|
||||||
|
proc GetInclude {line} {
|
||||||
|
return [lindex [split $line {'"}] 1]
|
||||||
|
}
|
||||||
|
proc GetUse {line} {
|
||||||
|
return [lindex $line 1]
|
||||||
|
}
|
||||||
|
proc GetModule {line} {
|
||||||
|
return [lindex $line 1]
|
||||||
|
}
|
||||||
|
|
||||||
|
# ObjectFile, ModuleFile --
|
||||||
|
# Transform the file name
|
||||||
|
# Arguments:
|
||||||
|
# name Source file/module name
|
||||||
|
# Result:
|
||||||
|
# Name of a file or a module
|
||||||
|
#
|
||||||
|
proc ObjectFile {name} {
|
||||||
|
return "[file root $name].o"
|
||||||
|
}
|
||||||
|
proc ModuleFile {name} {
|
||||||
|
return "[string toupper $name].mod"
|
||||||
|
}
|
||||||
|
|
||||||
|
# analyseAllFiles --
|
||||||
|
# Analyse all files in the current directory
|
||||||
|
# Arguments:
|
||||||
|
# filename Name of the file for dependencies
|
||||||
|
# type Type of output ("make" or "ordered")
|
||||||
|
# Result:
|
||||||
|
# None
|
||||||
|
#
|
||||||
|
proc analyseAllFiles {filename type} {
|
||||||
|
|
||||||
|
set outfile [open $filename w]
|
||||||
|
|
||||||
|
if { $::tcl_platform(platform) == "windows" } {
|
||||||
|
set mask "*.f *.for *.f90"
|
||||||
|
} else {
|
||||||
|
set mask "*.f *.for *.f90 *.F *.FOR *.F90"
|
||||||
|
}
|
||||||
|
set files {}
|
||||||
|
foreach f [eval glob -type f $mask] {
|
||||||
|
foreach {provided required include} [getDependencyItems $f] {break}
|
||||||
|
|
||||||
|
set deps($f) {}
|
||||||
|
|
||||||
|
foreach i $include {
|
||||||
|
lappend deps($f) $i
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach m $provided {
|
||||||
|
set mod [ModuleFile $m]
|
||||||
|
lappend files $mod
|
||||||
|
set deps($mod) $f
|
||||||
|
}
|
||||||
|
foreach m $required {
|
||||||
|
set mod [ModuleFile $m]
|
||||||
|
set deps($f) $mod
|
||||||
|
}
|
||||||
|
lappend files $f
|
||||||
|
}
|
||||||
|
|
||||||
|
switch -- $type {
|
||||||
|
"make" {
|
||||||
|
foreach f $files {
|
||||||
|
if { [lsearch {.f .for .f90 .F .FOR .F90} [file extension $f]] >= 0 } {
|
||||||
|
puts $outfile [ObjectFile $f]\t:\t$f\n\t[join $deps($f) \\\n\t]
|
||||||
|
} else {
|
||||||
|
puts $outfile $f\t:\t[join $deps($f) \\\n\t]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"ordered" {
|
||||||
|
puts "TO BE DONE!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
close $outfile
|
||||||
|
}
|
||||||
|
|
||||||
|
# main --
|
||||||
|
# Get the thing going
|
||||||
|
#
|
||||||
|
|
||||||
|
analyseAllFiles test.mk make
|
||||||
11
flibs-0.9/flibs/app/testdep/test.mk
Normal file
11
flibs-0.9/flibs/app/testdep/test.mk
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
A.mod : tsta.f90
|
||||||
|
B.mod : tsta.f90
|
||||||
|
tsta.o : tsta.f90
|
||||||
|
D.mod
|
||||||
|
C.mod : tstc.f90
|
||||||
|
tstc.o : tstc.f90
|
||||||
|
|
||||||
|
D.mod : tstd.f90
|
||||||
|
tstd.o : tstd.f90
|
||||||
|
f.inc\
|
||||||
|
g.inc
|
||||||
10
flibs-0.9/flibs/app/testdep/tsta.f90
Normal file
10
flibs-0.9/flibs/app/testdep/tsta.f90
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
! Testing dependencies
|
||||||
|
!
|
||||||
|
module a
|
||||||
|
use b
|
||||||
|
use c
|
||||||
|
end module
|
||||||
|
|
||||||
|
module b
|
||||||
|
use d
|
||||||
|
end module
|
||||||
4
flibs-0.9/flibs/app/testdep/tstc.f90
Normal file
4
flibs-0.9/flibs/app/testdep/tstc.f90
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
! Testing dependencies
|
||||||
|
!
|
||||||
|
module c
|
||||||
|
end module
|
||||||
6
flibs-0.9/flibs/app/testdep/tstd.f90
Normal file
6
flibs-0.9/flibs/app/testdep/tstd.f90
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
! Testing dependencies
|
||||||
|
!
|
||||||
|
module d
|
||||||
|
include "f.inc"
|
||||||
|
include "g.inc"
|
||||||
|
end module
|
||||||
10
flibs-0.9/flibs/app/tsta.f90
Normal file
10
flibs-0.9/flibs/app/tsta.f90
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
! Testing dependencies
|
||||||
|
!
|
||||||
|
module a
|
||||||
|
use b
|
||||||
|
use c
|
||||||
|
end module
|
||||||
|
|
||||||
|
module b
|
||||||
|
use d
|
||||||
|
end module
|
||||||
10
flibs-0.9/flibs/app/tstc.f90
Normal file
10
flibs-0.9/flibs/app/tstc.f90
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
! Testing dependencies
|
||||||
|
!
|
||||||
|
module a
|
||||||
|
use b
|
||||||
|
use c
|
||||||
|
end module
|
||||||
|
|
||||||
|
module b
|
||||||
|
use d
|
||||||
|
end module
|
||||||
207
flibs-0.9/flibs/chksys/chkcomp.f
Normal file
207
flibs-0.9/flibs/chksys/chkcomp.f
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
* @begin@ */
|
||||||
|
*
|
||||||
|
* chkcomp.f(or) - source code to check certain fetaures of the FORTRAN
|
||||||
|
* compiler
|
||||||
|
*
|
||||||
|
* Copyright (C) 1998 Arjen Markus
|
||||||
|
*
|
||||||
|
* Arjen Markus
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* General information:
|
||||||
|
* This file contains source code that uses various extensions to the
|
||||||
|
* FORTRAN standard and intentionally bad programming fragments.
|
||||||
|
* Comments explain each of them.
|
||||||
|
* Its purpose is to check if the compiler (in combination with the
|
||||||
|
* options) will flag the features.
|
||||||
|
*
|
||||||
|
* @end@
|
||||||
|
*
|
||||||
|
* $Author: arjenmarkus $
|
||||||
|
* $Date: 2008/03/17 17:57:56 $
|
||||||
|
* $Source: /cvsroot/flibs/chksys/chkcomp.f,v $
|
||||||
|
* $Log: chkcomp.f,v $
|
||||||
|
* Revision 1.1 2008/03/17 17:57:56 arjenmarkus
|
||||||
|
* Added directory "chksys" - programs to probe compiler properties
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @@------------------------------------------------------------------
|
||||||
|
* Routine: CHKSYS
|
||||||
|
* Author: Arjen Markus
|
||||||
|
* Purpose: Main program
|
||||||
|
* Context: -
|
||||||
|
* Summary:
|
||||||
|
* Show the properties of the compiler by expressly
|
||||||
|
* introducing errors and extensions
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
PROGRAM CHKCMP
|
||||||
|
*
|
||||||
|
* -------- A very useful feature: make sure that all variables
|
||||||
|
* have to be declared. Unfortunately, it is an extension
|
||||||
|
* to the FORTRAN standard
|
||||||
|
*
|
||||||
|
IMPLICIT NONE
|
||||||
|
*
|
||||||
|
CHARACTER*40 STRING
|
||||||
|
INTEGER INTVAL , INTV2 , I
|
||||||
|
REAL REAVAL
|
||||||
|
DOUBLE PRECISION DBLVAL
|
||||||
|
*
|
||||||
|
* -------- Does the compiler accept:
|
||||||
|
* - lowercase letters
|
||||||
|
* - underscores in variable names
|
||||||
|
* - long variable names
|
||||||
|
* - length of data type
|
||||||
|
*
|
||||||
|
* Note:
|
||||||
|
* None of these variables are actually used, so it may
|
||||||
|
* flag that!
|
||||||
|
*
|
||||||
|
INTEGER lowcas
|
||||||
|
INTEGER UND_SC
|
||||||
|
INTEGER LONGVARIABLENAME
|
||||||
|
INTEGER*4 INT4
|
||||||
|
INTEGER*2 INT2
|
||||||
|
*
|
||||||
|
* -------- Does the compiler support the INCLUDE-statement?
|
||||||
|
*
|
||||||
|
INCLUDE 'chkcomp.inc'
|
||||||
|
*
|
||||||
|
* -------- Some compilers accept:
|
||||||
|
* - double quotes (") to delimit strings
|
||||||
|
* - C-like escape-sequences
|
||||||
|
*
|
||||||
|
STRING = "Double quote"
|
||||||
|
STRING = '\'
|
||||||
|
*
|
||||||
|
* -------- Does the compiler register the fact that
|
||||||
|
* we are assigning too large a value? Or that
|
||||||
|
* we may loose precision?
|
||||||
|
*
|
||||||
|
INTVAL = INT( 1.0E20 )
|
||||||
|
INTVAL = 1.0E20
|
||||||
|
REAVAL = 1.0E100
|
||||||
|
REAVAL = 1.0D100
|
||||||
|
DBLVAL = 1.12345678901234567890D00
|
||||||
|
REAVAL = DBLVAL
|
||||||
|
*
|
||||||
|
* -------- Some compilers do not accept invalid substrings
|
||||||
|
* and can quite smart about it
|
||||||
|
*
|
||||||
|
WRITE(*,*) STRING(1:0)
|
||||||
|
INTVAL = LEN(STRING) + 1
|
||||||
|
WRITE(*,*) STRING(1:INTVAL)
|
||||||
|
*
|
||||||
|
* -------- Some compilers accept very long statements
|
||||||
|
* (though the number of spaces may be important as well)
|
||||||
|
*
|
||||||
|
STRING = '1' //
|
||||||
|
1 '2' //
|
||||||
|
2 '3' //
|
||||||
|
3 '4' //
|
||||||
|
4 '5' //
|
||||||
|
5 '6' //
|
||||||
|
6 '7' //
|
||||||
|
7 '8' //
|
||||||
|
8 '9' //
|
||||||
|
9 '0' //
|
||||||
|
& 'A' //
|
||||||
|
1 'B' //
|
||||||
|
2 'C' //
|
||||||
|
3 'D' //
|
||||||
|
4 'E' //
|
||||||
|
5 'F' //
|
||||||
|
6 'G' //
|
||||||
|
7 'H' //
|
||||||
|
8 'I' //
|
||||||
|
9 'J' //
|
||||||
|
& 'K' //
|
||||||
|
1 'L'
|
||||||
|
*
|
||||||
|
* -------- Use a variable before it is set
|
||||||
|
*
|
||||||
|
INTVAL = INTV2
|
||||||
|
*
|
||||||
|
* -------- Check DO-loops and IF-statements:
|
||||||
|
* - Can we change the variable?
|
||||||
|
* - Can we jump into a DO-loop or an IF block?
|
||||||
|
*
|
||||||
|
DO 100 I = 1,10
|
||||||
|
IF ( I .EQ. 5 ) I = 6
|
||||||
|
WRITE(*,*) I
|
||||||
|
100 CONTINUE
|
||||||
|
*
|
||||||
|
IF ( INTVAL .GT. 1 ) GOTO 120
|
||||||
|
IF ( INTVAL .LT. -1 ) GOTO 130
|
||||||
|
*
|
||||||
|
DO 110 I = 1,10
|
||||||
|
120 CONTINUE
|
||||||
|
WRITE(*,*) I
|
||||||
|
110 CONTINUE
|
||||||
|
*
|
||||||
|
IF ( INTVAL .GT. 2 ) THEN
|
||||||
|
130 CONTINUE
|
||||||
|
INTVAL = 10
|
||||||
|
ENDIF
|
||||||
|
*
|
||||||
|
* -------- Statements not reachable?
|
||||||
|
*
|
||||||
|
GOTO 210
|
||||||
|
WRITE(*,*) 'This statement is not reachable'
|
||||||
|
*
|
||||||
|
210 CONTINUE
|
||||||
|
IF ( INTVAL .GT. 10 ) THEN
|
||||||
|
GOTO 220
|
||||||
|
ELSE
|
||||||
|
GOTO 230
|
||||||
|
ENDIF
|
||||||
|
WRITE(*,*) 'Neither is this'
|
||||||
|
*
|
||||||
|
220 CONTINUE
|
||||||
|
230 CONTINUE
|
||||||
|
*
|
||||||
|
* -------- Check calls to routines (wrong arguments)
|
||||||
|
*
|
||||||
|
CALL SUBR1( INTVAL )
|
||||||
|
CALL SUBR2( INTVAL , INTV2 )
|
||||||
|
*
|
||||||
|
* -------- Check special comments
|
||||||
|
*
|
||||||
|
CALL PDEBUG
|
||||||
|
*
|
||||||
|
STOP
|
||||||
|
END
|
||||||
|
|
||||||
|
SUBROUTINE SUBR1( REAVAL )
|
||||||
|
*
|
||||||
|
* -------- Subroutine has one argument: a real
|
||||||
|
*
|
||||||
|
REAL REAVAL
|
||||||
|
WRITE(*,*) 'Real argument:' , REAVAL
|
||||||
|
RETURN
|
||||||
|
END
|
||||||
|
|
||||||
|
SUBROUTINE SUBR2( INTVAL )
|
||||||
|
*
|
||||||
|
* -------- Subroutine has one argument: an integer
|
||||||
|
*
|
||||||
|
INTEGER INTVAL
|
||||||
|
WRITE(*,*) 'Integer argument:' , INTVAL
|
||||||
|
RETURN
|
||||||
|
END
|
||||||
|
|
||||||
|
SUBROUTINE PDEBUG
|
||||||
|
*
|
||||||
|
* -------- Some compilers support the D and ! comments:
|
||||||
|
* D: hide/show debug-statements
|
||||||
|
* !: in-line comments
|
||||||
|
*
|
||||||
|
* (This code is put at the end because at least one
|
||||||
|
* compiler aborts on the D in the first column)
|
||||||
|
*
|
||||||
|
WRITE(*,*) 'PDEBUG' ! Dummy routine
|
||||||
|
D WRITE(*,*) 'In DEBUG mode'
|
||||||
|
*
|
||||||
|
RETURN
|
||||||
|
END
|
||||||
408
flibs-0.9/flibs/chksys/chkcompff.f90
Normal file
408
flibs-0.9/flibs/chksys/chkcompff.f90
Normal file
@@ -0,0 +1,408 @@
|
|||||||
|
! DOC
|
||||||
|
!
|
||||||
|
! chkcomff.f90 - source code to check certain features of the
|
||||||
|
! FORTRAN 90 compiler
|
||||||
|
!
|
||||||
|
! Copyright (C) 1998 Arjen Markus
|
||||||
|
!
|
||||||
|
! Arjen Markus
|
||||||
|
!
|
||||||
|
!
|
||||||
|
! General information:
|
||||||
|
! This file contains source code that uses various violations of the
|
||||||
|
! FORTRAN 90 standard and intentionally bad programming fragments.
|
||||||
|
! Comments explain each of them.
|
||||||
|
! Its purpose is to check if the compiler (in combination with the
|
||||||
|
! options) will flag the features.
|
||||||
|
!
|
||||||
|
! ENDDOC
|
||||||
|
!
|
||||||
|
! $Author: arjenmarkus $
|
||||||
|
! $Date: 2008/03/17 17:57:56 $
|
||||||
|
! $Source: /cvsroot/flibs/chksys/chkcompff.f90,v $
|
||||||
|
! $Log: chkcompff.f90,v $
|
||||||
|
! Revision 1.1 2008/03/17 17:57:56 arjenmarkus
|
||||||
|
! Added directory "chksys" - programs to probe compiler properties
|
||||||
|
!
|
||||||
|
!
|
||||||
|
! --------------------------------------------------------------------
|
||||||
|
!
|
||||||
|
! --------------------------------------------------------------------
|
||||||
|
! Module: SCOPE_MOD
|
||||||
|
! Author: Arjen Markus
|
||||||
|
! Purpose: Introduce scope problems
|
||||||
|
! Context: Used by main
|
||||||
|
! Summary:
|
||||||
|
! Define some variables to check scoping issues:
|
||||||
|
! - Variable "int_var" is also defined in the
|
||||||
|
! main program.
|
||||||
|
! - Variable "real_mod" is passed as an actual argument
|
||||||
|
! in the main program to subroutine "double_access"
|
||||||
|
! - The module uses module "sub_module" to see what happens
|
||||||
|
! to variables that are defined in sub modules: do they
|
||||||
|
! automatically become visible?
|
||||||
|
! --------------------------------------------------------------------
|
||||||
|
!
|
||||||
|
module sub_module
|
||||||
|
integer :: int_submodule
|
||||||
|
end module
|
||||||
|
module scope_mod
|
||||||
|
integer , dimension(1:10) :: int_var
|
||||||
|
real :: real_mod
|
||||||
|
end module
|
||||||
|
|
||||||
|
! --------------------------------------------------------------------
|
||||||
|
! Routine: arglist_extern
|
||||||
|
! Author: Arjen Markus
|
||||||
|
! Purpose: Show the compiler's ability to detect interface problems
|
||||||
|
! Context: Used by main program
|
||||||
|
! Summary:
|
||||||
|
! Simple subroutine, called with the wrong type of
|
||||||
|
! actual arguments
|
||||||
|
! --------------------------------------------------------------------
|
||||||
|
!
|
||||||
|
subroutine arglist_extern( intv )
|
||||||
|
!
|
||||||
|
implicit none
|
||||||
|
!
|
||||||
|
integer :: intv
|
||||||
|
|
||||||
|
write(*,*) 'Value:' , intv
|
||||||
|
return
|
||||||
|
end subroutine
|
||||||
|
|
||||||
|
! --------------------------------------------------------------------
|
||||||
|
! Program: CHKCOMP
|
||||||
|
! Author: Arjen Markus
|
||||||
|
! Purpose: Main program
|
||||||
|
! Context: -
|
||||||
|
! Summary:
|
||||||
|
! Show the properties of the compiler by expressly
|
||||||
|
! introducing (semantical) errors and extensions
|
||||||
|
! --------------------------------------------------------------------
|
||||||
|
!
|
||||||
|
program chkcmp
|
||||||
|
!
|
||||||
|
! -------- Use module "scope_mod": two levels of scope problems
|
||||||
|
! The module defines variables "int_var", "real_mod" and
|
||||||
|
! via a submodule "int_submodule".
|
||||||
|
! The scope problems are:
|
||||||
|
! - Program CHKCOMP defines a local variable "int_var"
|
||||||
|
! - Program CHKCOMP assumes "int_submodule" is available
|
||||||
|
! via "scope_mod"
|
||||||
|
! - Program CHKCOMP uses "real_mod" as an actual parameter:
|
||||||
|
! to the subroutine "double_access"
|
||||||
|
! - once for a dummy parameter with a different name
|
||||||
|
! - once for a dummy parameter with the same name
|
||||||
|
!
|
||||||
|
use scope_mod
|
||||||
|
!
|
||||||
|
! -------- A very useful feature: make sure that all variables
|
||||||
|
! have to be declared. It should be placed before any
|
||||||
|
! declarations
|
||||||
|
!
|
||||||
|
implicit none
|
||||||
|
!
|
||||||
|
! -------- FORTRAN 90 introduced the problem of scope into the
|
||||||
|
! FORTRAN world. Does the compiler flag such problems?
|
||||||
|
! The variables string_var and int_var are also used in
|
||||||
|
! subroutine scope_problem.
|
||||||
|
!
|
||||||
|
character :: string_var
|
||||||
|
integer :: int_var ! Also in "scope_mod"
|
||||||
|
real :: real_var
|
||||||
|
real , pointer , dimension(:) :: ptor
|
||||||
|
!
|
||||||
|
! -------- Does the compiler check for:
|
||||||
|
! - scoping problems
|
||||||
|
! - problems with actual argument lists (internal and external)
|
||||||
|
! - problems with double access
|
||||||
|
! - problems with incomplete logic in function
|
||||||
|
! - problems with deallocation via a pointer
|
||||||
|
! - missing interface (required when working with pointers)
|
||||||
|
! - use of variables before they are set
|
||||||
|
!
|
||||||
|
call scope_problem
|
||||||
|
call arglist_problem( real_var )
|
||||||
|
call arglist_extern( real_var )
|
||||||
|
call double_access( real_var , real_var , real_mod )
|
||||||
|
int_var = -1
|
||||||
|
write( * , * ) 'Result: ' , func_incomplete( int_var )
|
||||||
|
write( * , * ) 'Result: ' , func_no_return ( int_var )
|
||||||
|
|
||||||
|
call alloc_dealloc
|
||||||
|
call set_null( ptor )
|
||||||
|
call undefined_vars
|
||||||
|
|
||||||
|
!
|
||||||
|
! end of program
|
||||||
|
!
|
||||||
|
stop
|
||||||
|
|
||||||
|
! --------------------------------------------------------------------
|
||||||
|
! Routines: internal routines
|
||||||
|
! Author: Arjen Markus
|
||||||
|
! Contains:
|
||||||
|
! scope_problem - Show scoping problems
|
||||||
|
! arglist_problem - Show that the calls to internal routines are checked
|
||||||
|
! double_access - Show problems with double access
|
||||||
|
! func_incomplete - Show that incomplete logic brings trouble to
|
||||||
|
! functions
|
||||||
|
! --------------------------------------------------------------------
|
||||||
|
contains
|
||||||
|
|
||||||
|
! @@------------------------------------------------------------------
|
||||||
|
! Routine: scope_problem
|
||||||
|
! Author: Arjen Markus
|
||||||
|
! Purpose: Show scoping problems
|
||||||
|
! Context: Used by main program
|
||||||
|
! Summary:
|
||||||
|
! Redefine two variables that have global scope
|
||||||
|
! --------------------------------------------------------------------
|
||||||
|
!
|
||||||
|
subroutine scope_problem( )
|
||||||
|
!
|
||||||
|
implicit none
|
||||||
|
!
|
||||||
|
! -------- These variables are also defined in CHKCOMP
|
||||||
|
!
|
||||||
|
character string_var
|
||||||
|
complex int_var ! This is an integer in CHKCOMP and in
|
||||||
|
! scope_mod
|
||||||
|
|
||||||
|
int_var = (1.0,1.0)
|
||||||
|
write(*,*) 'Complex:' , int_var
|
||||||
|
return
|
||||||
|
end subroutine
|
||||||
|
|
||||||
|
! --------------------------------------------------------------------
|
||||||
|
! Routine: arglist_problem
|
||||||
|
! Author: Arjen Markus
|
||||||
|
! Purpose: Show that the calls to internal routines are checked
|
||||||
|
! Context: Used by main program
|
||||||
|
! Summary:
|
||||||
|
! Define a subroutine with a different list than used
|
||||||
|
! in the main program
|
||||||
|
! --------------------------------------------------------------------
|
||||||
|
!
|
||||||
|
subroutine arglist_problem( one_arg )
|
||||||
|
!
|
||||||
|
implicit none
|
||||||
|
!
|
||||||
|
! -------- The one argument in main is a real
|
||||||
|
!
|
||||||
|
character :: one_arg
|
||||||
|
|
||||||
|
write(*,*) 'One arg' , one_arg
|
||||||
|
return
|
||||||
|
end subroutine
|
||||||
|
|
||||||
|
! --------------------------------------------------------------------
|
||||||
|
! Routine: double_access
|
||||||
|
! Author: Arjen Markus
|
||||||
|
! Purpose: Show problems with double access
|
||||||
|
! Context: Used by main program
|
||||||
|
! Summary:
|
||||||
|
! The first dummy argument has the same name as a variable
|
||||||
|
! in the main routine. The second dummy argument has a
|
||||||
|
! different name, but the actual one substituted is
|
||||||
|
! the same. The third argument has the same name as a
|
||||||
|
! module variable.
|
||||||
|
!
|
||||||
|
! This is trouble according to the standard.
|
||||||
|
! --------------------------------------------------------------------
|
||||||
|
!
|
||||||
|
subroutine double_access( real_var , second_arg , real_mod )
|
||||||
|
!
|
||||||
|
implicit none
|
||||||
|
real :: real_var , second_arg , real_mod
|
||||||
|
|
||||||
|
real_var = second_arg + real_mod
|
||||||
|
|
||||||
|
return
|
||||||
|
end subroutine
|
||||||
|
|
||||||
|
! --------------------------------------------------------------------
|
||||||
|
! Routine: func_incomplete
|
||||||
|
! Author: Arjen Markus
|
||||||
|
! Purpose: Show that incomplete logic brings trouble to functions
|
||||||
|
! Context: Used by main program
|
||||||
|
! Summary:
|
||||||
|
! Set the function's return value ONLY if the argument is
|
||||||
|
! positive. Forget about the other possibilities. Is this
|
||||||
|
! flagged? (The function does not always return an
|
||||||
|
! explicitly set value!)
|
||||||
|
! --------------------------------------------------------------------
|
||||||
|
!
|
||||||
|
integer function func_incomplete( one_arg )
|
||||||
|
!
|
||||||
|
implicit none
|
||||||
|
!
|
||||||
|
integer :: one_arg
|
||||||
|
|
||||||
|
if ( one_arg > 0 ) then
|
||||||
|
func_incomplete = 1
|
||||||
|
endif
|
||||||
|
!
|
||||||
|
return
|
||||||
|
end function
|
||||||
|
|
||||||
|
! --------------------------------------------------------------------
|
||||||
|
! Routine: func_no_return
|
||||||
|
! Author: Arjen Markus
|
||||||
|
! Purpose: Show that functions that do not set a return value are
|
||||||
|
! flagged
|
||||||
|
! Context: Used by main program
|
||||||
|
! Summary:
|
||||||
|
! Do not set the function's return value
|
||||||
|
! --------------------------------------------------------------------
|
||||||
|
!
|
||||||
|
integer function func_no_return( one_arg )
|
||||||
|
!
|
||||||
|
implicit none
|
||||||
|
!
|
||||||
|
integer :: one_arg
|
||||||
|
integer :: return_val
|
||||||
|
|
||||||
|
if ( one_arg > 0 ) then
|
||||||
|
return_val = 1 ! Just a local!
|
||||||
|
endif
|
||||||
|
!
|
||||||
|
return
|
||||||
|
end function
|
||||||
|
|
||||||
|
! --------------------------------------------------------------------
|
||||||
|
! Routines: end of internal procedures
|
||||||
|
! --------------------------------------------------------------------
|
||||||
|
end program
|
||||||
|
|
||||||
|
! --------------------------------------------------------------------
|
||||||
|
! Routine: set_null
|
||||||
|
! Author: Arjen Markus
|
||||||
|
! Purpose: Show whether the compiler complains about lacking interfaces
|
||||||
|
! Context: Used by main program
|
||||||
|
! Summary:
|
||||||
|
! Set the one argument to NULL. As this is a pointer,
|
||||||
|
! an interface is required. Does the compiler complain?
|
||||||
|
! --------------------------------------------------------------------
|
||||||
|
!
|
||||||
|
subroutine set_null( ptor )
|
||||||
|
!
|
||||||
|
implicit none
|
||||||
|
!
|
||||||
|
real, pointer, dimension(:) :: ptor
|
||||||
|
|
||||||
|
nullify( ptor )
|
||||||
|
return
|
||||||
|
end subroutine
|
||||||
|
|
||||||
|
! --------------------------------------------------------------------
|
||||||
|
! Routine: use_interface
|
||||||
|
! Author: Arjen Markus
|
||||||
|
! Purpose: Show the strange error messages when using interfaces wrongly
|
||||||
|
! Context: Used by main program
|
||||||
|
! Summary:
|
||||||
|
! Define an interface with a name at the end
|
||||||
|
! --------------------------------------------------------------------
|
||||||
|
!
|
||||||
|
subroutine use_interface
|
||||||
|
!
|
||||||
|
implicit none
|
||||||
|
!
|
||||||
|
real, pointer, dimension(:) :: ptor
|
||||||
|
real, pointer, dimension(:) :: ptor2
|
||||||
|
|
||||||
|
!
|
||||||
|
! The end interface statement should not contain the name!
|
||||||
|
! Note:
|
||||||
|
! Some compilers will accept this. Others do not.
|
||||||
|
!
|
||||||
|
interface null_pointer
|
||||||
|
subroutine set_null( ptor )
|
||||||
|
real, pointer, dimension(:) :: ptor
|
||||||
|
end subroutine
|
||||||
|
end interface null_pointers
|
||||||
|
|
||||||
|
call null_pointer( ptor )
|
||||||
|
call null_pointer( ptor2 )
|
||||||
|
|
||||||
|
return
|
||||||
|
end subroutine
|
||||||
|
|
||||||
|
! --------------------------------------------------------------------
|
||||||
|
! Routine: alloc_dealloc
|
||||||
|
! Author: Arjen Markus
|
||||||
|
! Purpose: Show that the compiler can detect obvious deallocation
|
||||||
|
! problems
|
||||||
|
! Context: Used by main program
|
||||||
|
! Summary:
|
||||||
|
! Allocate an allocatable array, set a pointer to it
|
||||||
|
! and deallocate via the pointer - this violates the
|
||||||
|
! standard's access rules.
|
||||||
|
! --------------------------------------------------------------------
|
||||||
|
!
|
||||||
|
subroutine alloc_dealloc
|
||||||
|
!
|
||||||
|
implicit none
|
||||||
|
!
|
||||||
|
real, pointer, dimension(:) :: ptor
|
||||||
|
real, allocatable, dimension(:) :: rarray
|
||||||
|
|
||||||
|
!
|
||||||
|
! Allocate the array and deallocate via the pointer
|
||||||
|
!
|
||||||
|
allocate( rarray(1:10) )
|
||||||
|
|
||||||
|
ptor => rarray
|
||||||
|
deallocate( ptor )
|
||||||
|
|
||||||
|
return
|
||||||
|
end subroutine
|
||||||
|
|
||||||
|
! --------------------------------------------------------------------
|
||||||
|
! Routine: undefined_vars
|
||||||
|
! Author: Arjen Markus
|
||||||
|
! Purpose: Show that the compiler can detect assignments that
|
||||||
|
! use undefined variables
|
||||||
|
! Context: Used by main program
|
||||||
|
! Summary:
|
||||||
|
! Use unset local variables in an assignment.
|
||||||
|
! Compare reals (another obvious problem).
|
||||||
|
! Convert double to real (yet another obvious problem).
|
||||||
|
! --------------------------------------------------------------------
|
||||||
|
!
|
||||||
|
subroutine undefined_vars
|
||||||
|
!
|
||||||
|
implicit none
|
||||||
|
!
|
||||||
|
real :: result
|
||||||
|
real :: operand_a
|
||||||
|
real :: operand_b
|
||||||
|
real , pointer :: ptor
|
||||||
|
double precision :: dbl_value
|
||||||
|
|
||||||
|
!
|
||||||
|
! Assignment with undefined variables
|
||||||
|
!
|
||||||
|
result = operand_a + operand_b
|
||||||
|
|
||||||
|
!
|
||||||
|
! Silently convert double precision to single
|
||||||
|
!
|
||||||
|
dbl_value = atan( 1.0d+00 )
|
||||||
|
result = dbl_value
|
||||||
|
|
||||||
|
!
|
||||||
|
! Compare reals
|
||||||
|
!
|
||||||
|
if ( result .ne. dbl_value ) then
|
||||||
|
write( * , * ) 'Some truncation occurred!'
|
||||||
|
endif
|
||||||
|
|
||||||
|
!
|
||||||
|
! Write unassigned pointer to screen
|
||||||
|
!
|
||||||
|
write( * , * ) ptor
|
||||||
|
|
||||||
|
return
|
||||||
|
end subroutine
|
||||||
40
flibs-0.9/flibs/chksys/chkcompff_extra.f90
Normal file
40
flibs-0.9/flibs/chksys/chkcompff_extra.f90
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
! Extra checks on Fortran 95 compiler:
|
||||||
|
!
|
||||||
|
! character(len=lenarg) - in subroutines, lenarg is an argument
|
||||||
|
!
|
||||||
|
! allocate( array(0) ) - is it allocated or not?
|
||||||
|
!
|
||||||
|
! allocatable components in derived type
|
||||||
|
!
|
||||||
|
program chkf95
|
||||||
|
integer, dimension(:), allocatable, target :: array
|
||||||
|
integer, dimension(:), pointer :: parray
|
||||||
|
type pointer
|
||||||
|
integer, dimension(:), pointer :: parray
|
||||||
|
end type
|
||||||
|
|
||||||
|
type(pointer) :: p
|
||||||
|
|
||||||
|
allocate( array(0) )
|
||||||
|
|
||||||
|
parray => array
|
||||||
|
p%parray => array
|
||||||
|
|
||||||
|
if ( allocated(array) ) then
|
||||||
|
write(*,*) 'Array is allocated - size: ', size(array)
|
||||||
|
else
|
||||||
|
write(*,*) 'Array is reported as NOT allocated'
|
||||||
|
endif
|
||||||
|
|
||||||
|
if ( associated(parray) ) then
|
||||||
|
write(*,*) 'Pointer to array is associated - size: ', size(parray)
|
||||||
|
else
|
||||||
|
write(*,*) 'Pointer to array is reported as NOT associated'
|
||||||
|
endif
|
||||||
|
|
||||||
|
if ( associated(p%parray) ) then
|
||||||
|
write(*,*) '(Component) Pointer to array is associated - size: ', size(p%parray)
|
||||||
|
else
|
||||||
|
write(*,*) '(Component) Pointer to array is reported as NOT associated'
|
||||||
|
endif
|
||||||
|
end program
|
||||||
1372
flibs-0.9/flibs/chksys/chksys.f
Normal file
1372
flibs-0.9/flibs/chksys/chksys.f
Normal file
File diff suppressed because it is too large
Load Diff
365
flibs-0.9/flibs/chksys/chksys.html
Normal file
365
flibs-0.9/flibs/chksys/chksys.html
Normal file
@@ -0,0 +1,365 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>CHKSYS: Check compiler and run-time environment</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>
|
||||||
|
Checking properties of the compiler and the run-time
|
||||||
|
environment
|
||||||
|
</h1>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>chksys.f</td>
|
||||||
|
<td>A program to determine the properties of the
|
||||||
|
run-time environment for FORTRAN 77 programs</td>
|
||||||
|
</tr><tr>
|
||||||
|
<td>chkcomp.f</td>
|
||||||
|
<td>A FORTRAN 77 source file containing deliberate deviations
|
||||||
|
from the standard and deliberate bad statements for testing the
|
||||||
|
compiler's accuracy</td>
|
||||||
|
</tr><tr>
|
||||||
|
<td>chksysff.f90</td>
|
||||||
|
<td>A program to determine the properties of the
|
||||||
|
run-time environment for Fortran 90 programs</td>
|
||||||
|
</tr><tr>
|
||||||
|
<td>chkcomff.f90</td>
|
||||||
|
<td>A Fortran 90 source file containing deliberate deviations
|
||||||
|
from the standard and deliberate bad statements for testing the
|
||||||
|
compiler's accuracy</td>
|
||||||
|
</tr><tr>
|
||||||
|
<td>chksysc.c</td>
|
||||||
|
<td>A program to determine the properties of the run-time
|
||||||
|
environment for C programs</td>
|
||||||
|
</tr><tr>
|
||||||
|
<td>chkcompc.c</td>
|
||||||
|
<td>A C source file containing deliberate deviations from
|
||||||
|
the standard and deliberate bad statements for testing the
|
||||||
|
compiler's accuracy</td>
|
||||||
|
</tr>
|
||||||
|
</tr><tr>
|
||||||
|
<td>fp_special.f90</td>
|
||||||
|
<td>A Fortran 90 program to test the behaviour of a program in the
|
||||||
|
presence of floating-point exceptions and special IEEE numbers
|
||||||
|
(notably negative zeros)</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<h3>Introduction</h3>
|
||||||
|
<p>
|
||||||
|
The programs CHKSYS and CHKSYSFF are meant to help understand the
|
||||||
|
run-time environment of a FORTRAN program. For C there is a similar
|
||||||
|
program, CHKSYSC.
|
||||||
|
<p>
|
||||||
|
In many cases the actual behaviour of a program depends on the compiler
|
||||||
|
you use and the options you included during the compile and link steps.
|
||||||
|
This is especially true if errors occur or if you are using certain
|
||||||
|
open-ended language features.
|
||||||
|
<p>
|
||||||
|
Many programmers are not aware that such features exist and it is
|
||||||
|
sometimes difficult or impossible to find them in the documentation.
|
||||||
|
<p>
|
||||||
|
That is where the CHKSYS offer some assistence:
|
||||||
|
<ul>
|
||||||
|
<li>It checks areas that are open-ended, such as whether local variables
|
||||||
|
are automatically saved between subroutine calls and various odd
|
||||||
|
errors that can occur when using external files.
|
||||||
|
<li>It checks how (deliberate) run-time errors are handled, such as an
|
||||||
|
overflow or an exceedance of array bounds.
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
The program source CHKCOMP (in chkcomp.f(or) and its Fortran 90
|
||||||
|
equivalent chkcomff.f90) is meant to test the accuracy of the compiler.
|
||||||
|
It is not meant to validate the compiler. It simply contains a fair
|
||||||
|
number of very common extensions to the standard
|
||||||
|
and some deliberate program errors (like jumping into a DO-loop and
|
||||||
|
inaccessible statements). The errors are documented in the source code
|
||||||
|
via comments.
|
||||||
|
<p>
|
||||||
|
The rest of this document describes:
|
||||||
|
<br><a href="#usage">How to use the programs</a>
|
||||||
|
<br><a href="#tests">Description of the tests</a>
|
||||||
|
<br><a href="#results">Presentation of some results</a>
|
||||||
|
<p>
|
||||||
|
<p>
|
||||||
|
<a name="usage"><h3>Usage of the programs</h3></a>
|
||||||
|
<b>CHKCOMP:</b>
|
||||||
|
<ul>
|
||||||
|
<li>First run the compiler of choice with standard options
|
||||||
|
<li>Then try to find out what extra options are needed to get the
|
||||||
|
maximum set of messages. Such options include:
|
||||||
|
<ul>
|
||||||
|
<li>Highest warning level
|
||||||
|
<li>Check strict conformance to standard
|
||||||
|
<li>Check interfaces
|
||||||
|
<li>etc.
|
||||||
|
</ul>
|
||||||
|
<li>In general, it is a good idea to ALWAYS ask for the maximum number of
|
||||||
|
checks, as this can prevent programming errors at an early stage.
|
||||||
|
<li>Some (or many) compilers are lazy: they will offer very little checks
|
||||||
|
beyond basic syntax. Shun such compilers - or at least use appropriate
|
||||||
|
program checkers beside them.
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
<b>CHKSYS:</b>
|
||||||
|
<ul>
|
||||||
|
<li>Compile the program with the same options as the CHKCOMP source. If
|
||||||
|
this would result in errors, remove the strict conformance to the
|
||||||
|
standard, as it uses one, common, extension: IMPLICIT NONE.
|
||||||
|
<li>Run the program once to get the general features of the run-time
|
||||||
|
environment
|
||||||
|
<li>Edit the file "chksys.set" to select the more disruptive tests.
|
||||||
|
<li>Study the source code and the file "chksys.msg" to see how things
|
||||||
|
are done. You might learn something from it or you might have
|
||||||
|
suggestions.
|
||||||
|
<li>Use various compiler options:
|
||||||
|
<ul>
|
||||||
|
<li>With and without optimisations
|
||||||
|
<li>Array bounds checking
|
||||||
|
<li>Strict conformance to the standard
|
||||||
|
<li>Numerical options (like treatment of overflows and underflows)
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
<p>
|
||||||
|
<a name="tests"><h3>Tests that are performed</h3></a>
|
||||||
|
<b>CHKSYS</b> performs the following tests:
|
||||||
|
<ul>
|
||||||
|
<li>Operating system:
|
||||||
|
<ul>
|
||||||
|
<li>What type of system (UNIX, MS-DOS/Windows 3.x or Windows 95/NT)?
|
||||||
|
<li>Support for long file names?
|
||||||
|
<li>Distinction between upper and lower case in file names?
|
||||||
|
</ul>
|
||||||
|
<li>Memory model:
|
||||||
|
<ul>
|
||||||
|
<li>Static (local variables are automatically saved) or
|
||||||
|
dynamic (you must use SAVE to save the values)
|
||||||
|
<li>Length of an integer:
|
||||||
|
<ul>
|
||||||
|
<li>2 or 4 bytes? Often selectable via compiler switch. Determines
|
||||||
|
range
|
||||||
|
</ul>
|
||||||
|
<li>Precision of real variables and numerical operations:
|
||||||
|
<ul>
|
||||||
|
<li>How many decimals are significant?
|
||||||
|
<li>Any obvious problems with multiplications
|
||||||
|
</ul>
|
||||||
|
<li>What is the unit for the length of a direct-access record?
|
||||||
|
<ul>
|
||||||
|
<li>Often a byte, sometimes a word (e.g. 4 bytes!)
|
||||||
|
</ul>
|
||||||
|
<li>Are binary files allowed? And what keywords do you use?
|
||||||
|
<li>How many files can be opened at the same time?
|
||||||
|
<li>File handling:
|
||||||
|
<ul>
|
||||||
|
<li>Are the parameters to the OPEN statement checked immediately?
|
||||||
|
<li>Using unformatted READs on a formatted file
|
||||||
|
<li>Writing to an unopened file
|
||||||
|
<li>Reading too many data from a record of an unformatted file
|
||||||
|
<li>Writing too many data to a record of a direct-access file
|
||||||
|
<li>Opening the same file twice
|
||||||
|
<li>Closing an unopened file
|
||||||
|
<li>Opening a second file to the same unit
|
||||||
|
<li>Reading files of which the last line is incomplete
|
||||||
|
</ul>
|
||||||
|
<li>Check the behaviour of DO-loops:
|
||||||
|
<ul>
|
||||||
|
<li>Can you change the value of a DO-variable?
|
||||||
|
<li>What happens if you change the upper limit?
|
||||||
|
<li>Are DO-loops performed at least once? (They should not!)
|
||||||
|
</ul>
|
||||||
|
<li>Check the behaviour of overlapping substrings:
|
||||||
|
<ul>
|
||||||
|
<li>Shifting characters to the left and right
|
||||||
|
</ul>
|
||||||
|
<li>Miscellaneous stuff:
|
||||||
|
<ul>
|
||||||
|
<li>Treatment of a backslash (C-like espace character?)
|
||||||
|
<li>Formatting in list-directed output
|
||||||
|
<li>The first character when writing to the screen
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
<p>
|
||||||
|
<a name="results"><h3>Some results</h3></a>
|
||||||
|
<i>Compiling CHKCOMP:</i>
|
||||||
|
<p>
|
||||||
|
The first listing is the result when using MicroSoft FORTRAN version 5.1,
|
||||||
|
with the maximum level of warnings (which turns out to be the default)
|
||||||
|
but not the switch to force checking against the standard:
|
||||||
|
<pre>
|
||||||
|
chkcomp.for(79) : error F2566: INTEGER : REAL : type conversion error
|
||||||
|
chkcomp.for(80) : error F2566: INTEGER : REAL : type conversion error
|
||||||
|
chkcomp.for(81) : error F2005: illegal REAL constant
|
||||||
|
chkcomp.for(82) : error F2566: REAL : REAL : type conversion error
|
||||||
|
chkcomp.for(128) : error F2516: I : assignment using active DO variable illegal
|
||||||
|
chkcomp.for(136) : warning F4801: label 120 : used across blocks
|
||||||
|
chkcomp.for(141) : warning F4801: label 130 : used across blocks
|
||||||
|
chkcomp.for(171) : warning F4999: LOWCAS : variable declared but not used
|
||||||
|
chkcomp.for(171) : warning F4999: LONGVARIABLENAME : variable declared but not used
|
||||||
|
chkcomp.for(171) : warning F4999: UND_SC : variable declared but not used
|
||||||
|
chkcomp.for(171) : warning F4999: INT2 : variable declared but not used
|
||||||
|
chkcomp.for(171) : warning F4999: INT4 : variable declared but not used
|
||||||
|
chkcomp.for(171) : warning F4999: INTV2 : variable declared but not used
|
||||||
|
chkcomp.for(171) : warning F4999: DBLVAL : variable declared but not used
|
||||||
|
chkcomp.for(171) : warning F4999: REAVAL : variable declared but not used
|
||||||
|
chkcomp.for(178) : error F3606: SUBR1 : formal argument REAVAL : type mismatch
|
||||||
|
chkcomp.for(187) : error F2202: SUBR2 : defined with different number of arguments
|
||||||
|
</pre>
|
||||||
|
<p>
|
||||||
|
Below is a listing from the Lahey FORTRAN 77 compiler, version 5.20,
|
||||||
|
using no particular switches:
|
||||||
|
<pre>
|
||||||
|
Compiling chkcomp.for, a Standard Format Source File
|
||||||
|
|
||||||
|
OPTION DESCRIPTION OPTION DESCRIPTION
|
||||||
|
/n0 - Standard FORTRAN 77 IMPLICIT /nL - No Line-number table
|
||||||
|
/n2 - Generate 387 constants and code / P - Protect constant arguments
|
||||||
|
/n4 - No 80486 optimizations /nQ1 - "Unlimited" NDP stack
|
||||||
|
/n7 - Optimize inter-statement /nQ2 - No protected-mode RPC
|
||||||
|
/nA2 - No allocatable array checking /nQ3 - No real-mode RPC
|
||||||
|
/nB - No Bounds checking / R - Remember local variables
|
||||||
|
/nC - Ignore nonstandard usage / S - Create filename.SLD for SOLD
|
||||||
|
/nC1 - INTEGER constants 4 bytes /nT - INTEGER*4, LOGICAL*4 default
|
||||||
|
/nD - DIRECT files with headers /nV - Not VAX interpretation
|
||||||
|
/nH - No Hardcopy source listing / W - Display Warning messages
|
||||||
|
/nI - No Interface checking /nX - No Xref listing
|
||||||
|
/nK - Generate 80x87 code /nZ1 - Better SOLD debugging
|
||||||
|
|
||||||
|
Compiling line 35: PROGRAM CHKCMP
|
||||||
|
File chkcomp.for, line 80:
|
||||||
|
INTVAL = 1.0E20
|
||||||
|
^
|
||||||
|
Warning - INTEGER variable (INTVAL) possibly assigned new value before
|
||||||
|
former value used.
|
||||||
|
|
||||||
|
File chkcomp.for, line 81:
|
||||||
|
REAVAL = 1.0E100
|
||||||
|
^
|
||||||
|
Fatal - Expression is not within numeric limits of REAL data type
|
||||||
|
(1.18E-38 : 3.40E+38) (See Section 6.3 in Lahey Programmer's Reference).
|
||||||
|
|
||||||
|
File chkcomp.for, line 82:
|
||||||
|
REAVAL = 1.0D100
|
||||||
|
^
|
||||||
|
Warning - REAL variable (REAVAL) possibly assigned new value before former
|
||||||
|
value used.
|
||||||
|
|
||||||
|
File chkcomp.for, line 84:
|
||||||
|
REAVAL = DBLVAL
|
||||||
|
^
|
||||||
|
Warning - REAL variable (REAVAL) possibly assigned new value before former
|
||||||
|
value used.
|
||||||
|
|
||||||
|
File chkcomp.for, line 90:
|
||||||
|
INTVAL = LEN(STRING) + 1
|
||||||
|
^
|
||||||
|
Warning - INTEGER variable (INTVAL) possibly assigned new value before
|
||||||
|
former value used.
|
||||||
|
|
||||||
|
File chkcomp.for, line 121:
|
||||||
|
INTVAL = INTV2
|
||||||
|
^
|
||||||
|
Warning - INTEGER variable (INTV2) is used before being assigned a value.
|
||||||
|
|
||||||
|
File chkcomp.for, line 128:
|
||||||
|
IF ( I .EQ. 5 ) I = 6
|
||||||
|
^^
|
||||||
|
Fatal - INTEGER variable (I) is a DO index, cannot assign a value (See
|
||||||
|
Section 8.4.1 in Lahey Language Reference).
|
||||||
|
Fatal - Statement illegal as IF suffix (See Section 8.5.2.2 in Lahey
|
||||||
|
Language Reference).
|
||||||
|
|
||||||
|
File chkcomp.for, line 148:
|
||||||
|
WRITE(*,*) 'This statement is not reachable'
|
||||||
|
^
|
||||||
|
Warning - No execution path reaches this statement.
|
||||||
|
|
||||||
|
File chkcomp.for, line 156:
|
||||||
|
WRITE(*,*) 'Neither is this'
|
||||||
|
^
|
||||||
|
Warning - No execution path reaches this statement.
|
||||||
|
|
||||||
|
Warning - INTEGER variable (LOWCAS) is declared but never used,
|
||||||
|
File chkcomp.for, line 58.
|
||||||
|
Warning - INTEGER variable (UND_SC) is declared but never used,
|
||||||
|
File chkcomp.for, line 59.
|
||||||
|
Warning - INTEGER variable (LONGVARIABLENAME) is declared but never used,
|
||||||
|
File chkcomp.for, line 60.
|
||||||
|
Warning - INTEGER variable (INT4) is declared but never used,
|
||||||
|
File chkcomp.for, line 61.
|
||||||
|
Warning - INTEGER*2 variable (INT2) is declared but never used,
|
||||||
|
File chkcomp.for, line 62.
|
||||||
|
|
||||||
|
Fatal - Expression is not within numeric limits of INTEGER data type
|
||||||
|
(-2,147,483,648 : 2,147,483,647) (See Section 6.3 in Lahey Programmer's
|
||||||
|
Reference), File chkcomp.for, line 79.
|
||||||
|
Fatal - Expression is not within numeric limits of INTEGER data type
|
||||||
|
(-2,147,483,648 : 2,147,483,647) (See Section 6.3 in Lahey Programmer's
|
||||||
|
Reference), File chkcomp.for, line 80.
|
||||||
|
Warning - REAL variable (REAVAL) assigned a value, never used,
|
||||||
|
File chkcomp.for, lines 81, 82, 84.
|
||||||
|
Fatal - Expression is not within numeric limits of REAL data type
|
||||||
|
(1.18E-38 : 3.40E+38) (See Section 6.3 in Lahey Programmer's Reference),
|
||||||
|
File chkcomp.for, line 82.
|
||||||
|
Fatal - Substring specifier must be > 0 and <= string length (See Section
|
||||||
|
4.4.4.1 in Lahey Language Reference), File chkcomp.for, line 89.
|
||||||
|
Fatal - Statement label (120) appears in transfer context outside DO range
|
||||||
|
or block IF (See Chapter 8 in Lahey Language Reference), File chkcomp.for,
|
||||||
|
line 132.
|
||||||
|
Fatal - Statement label (130) appears in transfer context outside DO range
|
||||||
|
or block IF (See Chapter 8 in Lahey Language Reference), File chkcomp.for,
|
||||||
|
line 133.
|
||||||
|
|
||||||
|
Compiling line 173: SUBROUTINE SUBR1( REAVAL )
|
||||||
|
Compiling line 182: SUBROUTINE SUBR2( INTVAL )
|
||||||
|
File chkcomp.for, line 182:
|
||||||
|
SUBROUTINE SUBR2( INTVAL )
|
||||||
|
^
|
||||||
|
Warning - Argument count conflicts with previous usage (See Section 10.3.1
|
||||||
|
in Lahey Language Reference).
|
||||||
|
|
||||||
|
Compiling line 191: SUBROUTINE PDEBUG
|
||||||
|
File chkcomp.for, line 201:
|
||||||
|
D WRITE(*,*) 'In DEBUG mode'
|
||||||
|
|
||||||
|
Abort - Standard source file, columns 1-5: blanks and/or digits (See
|
||||||
|
Section 1.6 in Lahey Language Reference).
|
||||||
|
|
||||||
|
</pre>
|
||||||
|
Both compilers are fairly old (copyrights indicate 1992), but they
|
||||||
|
do show the capabilities of a good compiler:
|
||||||
|
<ul>
|
||||||
|
<li>Interface checks:
|
||||||
|
<ul>
|
||||||
|
<li><i>These are a major source of errors</i> and
|
||||||
|
unfortunately FORTRAN 77 provides no prototyping mechanisms.
|
||||||
|
The compilers check the consistency <i>within the file</i> only.
|
||||||
|
</ul>
|
||||||
|
<li>Use and misuse of variables:
|
||||||
|
<ul>
|
||||||
|
<li>Both warn about variables that have been declared, but not been used.
|
||||||
|
<li>The Lahey compiler does a more thorough job, because it also warns
|
||||||
|
about <i>new assignments before the previous value was used</i>.
|
||||||
|
<li>Illegal use of DO-loop variables.
|
||||||
|
</ul>
|
||||||
|
<li>Unreachable statements:
|
||||||
|
<ul>
|
||||||
|
<li>The MicroSoft compiler does not warn us about them
|
||||||
|
<li>The Lahey compiler does a pretty thorough job! It even detects the
|
||||||
|
problem with this construct:
|
||||||
|
<pre>
|
||||||
|
151 IF ( INTVAL .GT. 10 ) THEN
|
||||||
|
152 GOTO 220
|
||||||
|
153 ELSE
|
||||||
|
154 GOTO 230
|
||||||
|
155 ENDIF
|
||||||
|
156 WRITE(*,*) 'Neither is this'
|
||||||
|
</pre>
|
||||||
|
<li>Illegal substrings:
|
||||||
|
<ul>
|
||||||
|
<li>Note the <i>fatal</i> error for line 89: we are using a zero-length
|
||||||
|
substring.
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
635
flibs-0.9/flibs/chksys/chksys.msg
Normal file
635
flibs-0.9/flibs/chksys/chksys.msg
Normal file
@@ -0,0 +1,635 @@
|
|||||||
|
@INTRODUCTION
|
||||||
|
CHKSYS: A program to determine the properties of the run-time
|
||||||
|
environment for FORTRAN programs
|
||||||
|
|
||||||
|
The program presents information about:
|
||||||
|
- What type of system are you running on (e.g. UNIX or MS Windows)?
|
||||||
|
- What restrictions for file names?
|
||||||
|
- Are local variables in subroutines SAVEd or not?
|
||||||
|
- Other matters concerning portability and the detection of
|
||||||
|
run-time errors.
|
||||||
|
|
||||||
|
Note:
|
||||||
|
Some systems will ask for a file name when a READ/WRITE occurs to an
|
||||||
|
openend file (unit number) as occurs in the third file-handling test.
|
||||||
|
The program can not prevent the question but it tries to detect the
|
||||||
|
result. So:
|
||||||
|
First run the program without redirection. Then you know what happens.
|
||||||
|
The recommended file name is "askfile".
|
||||||
|
|
||||||
|
Note:
|
||||||
|
Some tests may cause the program to crash or, in the worst to let
|
||||||
|
the whole system hang (on PC). So the file "chksys.set" can be used
|
||||||
|
to control whether such tests are performed.
|
||||||
|
|
||||||
|
@FILE-SYSTEM
|
||||||
|
File system
|
||||||
|
-----------
|
||||||
|
The following information about the operating system and the file
|
||||||
|
system is obtained:
|
||||||
|
|
||||||
|
@PROGRAM-ERROR
|
||||||
|
*** Error:
|
||||||
|
*** The program has come up with an unknown condition.
|
||||||
|
*** Please check this!
|
||||||
|
|
||||||
|
@OS-UNKNOWN
|
||||||
|
Operating system: Unknown. The following information might be misleading
|
||||||
|
|
||||||
|
@OS-UNIX
|
||||||
|
Operating system: The program is running under UNIX
|
||||||
|
|
||||||
|
@OS-DOS-WINDOWS
|
||||||
|
Operating system: The program is running under MS DOS or MS Windows 3.x
|
||||||
|
|
||||||
|
@OS-WINDOWS-95-NT
|
||||||
|
Operating system: The program is running under MS Windows 95 or NT
|
||||||
|
(No further distinction can be made)
|
||||||
|
|
||||||
|
@FILE-SYSTEM-SHORT-NAMES
|
||||||
|
The file system supports short file names only (either the DOS convention
|
||||||
|
or an old UNIX System V convention)
|
||||||
|
|
||||||
|
@FILE-SYSTEM-LONG-NAMES
|
||||||
|
The file system supports long file names (more than 14 characters)
|
||||||
|
|
||||||
|
@FILE-SYSTEM-IGNORE-CASE
|
||||||
|
File names are insensitive to uppercase and lowercase (e.g. CHKSYS.MSG
|
||||||
|
and chksys.msg are equivalent)
|
||||||
|
|
||||||
|
@FILE-SYSTEM-RESPECT-CASE
|
||||||
|
The file system distinguishes between uppercase and lowercase in file
|
||||||
|
names (e.g. CHKSYS.MSG and chksys.msg are not the same files!)
|
||||||
|
|
||||||
|
@FILE-DIRECT-ACCESS
|
||||||
|
Record length for direct access files
|
||||||
|
-------------------------------------
|
||||||
|
A widespread misunderstanding of direct-access files is, that the
|
||||||
|
record length is expressed in bytes (or perhaps characters). Thus a
|
||||||
|
record that should contain 10 ordinary integers should have at least
|
||||||
|
length 40:
|
||||||
|
|
||||||
|
OPEN( 10 , FILE = 'direct.dat' , RECL = 40 )
|
||||||
|
WRITE( 10 , REC = 1 ) ( IARRAY(I) , I = 1,10 )
|
||||||
|
|
||||||
|
In fact this is compiler-dependent! Some compilers use a "word"
|
||||||
|
(commonly 32 bits or 4 bytes) as the unit of length. The OPEN
|
||||||
|
statement would then need to be:
|
||||||
|
|
||||||
|
OPEN( 10 , FILE = 'direct.dat' , RECL = 10 )
|
||||||
|
|
||||||
|
In this case:
|
||||||
|
|
||||||
|
@FILE-BINARY-FILES
|
||||||
|
Use of binary files
|
||||||
|
-------------------
|
||||||
|
Some FORTRAN compilers allow BINARY files as an extension to
|
||||||
|
the standard. Such files have the advantage of being independent
|
||||||
|
of the FORTRAN compiler, in contrast to the ordinary UNFORMATTED
|
||||||
|
files. Binary files can easily be used in a C program for instance.
|
||||||
|
|
||||||
|
Unfortunately, each compiler has its own way of specifying such files.
|
||||||
|
|
||||||
|
@FILE-BINARY-FILES-ALLOWED
|
||||||
|
The current compiler supports binary files. Use the following keywords
|
||||||
|
in the OPEN statement:
|
||||||
|
|
||||||
|
@FILE-BINARY-FILES-NOT-ALLOWED
|
||||||
|
The current compiler does NOT support binary files.
|
||||||
|
|
||||||
|
@NUMBER-OPEN-FILES
|
||||||
|
Maximum number of open files
|
||||||
|
----------------------------
|
||||||
|
All systems have a limit to the number of files that can opened at the
|
||||||
|
same time.
|
||||||
|
|
||||||
|
@NUMBER-OPEN-FILES-LIMITED
|
||||||
|
The current system allows a limited number of open files:
|
||||||
|
|
||||||
|
@NUMBER-OPEN-FILES-UNLIMITED
|
||||||
|
The current system allows at least 90 open files, which for almost all
|
||||||
|
practical purposes is quite enough.
|
||||||
|
|
||||||
|
@FILE-STANDARD
|
||||||
|
Standard LU-numbers
|
||||||
|
-------------------
|
||||||
|
FORTRAN 77 uses several standard LU numbers, such as 5 for reading
|
||||||
|
input from the keyboard. The list below shows which standard LU numbers
|
||||||
|
are used an to what files they are connected:
|
||||||
|
|
||||||
|
@LENGTH-INTEGER
|
||||||
|
Number of bytes for integers
|
||||||
|
----------------------------
|
||||||
|
Many compilers offer an option to set the default length for integer
|
||||||
|
variables. Thus the range for variables declared as INTEGER is
|
||||||
|
sometimes from -32767 to 32767 (the length of an integer is 2 bytes)
|
||||||
|
and sometimes from -2147483647 to 2147483647 (the length of an
|
||||||
|
integer is 4 bytes).
|
||||||
|
|
||||||
|
In contrast to FORTRAN 90, FORTRAN 77 does not allow these limits to
|
||||||
|
be easily detected.
|
||||||
|
|
||||||
|
According to the test however:
|
||||||
|
@NUMERICAL-PRECISION
|
||||||
|
Numerical precision
|
||||||
|
-------------------
|
||||||
|
The program tries to obtain some information about the numerical aspects
|
||||||
|
of the compiler and run-time environment:
|
||||||
|
- The number of significant decimals in single and double precision reals
|
||||||
|
- The precision of certain operations: is x*y equal to y*x,
|
||||||
|
is x*y equal to(-x)*(-y), is -x equal to abs(x) if x < 0
|
||||||
|
(Reports from several sources show that this need not be the case!)
|
||||||
|
|
||||||
|
Note:
|
||||||
|
A program like "paranoia" is capable of doing a thorough test on
|
||||||
|
numerical operations. The tests here are quick and dirty, to get
|
||||||
|
some insight quickly.
|
||||||
|
|
||||||
|
Test 1: Number of significant decimals in single and double precision reals
|
||||||
|
-------
|
||||||
|
In most cases the number of significant decimals is 7 for single precision
|
||||||
|
and 15 for double precision. The numbers are established in two ways:
|
||||||
|
- A simple approach
|
||||||
|
- A roundabout approach
|
||||||
|
The latter is necessary because some compilers seem to use caching
|
||||||
|
techniques, which gives rise to strange results.
|
||||||
|
|
||||||
|
@NUMERICAL-COMMUTATIVE
|
||||||
|
Test 2: Is multiplication commutative (i.e. x*y equal y*x)?
|
||||||
|
-------
|
||||||
|
The test is not exhaustive, but if the test shows that multiplication
|
||||||
|
is NOT commutative, then you are in trouble.
|
||||||
|
|
||||||
|
@NUMERICAL-NEGATIVE
|
||||||
|
Test 3: Is the sign of influence on multiplication?
|
||||||
|
-------
|
||||||
|
The test looks for differences in: x*y and (-x)*(-y). The test is NOT
|
||||||
|
exhaustive, but merely indicates a potential for trouble.
|
||||||
|
|
||||||
|
@NUMERICAL-ABSOLUTE
|
||||||
|
Test 4: Is (-x) equal to abs(x)?
|
||||||
|
-------
|
||||||
|
The test looks for differences in: -x and abs(x), with x negative.
|
||||||
|
The test is NOT exhaustive, but merely indicates a potential
|
||||||
|
for trouble.
|
||||||
|
|
||||||
|
@NUMERICAL-UNWANTED-RESULT-SINGLE
|
||||||
|
The test showed differences between the two calculation results
|
||||||
|
for SINGLE precision. This may give trouble in numerical calculations.
|
||||||
|
|
||||||
|
@NUMERICAL-UNWANTED-RESULT-DOUBLE
|
||||||
|
The test showed differences between the two calculation results
|
||||||
|
for DOUBLE precision. This may give trouble in numerical calculations.
|
||||||
|
|
||||||
|
@NUMERICAL-RESULT-ALLRIGHT
|
||||||
|
The test showed NO differences between the two calculation results.
|
||||||
|
This is no guarantee, but indicates that there are no obvious problems.
|
||||||
|
|
||||||
|
@NUMERICAL-STRANGE-PRECISION
|
||||||
|
Warning:
|
||||||
|
The simple approach showed that single and double precision have
|
||||||
|
a very large, equal, precision. This is probably due to caching of
|
||||||
|
intermediate results of calculations. Try again without any optimisation.
|
||||||
|
|
||||||
|
The simple approach gives the following results:
|
||||||
|
|
||||||
|
@FILE-HANDLING
|
||||||
|
File handling
|
||||||
|
-------------
|
||||||
|
A number of tests follow designed to check the behaviour of the
|
||||||
|
file I/O system.
|
||||||
|
|
||||||
|
@FILE-TEST-CHECK-OPEN
|
||||||
|
Test 1: Are the parameters to the OPEN statement checked immediately?
|
||||||
|
-------
|
||||||
|
A scratch file is opened with the statement:
|
||||||
|
OPEN( 10 , STATUS = 'SCRATCH' , IOSTAT = IERR ,
|
||||||
|
FORM = 'INVALID!' )
|
||||||
|
|
||||||
|
@FILE-TEST-CHECK-NO
|
||||||
|
Warning:
|
||||||
|
The parameters in the OPEN statement are NOT checked immediately. This
|
||||||
|
will probably be delayed until the first READ or WRITE.
|
||||||
|
@FILE-TEST-CHECK-YES
|
||||||
|
Note:
|
||||||
|
The parameters in the OPEN statement are checked immediately. You can
|
||||||
|
not open the file with invalid parameters.
|
||||||
|
|
||||||
|
@FILE-TEST-MIXED-FORMAT
|
||||||
|
Test 2: Using unformatted READs on a formatted file
|
||||||
|
-------
|
||||||
|
Create a formatted file and read it as if it were unformatted.
|
||||||
|
(The program tries to read the first record only)
|
||||||
|
Three situations may occur:
|
||||||
|
- Reopening the file as unformatted causes an error
|
||||||
|
- Reading data from the file causes an error
|
||||||
|
- The program reports no error at all
|
||||||
|
|
||||||
|
@FILE-TEST-CREATE-ERROR
|
||||||
|
Warning:
|
||||||
|
The file that is used in this test (called "chksys.1") could not
|
||||||
|
be opened. This means the test has been skipped.
|
||||||
|
|
||||||
|
Possible causes:
|
||||||
|
- The file name does not conform to the conventions of this platform
|
||||||
|
- You have no permission to create files in this directory
|
||||||
|
|
||||||
|
@FILE-TEST-MIXED-ERROR-OPEN
|
||||||
|
In this case: An error occurs when trying to open the file.
|
||||||
|
|
||||||
|
@FILE-TEST-MIXED-ERROR-READ
|
||||||
|
In this case: An error occurs when trying to read data.
|
||||||
|
|
||||||
|
@FILE-TEST-MIXED-NO-ERROR-AT-ALL
|
||||||
|
Warning:
|
||||||
|
No error occurred AT ALL! This is a very awkward situation.
|
||||||
|
It may be that the string that was written ("INVALID!")
|
||||||
|
starts exactly as an unformatted file would. Most likely,
|
||||||
|
the compiler does not flag any error. That would be serious
|
||||||
|
indeed!
|
||||||
|
|
||||||
|
@FILE-TEST-WRITE-UNOPENED
|
||||||
|
Test 3: Writing to an unopened file
|
||||||
|
-------
|
||||||
|
What happens if you inadvertently write to an unopened file (that
|
||||||
|
is a LU-number that has not been connected to a file)?
|
||||||
|
|
||||||
|
From past experience:
|
||||||
|
- The program may ask for a file name
|
||||||
|
- The program opens a file like "fort.10"
|
||||||
|
- The program produces a run-time error
|
||||||
|
|
||||||
|
Note: if the program asks for a file name, type "askfile" (in lowercase
|
||||||
|
letters). This way the program may be able to detect the fact that
|
||||||
|
at some low level a question was put on screen.
|
||||||
|
|
||||||
|
Note: text appearing after these line that does not start "In this case"
|
||||||
|
was written by the run-time library, not by this program itself.
|
||||||
|
|
||||||
|
@FILE-TEST-UNOPENED-ERROR
|
||||||
|
In this case: the program will produce a run-time error
|
||||||
|
|
||||||
|
@FILE-TEST-UNOPENED-OPEN
|
||||||
|
In this case: the program seems to use a default file name
|
||||||
|
|
||||||
|
@FILE-TEST-UNOPENED-ASK
|
||||||
|
In this case: the program (probably) asks you for a name
|
||||||
|
|
||||||
|
@FILE-TEST-READ-TOO-MANY
|
||||||
|
Test 4: Reading too many data from a record of an unformatted file
|
||||||
|
-------
|
||||||
|
The test is simple: does the program identify a problem reading too
|
||||||
|
many data from an unformatted record? If not, you have a very faulty
|
||||||
|
compiler, or you are using the wrong options.
|
||||||
|
|
||||||
|
@FILE-TEST-TOO-MANY-ERROR
|
||||||
|
In this case: The program correctly detects the error.
|
||||||
|
|
||||||
|
@FILE-TEST-TOO-MANY-NO-ERROR
|
||||||
|
Warning:
|
||||||
|
The program seems to think everything went well! You should not
|
||||||
|
use this compiler or at least check the set of compiler options.
|
||||||
|
|
||||||
|
@FILE-TEST-WRITE-TOO-MANY
|
||||||
|
Test 5: Writing too many data to a record of a direct-access file
|
||||||
|
-------
|
||||||
|
The test consists of opening a scratch file with record length 4 and
|
||||||
|
writing ten integers to the first record. This should result in a
|
||||||
|
run-time error.
|
||||||
|
|
||||||
|
@FILE-TEST-OPENING-FILE-TWICE
|
||||||
|
Test 6: Opening the same file twice
|
||||||
|
-------
|
||||||
|
The test consists of opening the same file ("chksys.1") twice,
|
||||||
|
to units 10 and 11. There are four possibilities:
|
||||||
|
- All attempts fail (the file is not opened at all after the two OPEN
|
||||||
|
statements)
|
||||||
|
- The second attempt fails
|
||||||
|
- The first unit is implicitly closed
|
||||||
|
- The file remains open for both units
|
||||||
|
|
||||||
|
@FILE-TEST-OPEN-TWICE-ERROR
|
||||||
|
Note:
|
||||||
|
The second OPEN statement caused a run-time error
|
||||||
|
|
||||||
|
@FILE-TEST-OPEN-TWICE-NO-ERROR
|
||||||
|
Warning:
|
||||||
|
The second OPEN statement caused NO run-time error at all
|
||||||
|
|
||||||
|
@FILE-TEST-OPEN-TWICE-BOTH-OPEN
|
||||||
|
Warning:
|
||||||
|
The units are successfully opened to the same file. This may cause
|
||||||
|
all kinds of trouble (interaction between READs and WRITEs to the
|
||||||
|
two units).
|
||||||
|
|
||||||
|
@FILE-TEST-OPEN-TWICE-ONLY-FIRST
|
||||||
|
Note:
|
||||||
|
Only the first OPEN statement is succssful. The file remains opened
|
||||||
|
to the first unit.
|
||||||
|
|
||||||
|
@FILE-TEST-OPEN-TWICE-ONLY-SECOND
|
||||||
|
Note:
|
||||||
|
The second OPEN statement caused the first unit to be closed.
|
||||||
|
The file is opened to the second unit.
|
||||||
|
|
||||||
|
@FILE-TEST-OPEN-TWICE-BOTH-CLOSED
|
||||||
|
Warning:
|
||||||
|
The second OPEN statement caused the first unit to be closed and it
|
||||||
|
failed to open the file. So neither unit is opened!
|
||||||
|
|
||||||
|
@FILE-TEST-OPEN-TWICE-ERROR-CLOSE
|
||||||
|
Warning:
|
||||||
|
An error occurred while closing the first or second unit. So, apparently
|
||||||
|
the file was not opened to two units independently.
|
||||||
|
|
||||||
|
@FILE-TEST-CLOSING-FILE
|
||||||
|
Test 7: Closing an unopened file
|
||||||
|
-------
|
||||||
|
The test consists of closing a unit number that was never connected
|
||||||
|
to a file. If this produces a run-time error, closing such a
|
||||||
|
unit number will abort your program.
|
||||||
|
|
||||||
|
Special note:
|
||||||
|
Some systems produce a "Too many open files" error if you attempt to
|
||||||
|
close all unit numbers without regard to whether they were opened in
|
||||||
|
the first place, like:
|
||||||
|
|
||||||
|
*
|
||||||
|
* Close all possible files, just for safety
|
||||||
|
*
|
||||||
|
DO 110 LUN = 10,99
|
||||||
|
CLOSE( LUN )
|
||||||
|
110 CONTINUE
|
||||||
|
|
||||||
|
@FILE-TEST-CLOSING-FILE-ERROR
|
||||||
|
Warning:
|
||||||
|
A run-time error occurs if you try to close an unopened file.
|
||||||
|
|
||||||
|
@FILE-TEST-CLOSING-FILE-NO-ERROR
|
||||||
|
Note:
|
||||||
|
No run-time error occurred, though this may not be the case on other
|
||||||
|
platforms or with a different compiler (or even different options).
|
||||||
|
|
||||||
|
@FILE-TEST-OPEN-AGAIN
|
||||||
|
Test 8: Opening another file to the same LU-number
|
||||||
|
-------
|
||||||
|
The test consists of opening a file to unit 10 and then opening yet
|
||||||
|
another file to the same LU-number. The result might be that the first
|
||||||
|
file is closed.
|
||||||
|
|
||||||
|
@FILE-TEST-OPEN-AGAIN-NO
|
||||||
|
Warning:
|
||||||
|
No run-time error occurred. This means that you could inadvertently
|
||||||
|
loose the connection to an open file.
|
||||||
|
|
||||||
|
@FILE-TEST-OPEN-AGAIN-ERROR
|
||||||
|
Note:
|
||||||
|
This causes a run-time error, as it probably should.
|
||||||
|
|
||||||
|
@FILE-TEST-INCOMPLETE-LINES
|
||||||
|
Test 9: Are lines without an end-of-line character accepted?
|
||||||
|
-------
|
||||||
|
The test consists of creating a simple text file with one record which
|
||||||
|
does not have a proper end-of-line. Opening the file again and trying
|
||||||
|
to read that one line might give a problem.
|
||||||
|
|
||||||
|
@FILE-TEST-INCOMPLETE-ACCEPTED
|
||||||
|
Note:
|
||||||
|
The program accepts the line without a problem. (With some compilers
|
||||||
|
this would cause an end-of-file or a read error!)
|
||||||
|
|
||||||
|
@FILE-TEST-INCOMPLETE-OPEN-ERROR
|
||||||
|
Warning:
|
||||||
|
An OPEN error occurred. Can not complete the test.
|
||||||
|
|
||||||
|
@FILE-TEST-INCOMPLETE-READ-ERROR
|
||||||
|
Warning:
|
||||||
|
This causes a run-time error, not an end-of-file condition.
|
||||||
|
|
||||||
|
@FILE-TEST-INCOMPLETE-END-OF-FILE
|
||||||
|
Warning:
|
||||||
|
This causes an end-of-file condition, the last line can not be read.
|
||||||
|
|
||||||
|
@SHIFTING-STRINGS
|
||||||
|
Shifting strings
|
||||||
|
----------------
|
||||||
|
In this test substrings are shifted one character to the left and one
|
||||||
|
to the right. As the operations involve overlapping strings, it is
|
||||||
|
not obvious that the program will handle this correctly.
|
||||||
|
|
||||||
|
@SHIFTING-INCORRECT
|
||||||
|
Warning:
|
||||||
|
The results of the shifts in at least one direction are incorrect.
|
||||||
|
Be careful with such shifts!
|
||||||
|
|
||||||
|
@MISCELLANEOUS1
|
||||||
|
Miscellaneous issues
|
||||||
|
--------------------
|
||||||
|
Treatment of backslash characters (\):
|
||||||
|
Some compilers treat backslashes as C-like escape sequences, such
|
||||||
|
that '\t' becomes a TAB character
|
||||||
|
|
||||||
|
@BACKSLASH-ESCAPE
|
||||||
|
Warning:
|
||||||
|
This is the case with the current compiler (and the options used)!
|
||||||
|
|
||||||
|
@BACKSLASH-ASIS
|
||||||
|
This is NOT the case with the current compiler (and the options used).
|
||||||
|
So backslashes are safe to use. Be aware of this behaviour though.
|
||||||
|
|
||||||
|
@MISCELLANEOUS2
|
||||||
|
The next two lines should appear without an empty line. The lines
|
||||||
|
after that show the treatment of numbers (right-justified or
|
||||||
|
left-justified):
|
||||||
|
|
||||||
|
@TREATMENT-ASTERISK
|
||||||
|
|
||||||
|
If there is a line in between, then note that code like:
|
||||||
|
CHARACTER*75 STR1 , STR2
|
||||||
|
WRITE(*,*) STR1
|
||||||
|
WRITE(*,*) STR2
|
||||||
|
|
||||||
|
may give different results than you expect! It means that the
|
||||||
|
output is less than 75 columns wide, hence wrapping occurs.
|
||||||
|
|
||||||
|
@MISCELLANEOUS3
|
||||||
|
Characters in the first column that are written to the screen may be
|
||||||
|
eliminated or regarded as carriage control. The string '%1234567890'
|
||||||
|
was written with the statement:
|
||||||
|
WRITE( * , '(A)' ) '%1234567890'
|
||||||
|
|
||||||
|
@MEMORY
|
||||||
|
Memory model
|
||||||
|
------------
|
||||||
|
Contrary to what many programmers believe, variables in subroutines are
|
||||||
|
not automatically saved. In fact the SAVE statement should be used
|
||||||
|
to ensure this.
|
||||||
|
|
||||||
|
@MEMORY-STATIC
|
||||||
|
Static memory:
|
||||||
|
From the test it appears that local variables retain their
|
||||||
|
values between calls. Thus most likely, local variables and
|
||||||
|
arrays are stored in static memory.
|
||||||
|
Consequences:
|
||||||
|
- The SAVE statement has no other effect than documentation
|
||||||
|
- Large arrays do not cause a stack overflow
|
||||||
|
Warnings:
|
||||||
|
- Use the SAVE statement to document persistent variables
|
||||||
|
- Use SAVE for any large arrays, as a different environment
|
||||||
|
might pose stack problems!
|
||||||
|
|
||||||
|
@MEMORY-DYNAMIC
|
||||||
|
Dynamic memory:
|
||||||
|
From the test it appears that local variables DO NOT retain
|
||||||
|
their values between calls. Thus most likely, local variables
|
||||||
|
and arrays are stored in the stack.
|
||||||
|
Consequences:
|
||||||
|
- The SAVE statement should be used to preserve the values
|
||||||
|
- Large arrays may cause stack overflow in the middle of the
|
||||||
|
program run
|
||||||
|
Solutions:
|
||||||
|
- Use the SAVE statement to preserve the values
|
||||||
|
(This provides documentation as well)
|
||||||
|
- Use SAVE for any large arrays to force them in static memory
|
||||||
|
|
||||||
|
@DO-LOOPS
|
||||||
|
Test the behaviour of DO-loops
|
||||||
|
------------------------------
|
||||||
|
Test 1: Is the number of iterations in a DO-loop protected?
|
||||||
|
-------
|
||||||
|
If the variable that controls the DO-loop is changed by mistake,
|
||||||
|
then various things can happen. It is even possible that the DO-loop
|
||||||
|
will never end!
|
||||||
|
|
||||||
|
In this test, the number of steps should be 10, and the DO-variable
|
||||||
|
should (probably) become 26, because it is changed to 20 at step 5.
|
||||||
|
|
||||||
|
@DO-LOOP-ALTERABLE
|
||||||
|
Warning:
|
||||||
|
The number of iterations can be changed! If the variable is changed,
|
||||||
|
then the DO-variable jumps from 4 to 20. If the variable is 21 at the
|
||||||
|
end of the loop, then the value is saved.
|
||||||
|
|
||||||
|
@DO-LOOP-PROTECTED
|
||||||
|
The number of iterations can not be changed, though the iteration
|
||||||
|
variable may be changed. If the variable is changed, then the step
|
||||||
|
number jumps from 4 to 20. If the variable is 26 at the end of the
|
||||||
|
loop, then the value is saved.
|
||||||
|
|
||||||
|
@DO-LOOP-INFINITE
|
||||||
|
Warning:
|
||||||
|
The implementation of DO-loops is such that a change to the DO-variable
|
||||||
|
leads to INFINITE loops! In our test, the DO-loop is terminated after
|
||||||
|
20 steps, indicating this somewhat bizarre behaviour.
|
||||||
|
|
||||||
|
@DO-LOOP-CHANGE-UPPER
|
||||||
|
Test 2: What happens if the upper limit in a DO_loop is changed?
|
||||||
|
-------
|
||||||
|
The DO-loop looks like this:
|
||||||
|
NOSTPM = 10
|
||||||
|
DO 110 I = 1,NOSTPM
|
||||||
|
IF ( I .EQ. 4 ) NOSTPM = 6
|
||||||
|
...
|
||||||
|
110 CONTINUE
|
||||||
|
|
||||||
|
Is it still run 10 times or not?
|
||||||
|
|
||||||
|
@DO-LOOP-LIMIT-ALTERABLE
|
||||||
|
Warning:
|
||||||
|
The number of iterations can be changed! If the upper limit is changed,
|
||||||
|
then the number of iterations also changes.
|
||||||
|
|
||||||
|
@DO-LOOP-LIMIT-PROTECTED
|
||||||
|
The number of iterations can not be changed.
|
||||||
|
|
||||||
|
@DO-LOOP-LIMIT-INFINITE
|
||||||
|
Warning:
|
||||||
|
The implementation of DO-loops is such that a change to the upper limit
|
||||||
|
may lead to INFINITE loops! In our test, the DO-loop is terminated after
|
||||||
|
20 steps, indicating this somewhat bizarre behaviour.
|
||||||
|
|
||||||
|
@DO-LOOP-PASS
|
||||||
|
Test 3: DO-loops conform to standard?
|
||||||
|
-------
|
||||||
|
In older versions of FORTRAN (FORTRAN 66 for instance), a DO-loop was
|
||||||
|
always executed at least once. This might make quite a difference.
|
||||||
|
|
||||||
|
@DO-LOOP-PASS-ONCE
|
||||||
|
Warning:
|
||||||
|
DO-loops are always executed at least once!
|
||||||
|
|
||||||
|
@DO-LOOP-PASS-ZERO
|
||||||
|
DO-loops seem to behave correctly.
|
||||||
|
|
||||||
|
@OVERFLOW
|
||||||
|
Test: What happens if an overflow is generated?
|
||||||
|
-----
|
||||||
|
The program calculates 1.0E30 / 1.0E-20, which can not be represented
|
||||||
|
in single precision (at least if it is a REAL*4 number, according to
|
||||||
|
IEEE guidelines). An overflow should occur.
|
||||||
|
|
||||||
|
@UNDERFLOW
|
||||||
|
Test: What happens if an underflow is generated?
|
||||||
|
-----
|
||||||
|
The program calculates 1.0E-20 / 1.0E30, which can not be represented
|
||||||
|
in single precision (at least if it is a REAL*4 number, according to
|
||||||
|
IEEE guidelines). It is either truncated to zero, or an underflow occurs.
|
||||||
|
|
||||||
|
@DIVISION
|
||||||
|
Test: What happens if the program divides by zero?
|
||||||
|
-----
|
||||||
|
The program calculates 1.0 / 0.0, which is clearly incorrect. It should
|
||||||
|
result in a "division by zero" error.
|
||||||
|
|
||||||
|
@DOMAIN
|
||||||
|
Test: The program tries to calculate SQRT( -1.0 )
|
||||||
|
-----
|
||||||
|
The program calculates SQRT( -1.0 ), which is clearly incorrect.
|
||||||
|
It should result in a "domain" error.
|
||||||
|
|
||||||
|
@ARRAYBOUND
|
||||||
|
Test: The program tries to access array elements outside the array
|
||||||
|
-----
|
||||||
|
The program uses an array of length 10 and accesses element 11.
|
||||||
|
As a bonus:
|
||||||
|
If the reported value for this element is 2.0, the array element is
|
||||||
|
actually a variable defined after the array. Similarly a value
|
||||||
|
of 3.1415926 indicates that the program used a variable prior to the
|
||||||
|
array. If neither value is reported, the memory layout is not obvious.
|
||||||
|
|
||||||
|
@ARRAY-NO-ERROR
|
||||||
|
Warning:
|
||||||
|
No error was generated. This means that we can access elements
|
||||||
|
outside the actual array without a run-time error. As this can cause
|
||||||
|
all kinds of nasty errors, which are likely to become apparent in
|
||||||
|
a totally different place, there are serious risks involved here.
|
||||||
|
|
||||||
|
Check if the compiler has an array bound check option and use this
|
||||||
|
at least during testing!
|
||||||
|
|
||||||
|
@NUMERIC-GENERATE
|
||||||
|
Warning:
|
||||||
|
The invalid calculation was done without a run-time error.
|
||||||
|
Now we will multiply the result by 2.0.
|
||||||
|
|
||||||
|
@NUMERIC-NO-ERROR
|
||||||
|
Warning:
|
||||||
|
No error was generated. This means that we can manipulate the
|
||||||
|
result of an invalid calculation. The severity of this behaviour
|
||||||
|
depends of course on the type of calculation.
|
||||||
|
(Use a program like "paranoia" to find out more about the numerical
|
||||||
|
properties of your compiler/computer.)
|
||||||
|
|
||||||
|
@SUBSTRING
|
||||||
|
Test: How does the program react to taking illegal substrings?
|
||||||
|
-----
|
||||||
|
This test consists of taking a zero-length substring and a substring
|
||||||
|
beyond the end of the string. It seems unclear what should happen in
|
||||||
|
these cases, but if range-checking is enabled, the program will abort.
|
||||||
|
|
||||||
|
@SUBSTRING-NO-ERROR
|
||||||
|
Note:
|
||||||
|
No error occurred, the program can continue. This means such errors may
|
||||||
|
remain in the program for a long time.
|
||||||
|
|
||||||
|
@end-of-file
|
||||||
25
flibs-0.9/flibs/chksys/chksys.set
Normal file
25
flibs-0.9/flibs/chksys/chksys.set
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# CHKSYS: Which checks to perform
|
||||||
|
# Possible keywords:
|
||||||
|
# @GENERAL - all general (well-behaved) tests
|
||||||
|
# @OVERFLOW - behaviour on overflow
|
||||||
|
# @UNDERFLOW - behaviour on underflow
|
||||||
|
# @DIVISION - behaviour on division by zero
|
||||||
|
# @DOMAIN - behaviour on negative argument for SQRT()
|
||||||
|
# @ARRAYBOUND - behaviour if array bounds are exceeded
|
||||||
|
# @SUBSTRING - behaviour if certain substrings are taken
|
||||||
|
#
|
||||||
|
# To include the test, the keyword must begin in the first column
|
||||||
|
# To exclude it, use the word SKIP in front.
|
||||||
|
#
|
||||||
|
# If you want concise information about the tests, put the keyword
|
||||||
|
# SUMMARY in (VERBOSE is just to show the opposite: a full report
|
||||||
|
# is default)
|
||||||
|
#
|
||||||
|
VERBOSE
|
||||||
|
@GENERAL
|
||||||
|
SKIP @OVERFLOW
|
||||||
|
SKIP @UNDERFLOW
|
||||||
|
SKIP @DIVISION
|
||||||
|
SKIP @DOMAIN
|
||||||
|
@SUBSTRING
|
||||||
|
@ARRAYBOUND
|
||||||
487
flibs-0.9/flibs/chksys/chksysc.msg
Normal file
487
flibs-0.9/flibs/chksys/chksysc.msg
Normal file
@@ -0,0 +1,487 @@
|
|||||||
|
@INTRODUCTION
|
||||||
|
CHKSYSC: A program to determine the properties of the run-time
|
||||||
|
environment for C programs
|
||||||
|
|
||||||
|
The program presents information about:
|
||||||
|
- What type of system are you running on (e.g. UNIX or MS Windows)?
|
||||||
|
- What restrictions for file names?
|
||||||
|
- Sizes and ranges for common data types
|
||||||
|
- Possible alignment issues
|
||||||
|
- Other matters concerning portability and the detection of
|
||||||
|
run-time errors.
|
||||||
|
|
||||||
|
Note:
|
||||||
|
Some tests may cause the program to crash or, in the worst to let
|
||||||
|
the whole system hang (on PC). So the file "chksysc.set" can be used
|
||||||
|
to control whether such tests are performed.
|
||||||
|
|
||||||
|
@ENVIRONMENT
|
||||||
|
Environment variables
|
||||||
|
---------------------
|
||||||
|
Most systems use environment variables to transfer information between
|
||||||
|
programs. Two such variables that may influence the behaviour of a
|
||||||
|
program are: PATH (searching executable programs) and LANG (specifying
|
||||||
|
the locale, which controls such things as a comma instead of a period
|
||||||
|
as decimal separator).
|
||||||
|
|
||||||
|
Furthermore, most systems supply the name of the program as the first
|
||||||
|
command-line argument, argv[0]. Many systems include the full path
|
||||||
|
in this variable, some, notably the Korn shell under UNIX, do not.
|
||||||
|
|
||||||
|
In this case:
|
||||||
|
@ENVIRONMENT-NO-COMMAND-ARGS
|
||||||
|
Note:
|
||||||
|
The run-time environment provides no arguments!
|
||||||
|
|
||||||
|
@ENVIRONMENT-NO-PATH
|
||||||
|
Note:
|
||||||
|
The environment variable PATH has not been defined
|
||||||
|
|
||||||
|
@ENVIRONMENT-NO-LANG
|
||||||
|
Note:
|
||||||
|
The environment variable LANG has not been defined
|
||||||
|
|
||||||
|
@ENVIRONMENT-CURR-TIME
|
||||||
|
Current time:
|
||||||
|
-------------
|
||||||
|
According to the system clock and formatting using the "%c" format
|
||||||
|
of strftime():
|
||||||
|
@ENVIRONMENT-NO-TIME
|
||||||
|
Warning:
|
||||||
|
The run-time environment does not support a system clock
|
||||||
|
|
||||||
|
@ENVIRONMENT-SETLOCALE
|
||||||
|
Locale:
|
||||||
|
-------
|
||||||
|
The function setlocale() can be used to set the locale, that is, items
|
||||||
|
that are specific to a country or a culture. These include:
|
||||||
|
- The order for day of the month and the name of the month
|
||||||
|
- The use of a comma instead of a period to separate decimals
|
||||||
|
- The order of characters in comparisons
|
||||||
|
|
||||||
|
Unfortunately, the C standard only defines the locales "C" (the standard
|
||||||
|
locale) and "" (the locale defined by the run-time environment, in a
|
||||||
|
system-specific way, such as via LANG).
|
||||||
|
|
||||||
|
It is not possible to check which locales are defined in the current
|
||||||
|
run-time environment. The program simply reports the current locale
|
||||||
|
(probably "C").
|
||||||
|
|
||||||
|
@FILE-SYSTEM
|
||||||
|
File system
|
||||||
|
-----------
|
||||||
|
The following information about the operating system and the file
|
||||||
|
system is obtained:
|
||||||
|
|
||||||
|
@PROGRAM-ERROR
|
||||||
|
*** Error:
|
||||||
|
*** The program has come up with an unknown condition.
|
||||||
|
*** Please check this!
|
||||||
|
|
||||||
|
@OS-UNKNOWN
|
||||||
|
Operating system: Unknown. The following information might be misleading
|
||||||
|
|
||||||
|
@OS-UNIX
|
||||||
|
Operating system: The program is running under UNIX
|
||||||
|
|
||||||
|
@OS-DOS-WINDOWS
|
||||||
|
Operating system: The program is running under MS DOS or MS Windows 3.x
|
||||||
|
|
||||||
|
@OS-WINDOWS-95-NT
|
||||||
|
Operating system: The program is running under MS Windows 95 or NT
|
||||||
|
(No further distinction can be made)
|
||||||
|
|
||||||
|
@FILE-SYSTEM-SHORT-NAMES
|
||||||
|
The file system supports short file names only (either the DOS convention
|
||||||
|
or an old UNIX System V convention)
|
||||||
|
|
||||||
|
@FILE-SYSTEM-LONG-NAMES
|
||||||
|
The file system supports long file names (more than 14 characters)
|
||||||
|
|
||||||
|
@FILE-SYSTEM-IGNORE-CASE
|
||||||
|
File names are insensitive to uppercase and lowercase (e.g. CHKSYS.MSG
|
||||||
|
and chksys.msg are equivalent)
|
||||||
|
|
||||||
|
@FILE-SYSTEM-RESPECT-CASE
|
||||||
|
The file system distinguishes between uppercase and lowercase in file
|
||||||
|
names (e.g. CHKSYS.MSG and chksys.msg are not the same files!)
|
||||||
|
|
||||||
|
@COMPILER-MACROS
|
||||||
|
Compiler macros
|
||||||
|
---------------
|
||||||
|
In general compilers predefine a number of macros that can be used to
|
||||||
|
identify certain characteristics of the compiler and the run-time
|
||||||
|
environment.
|
||||||
|
|
||||||
|
Standard macros include:
|
||||||
|
__STDC__ Used by standard-compliant compilers to indicate that the
|
||||||
|
standard is in effect. Particularly useful for enabling
|
||||||
|
prototypes.
|
||||||
|
This macro is not always defined if you are tacitly allowing
|
||||||
|
extensions.
|
||||||
|
__cplusplus Macro indicating the compiler is expecting C++.
|
||||||
|
The presence of this macro often means __STDC__ is NOT
|
||||||
|
defined.
|
||||||
|
_POSIX_SOURCE and _XOPEN_SOURCE
|
||||||
|
These macros indicate compliance to the POSIX and XOPEN
|
||||||
|
standards, which are mainly used in UNIX.
|
||||||
|
|
||||||
|
Almost every compiler also defines one or more usually ill-documented
|
||||||
|
macros that can tell you something about the computer system or the
|
||||||
|
run-time environment.
|
||||||
|
|
||||||
|
The program will try and find which such macros are defined and what type
|
||||||
|
of computer you are working on. Note that the test is not exhaustive nor
|
||||||
|
is it intended to be - it mainly distinguishes between a number of
|
||||||
|
popular brands.
|
||||||
|
|
||||||
|
@COMPILER-MACROS-GENERAL
|
||||||
|
The following general macros are defined:
|
||||||
|
|
||||||
|
@COMPILER-MACROS-SPECIFIC
|
||||||
|
The following macros are compiler-specific:
|
||||||
|
|
||||||
|
@COMPILER-MACROS-COMPILER
|
||||||
|
These indicate the following:
|
||||||
|
|
||||||
|
@COMPILER-MACROS-PREPROCESSOR
|
||||||
|
Preprocessor macros
|
||||||
|
-------------------
|
||||||
|
The C/C++ preprocessor defines several macros that can be useful
|
||||||
|
for introducing debug messages:
|
||||||
|
__FILE__ - the name of the source file
|
||||||
|
__LINE__ - the line in the source file
|
||||||
|
__DATE__ - the date of compilation
|
||||||
|
__TIME__ - the time of compilation
|
||||||
|
|
||||||
|
For instance:
|
||||||
|
|
||||||
|
@COMPILER-MACROS-PREPROC-NOFILE
|
||||||
|
Warning:
|
||||||
|
The current preprocessor does NOT work according to the Standard.
|
||||||
|
It does not define the macro __FILE__
|
||||||
|
|
||||||
|
@NUMBER-OPEN-FILES
|
||||||
|
Maximum number of open files
|
||||||
|
----------------------------
|
||||||
|
All systems have a limit to the number of files that can opened at the
|
||||||
|
same time.
|
||||||
|
|
||||||
|
@NUMBER-OPEN-FILES-MACRO
|
||||||
|
The C header file "stdio.h" provides a macro FOPEN_MAX. It is the
|
||||||
|
minimum number of files that is guaranteed can be opened.
|
||||||
|
|
||||||
|
@NUMBER-OPEN-FILES-NO-MACRO
|
||||||
|
The C header file "stdio.h" that was used does not provide a
|
||||||
|
macro FOPEN_MAX, contrary to most compilers.
|
||||||
|
|
||||||
|
@NUMBER-OPEN-FILES-LIMITED
|
||||||
|
The current system allows a limited number of open files:
|
||||||
|
|
||||||
|
@NUMBER-OPEN-FILES-UNLIMITED
|
||||||
|
The current system allows at least 90 open files, which for almost all
|
||||||
|
practical purposes is quite enough.
|
||||||
|
|
||||||
|
@BASIC-DATA-TYPES
|
||||||
|
Information about data types
|
||||||
|
----------------------------
|
||||||
|
The C header files along with the compiler's sizeof() macro
|
||||||
|
have provided the following information about the basic data types:
|
||||||
|
|
||||||
|
@BASIC-DATA-TYPES-MEMORY
|
||||||
|
Data types concerning memory:
|
||||||
|
-----------------------------
|
||||||
|
Three types are important here:
|
||||||
|
size_t - The type that is used for the size of an object in memory.
|
||||||
|
The maximum value it can reach defines the maximum amount
|
||||||
|
of memory you can allocate with one call to malloc().
|
||||||
|
ptrdiff_t - The type of value returned when taking the difference
|
||||||
|
between two addresses.
|
||||||
|
Warning:
|
||||||
|
The maximum allowable value may be smaller than can actually
|
||||||
|
occur!
|
||||||
|
void * - The general pointer type. A "long" variable should be
|
||||||
|
large enough to hold it.
|
||||||
|
|
||||||
|
@BASIC-DATA-TYPES-FORMAT
|
||||||
|
Data types and print formats:
|
||||||
|
-----------------------------
|
||||||
|
In C formatting strings like "%5f" can yield unexpected results:
|
||||||
|
- If the number to be printed is larger than fits in the space that
|
||||||
|
is allowed by the format, the resulting string will simply be enlarged.
|
||||||
|
- This poses the threat of array overflows on any sprintf() call.
|
||||||
|
|
||||||
|
To illustrate this, the program prints several examples. Note the use
|
||||||
|
of the "F" suffix. This is to avoid complaints from the compiler. There
|
||||||
|
may even be a difference between:
|
||||||
|
|
||||||
|
float_var = 1.0e20 ;
|
||||||
|
and
|
||||||
|
float_var = 1.0e20F ;
|
||||||
|
|
||||||
|
If this is so, it may be due to local optimisations (the numerical
|
||||||
|
registers retain the value 1.0e20 in double precision and this is used
|
||||||
|
in the printf() call).
|
||||||
|
|
||||||
|
@MEMORY-ALIGNMENT
|
||||||
|
Memory alignment
|
||||||
|
----------------
|
||||||
|
The organisation of the computer's memory sometimes becomes important:
|
||||||
|
- When determining the size of a structure
|
||||||
|
- When allocating memory
|
||||||
|
|
||||||
|
The fine grain aspects of the memory organisation are known as alignment.
|
||||||
|
It basically means that the memory that holds a short integer should
|
||||||
|
start at an even address, reals at an address that is a quadruple and
|
||||||
|
so on. Of course this all depends on the specific computer system.
|
||||||
|
|
||||||
|
Such alignments may cause gaps in structures and between variables.
|
||||||
|
Though mainly a waste of space, it can also hide array overflows until
|
||||||
|
you get to a different computer system (see the section on string
|
||||||
|
overflow).
|
||||||
|
|
||||||
|
The program tries to determine the alignment rules by looking at two
|
||||||
|
structures and by allocating some memory.
|
||||||
|
|
||||||
|
The structures are:
|
||||||
|
|
||||||
|
Structure 1: Structure 2:
|
||||||
|
struct _CharDoubleChar struct _DoubleCharChar
|
||||||
|
{ {
|
||||||
|
char one_char ; double one_double ;
|
||||||
|
double one_double ; char one_char ;
|
||||||
|
char one_char ; char two_char ;
|
||||||
|
} CharDoubleChar ; } DoubleCharChar ;
|
||||||
|
|
||||||
|
@MEMORY-ALIGNMENT-POINTERS
|
||||||
|
The malloc() function and its companions usually return addresses that
|
||||||
|
are a multiple of 2, 4, 8 etc. In this case:
|
||||||
|
|
||||||
|
@MEMORY-ALIGNMENT-FAILED-MULT
|
||||||
|
The successive calls to malloc() returned addresses that do not show
|
||||||
|
any consistent multiple. We failed to determine such a value.
|
||||||
|
|
||||||
|
@STRING-OVERFLOW
|
||||||
|
String overflow
|
||||||
|
---------------
|
||||||
|
The test tries to determine what happens to local variables if a
|
||||||
|
string is filled with another string that is too large. (C provides
|
||||||
|
no mechanism to adequately prevent this - you will have to program it
|
||||||
|
yourself)
|
||||||
|
|
||||||
|
The local variables are defined as (in this order!):
|
||||||
|
|
||||||
|
int int_before ;
|
||||||
|
char string[10] ;
|
||||||
|
int int_after ;
|
||||||
|
|
||||||
|
The results may be:
|
||||||
|
- The integer defined before the string is affected
|
||||||
|
- The integer defined after the string is affected
|
||||||
|
- There is no noticeable effect:
|
||||||
|
- The memory alignment makes sure there is enough space
|
||||||
|
- The stack has been reorganised
|
||||||
|
|
||||||
|
@STRING-OVERFLOW-BEFORE
|
||||||
|
Warning:
|
||||||
|
The string overflow affected the variable defined BEFORE the string
|
||||||
|
|
||||||
|
@STRING-OVERFLOW-AFTER
|
||||||
|
Warning:
|
||||||
|
The string overflow affected the variable defined AFTER the string
|
||||||
|
|
||||||
|
@STRING-OVERFLOW-NO-EFFECT
|
||||||
|
Warning:
|
||||||
|
The string overflow had no effect on either the variable that was
|
||||||
|
defined BEFORE the string or the one defined AFTER the string.
|
||||||
|
|
||||||
|
Caution:
|
||||||
|
Such errors may remain undetected for a long time! In fact, during the
|
||||||
|
development of this program it seemed as if the test had no effect, but
|
||||||
|
after adding enough subroutines, the PC I used ran the program as if
|
||||||
|
everything was normal and then hang up - or rebooted! Of course, I blamed
|
||||||
|
these new subroutines at first ...
|
||||||
|
|
||||||
|
@STRING-OVERFLOW-MEMORY-ALIGNMENT
|
||||||
|
The string overflow had no effect due to the memory alignment
|
||||||
|
for integers.
|
||||||
|
|
||||||
|
@STRING-OVERFLOW-STACK-REORGANISED
|
||||||
|
The string overflow had no effect because the variables in the stack
|
||||||
|
are not arranged in the order of definition.
|
||||||
|
|
||||||
|
@IMPLICIT-CAST
|
||||||
|
Implicit casting
|
||||||
|
----------------
|
||||||
|
The C compiler uses implicit casting in a number of situations. These
|
||||||
|
may cause very obscure errors, if you are not aware of this feature.
|
||||||
|
The background is the use of old-style Kernigan and Ritchie prototypes.
|
||||||
|
|
||||||
|
The test consists of executing the following code:
|
||||||
|
|
||||||
|
int_val = 1 ;
|
||||||
|
real_val = 1.1F ;
|
||||||
|
|
||||||
|
printf( "Real, integer: %d %d\n" , real_val , int_val ) ;
|
||||||
|
printf( "Real: %d\n" , real_val ) ;
|
||||||
|
printf( "Integer: %d\n" , int_val ) ;
|
||||||
|
|
||||||
|
From the first print statement, you would expect a bizarre integer and
|
||||||
|
then "1". From the second and third print statements simply a repetition
|
||||||
|
of each number. The result, however:
|
||||||
|
|
||||||
|
@FILE-HANDLING
|
||||||
|
File handling
|
||||||
|
-------------
|
||||||
|
Several tests follow to establish the behaviour of the run-time system
|
||||||
|
with regard to somewhat weird file handling:
|
||||||
|
- Opening a file that has an empty string as name
|
||||||
|
|
||||||
|
Note:
|
||||||
|
To get more information out of the system, the global variable "errno"
|
||||||
|
is used. Unfortunately, this does not always work. So, after the
|
||||||
|
message "System error:", you may not see a useful text.
|
||||||
|
|
||||||
|
Well, this is an indication of the quality of the compiler as well,
|
||||||
|
of course.
|
||||||
|
|
||||||
|
Note:
|
||||||
|
Be sure to include not only the header file "errno.h" but also
|
||||||
|
the header file "string.h" - this defines the strerror() function.
|
||||||
|
If not, some systems will present rubbish.
|
||||||
|
|
||||||
|
Note:
|
||||||
|
With some compilers a run-time error may follow that is handled by
|
||||||
|
an assert() macro. If this happens the program will not continue.
|
||||||
|
--- To do: think of a solution for this! ---
|
||||||
|
|
||||||
|
@FILE-EMPTY-NAME
|
||||||
|
Test 1: Opening a file with an empty name
|
||||||
|
-------
|
||||||
|
The fopen() is called like this:
|
||||||
|
|
||||||
|
pfile = fopen( "" , "r" ) ;
|
||||||
|
|
||||||
|
@FILE-EMPTY-NAME-NULL
|
||||||
|
The call to fopen() returned NULL - as expected.
|
||||||
|
@FILE-EMPTY-NAME-SUCCESS
|
||||||
|
The call to fopen() returned a non-NULL pointer. This means the error
|
||||||
|
was not caught, or at least not in an obvious way!
|
||||||
|
@FILE-EMPTY-END
|
||||||
|
Dummy
|
||||||
|
|
||||||
|
@LOGICAL-EXPRESSIONS
|
||||||
|
Logical expressions
|
||||||
|
-------------------
|
||||||
|
The C standard states that programs may short-cut logical expressions
|
||||||
|
like "a && b" and "a || b":
|
||||||
|
- If after evaluating "a" it becomes clear that the expression "a && b"
|
||||||
|
is false, "b" need not be evaluated
|
||||||
|
- Similarly, "a || b" is true if "a" is true, and "b" needs not to be
|
||||||
|
known.
|
||||||
|
|
||||||
|
The program checks how many arguments are evaluated in four different
|
||||||
|
logical expressions and assumes that short-cuts are the proper way
|
||||||
|
to evaluate these.
|
||||||
|
|
||||||
|
For each expression the program lists the order in which the operands
|
||||||
|
are used and what value they had.
|
||||||
|
|
||||||
|
@LOGICAL-EXPR-NOT-COMPLIANT
|
||||||
|
The evaluation of the logical expression does not seem compliant
|
||||||
|
|
||||||
|
@LOGICAL-EXPR-COMPLIANT
|
||||||
|
Note:
|
||||||
|
From the four tests we conclude that the evaluation of logical
|
||||||
|
expressions is compliant to the standard.
|
||||||
|
|
||||||
|
@LOGICAL-EXPR-AND
|
||||||
|
Test 1: Evaluate a && b, with "a" false
|
||||||
|
-------
|
||||||
|
@LOGICAL-EXPR-OR
|
||||||
|
Test 2: Evaluate a || b, with "a" true
|
||||||
|
-------
|
||||||
|
@LOGICAL-EXPR-THREE-OPERANDS
|
||||||
|
Test 3: Evaluate a && b || c, with "a", "b" and "c" true
|
||||||
|
-------
|
||||||
|
@LOGICAL-EXPR-THREE-BRACKETS
|
||||||
|
Test 4: Evaluate (a && b) || c, with "a", "b" and "c" true
|
||||||
|
-------
|
||||||
|
@ARITHMETIC-EVALUATION
|
||||||
|
Arithmetic evaluations
|
||||||
|
----------------------
|
||||||
|
Contrary to logical expressions, the standard does not prescribe any
|
||||||
|
order to the evaluation of individual terms or the synthesis to one
|
||||||
|
result.
|
||||||
|
|
||||||
|
This means that side effects will depend on the compiler and possibly
|
||||||
|
compiler options (such as optimisations). Side effects are present
|
||||||
|
in such expressions as:
|
||||||
|
|
||||||
|
for ( i= 0 ; i < 100 ; a[i++] = b[i] )
|
||||||
|
/* No body */ ;
|
||||||
|
|
||||||
|
Or:
|
||||||
|
a = i + b[i++] ;
|
||||||
|
|
||||||
|
The program tests a number of expressions and tries to decide what
|
||||||
|
order is used. For each expression the program lists the order in
|
||||||
|
which the operands are used and what value they had.
|
||||||
|
|
||||||
|
@ARITHMETIC-TWO-SUM
|
||||||
|
Test 1: Evaluate a + b
|
||||||
|
-------
|
||||||
|
@ARITHMETIC-THREE-SUM
|
||||||
|
Test 2: Evaluate a + b + c
|
||||||
|
-------
|
||||||
|
@ARITHMETIC-FOUR-SUM
|
||||||
|
Test 3: Evaluate a + b + c + d
|
||||||
|
-------
|
||||||
|
@ARITHMETIC-INDECISIVE
|
||||||
|
Note:
|
||||||
|
There was no consistent order in the evaluation of these expressions!
|
||||||
|
|
||||||
|
@ARITHMETIC-MIXED-TYPE-CALC
|
||||||
|
The next test consists of a somewhat naive calculation using reals
|
||||||
|
and integers:
|
||||||
|
|
||||||
|
int_val = 10 ;
|
||||||
|
float_val = 1.4 ;
|
||||||
|
int_result = 1.7 + int_val + float_val ;
|
||||||
|
|
||||||
|
@INPUT-FEATURES
|
||||||
|
Features of the input routines
|
||||||
|
------------------------------
|
||||||
|
The following tests use sscanf() and atof() to check whether these
|
||||||
|
functions return the proper values and, possibly, error codes.
|
||||||
|
|
||||||
|
@INPUT-SSCANF-RETURN-REGULAR
|
||||||
|
Test 1: Read two separate strings via sscanf()
|
||||||
|
-------
|
||||||
|
|
||||||
|
@INPUT-SSCANF-RETURN-EOF
|
||||||
|
Test 2: Try to read beyond the end of the string
|
||||||
|
-------
|
||||||
|
|
||||||
|
@INPUT-SSCANF-RETURN-INVALID
|
||||||
|
Test 3: Try to read a real value, but the string does not contain one
|
||||||
|
-------
|
||||||
|
|
||||||
|
@INPUT-SSCANF-COMPLIANT
|
||||||
|
Note:
|
||||||
|
The behaviour of sscanf() seems compliant to the Standard.
|
||||||
|
|
||||||
|
@INPUT-SSCANF-NON-COMPLIANT
|
||||||
|
Warning:
|
||||||
|
The behaviour of sscanf() is NOT compliant to the Standard. It does
|
||||||
|
not return the expected numbers.
|
||||||
|
|
||||||
|
@INPUT-ATOF-INVALID-INPUT
|
||||||
|
Test 4: What does atof() return if the string is not a valid real
|
||||||
|
-------
|
||||||
|
|
||||||
|
@INPUT-NO-ERROR
|
||||||
|
Warning:
|
||||||
|
There was no indication of an error. That means that the program is
|
||||||
|
not capable of detecting the fact that the input did not consist of
|
||||||
|
a valid number - at least not in this naive way.
|
||||||
32
flibs-0.9/flibs/chksys/chksysc.set
Normal file
32
flibs-0.9/flibs/chksys/chksysc.set
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
# CHKSYSC: Which checks to perform
|
||||||
|
# Possible keywords:
|
||||||
|
# @GENERAL - all general (well-behaved) tests
|
||||||
|
# @OVERFLOW - behaviour on overflow
|
||||||
|
# @UNDERFLOW - behaviour on underflow
|
||||||
|
# @DIVISION - behaviour on division by zero
|
||||||
|
# @DOMAIN - behaviour on negative argument for sqrt()
|
||||||
|
# @CHANGECONST - behaviour if a constant literal is changed
|
||||||
|
# @COPYNULL - behaviour if a NULL pointer is used in strcpy()
|
||||||
|
# @COPYOVERLAP - behaviour if the receiving string overlaps the copied
|
||||||
|
# string in strcpy()
|
||||||
|
# @FREENULL - behaviour if a NULL pointer is freed
|
||||||
|
# @FREELOCAL - behaviour if a pointer to local memory is freed
|
||||||
|
#
|
||||||
|
# To include the test, the keyword must begin in the first column
|
||||||
|
# To exclude it, use the word SKIP in front.
|
||||||
|
#
|
||||||
|
# If you want concise information about the tests, put the keyword
|
||||||
|
# SUMMARY in (VERBOSE is just to show the opposite: a full report
|
||||||
|
# is default)
|
||||||
|
#
|
||||||
|
VERBOSE
|
||||||
|
@GENERAL
|
||||||
|
SKIP @OVERFLOW
|
||||||
|
SKIP @UNDERFLOW
|
||||||
|
SKIP @DIVISION
|
||||||
|
SKIP @DOMAIN
|
||||||
|
@CHANGECONST
|
||||||
|
SKIP @COPYNULL
|
||||||
|
@COPYOVERLAP
|
||||||
|
@FREENULL
|
||||||
|
@FREELOCAL
|
||||||
1011
flibs-0.9/flibs/chksys/chksysff.f90
Normal file
1011
flibs-0.9/flibs/chksys/chksysff.f90
Normal file
File diff suppressed because it is too large
Load Diff
208
flibs-0.9/flibs/chksys/chksysff.msg
Normal file
208
flibs-0.9/flibs/chksys/chksysff.msg
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
@warning
|
||||||
|
File size should not exceed 800 lines!
|
||||||
|
@INTRODUCTION
|
||||||
|
CHKSYSFF: A program to determine the properties of the run-time
|
||||||
|
environment for FORTRAN 90 programs
|
||||||
|
|
||||||
|
The program presents information about:
|
||||||
|
- The numerical properties of the processor/compiler
|
||||||
|
- What character set is used?
|
||||||
|
- Manipulations with pointers and allocatable arrays
|
||||||
|
- Whether array assignments are properly implemented in the compiler
|
||||||
|
- Issues concerning the random number generation
|
||||||
|
|
||||||
|
Note:
|
||||||
|
The program is accompanied by a more comprehensive program written
|
||||||
|
in FORTRAN 77. As this language allows more variations in the
|
||||||
|
precise interpretation of the standard, it does concentrate on
|
||||||
|
various uncertainties in the behaviour of the run-time environment.
|
||||||
|
However, even a relatively new language like FORTRAN 90 has non-standard
|
||||||
|
extensions.
|
||||||
|
|
||||||
|
@LIST-KINDS
|
||||||
|
Integer and real kinds
|
||||||
|
----------------------
|
||||||
|
FORTRAN 90 has a number of portable features regarding the specification
|
||||||
|
of integers and reals of various lengths. To use these features you need
|
||||||
|
to know the "kinds" - numbers that indicates the kind of data you want.
|
||||||
|
|
||||||
|
The program tries to determine which integers and reals are supported by
|
||||||
|
the current run-time environment.
|
||||||
|
|
||||||
|
@CHAR-PROPERTIES
|
||||||
|
Ordinary characters
|
||||||
|
-------------------
|
||||||
|
The character set used by FORTRAN 90 consists of most characters you
|
||||||
|
find on ordinary QWERTY keyboards and none other. The language provides
|
||||||
|
standard ways of using different types of character sets besides the
|
||||||
|
ordinary, but there is no way (like for integers and reals) to find
|
||||||
|
out which are supported in the current environment. Instead, you will
|
||||||
|
have to consult the compiler's manual for that.
|
||||||
|
|
||||||
|
However, the default character set is supposed to have the following
|
||||||
|
properties:
|
||||||
|
- The functions ICHAR() and CHAR() are each others' inverse:
|
||||||
|
CHAR(ICHAR(c) = c for any character
|
||||||
|
- The functions IACHAR() and ACHAR() that give the ASCII code for the
|
||||||
|
characters are likewise related:
|
||||||
|
ACHAR(IACHAR(c) = c for any character
|
||||||
|
|
||||||
|
The program checks these relations for the FORTRAN 90 character set.
|
||||||
|
|
||||||
|
@RANDOM-NUMBERS
|
||||||
|
Random number generator
|
||||||
|
-----------------------
|
||||||
|
The language standard defines a random number generator that is supposed
|
||||||
|
to have a uniform distribution. Unfortunately, there are no guarantees
|
||||||
|
on the quality of the random number generator:
|
||||||
|
- What is the length of the pseudo-random number sequence?
|
||||||
|
- Does the generator truly have a uniform distribution?
|
||||||
|
|
||||||
|
This program is not capable of answering these and similar questions.
|
||||||
|
However, it does provide you with information on the quality:
|
||||||
|
- It draws 10000 samples and determines the distribution over ten bins
|
||||||
|
of equal size.
|
||||||
|
- It displays the number of samples in each bin, the average of the
|
||||||
|
samples and the standard deviation.
|
||||||
|
- It estimates via a simple test, if the distribution is roughly
|
||||||
|
uniform.
|
||||||
|
|
||||||
|
@RANDOM-NUMBERS-SUCCESS
|
||||||
|
One or more cases out of range. The random number generator fails the
|
||||||
|
uniformity test!
|
||||||
|
|
||||||
|
@RANDOM-NUMBERS-FAILURE
|
||||||
|
All classes within range. The random number generator seems uniform enough.
|
||||||
|
|
||||||
|
@UNDEFINED-POINTERS
|
||||||
|
Pointers: uninitialised
|
||||||
|
-----------------------
|
||||||
|
Pointers are a special type of data in FORTRAN 90. They can be used and
|
||||||
|
abused, as pointers in any language. What seems to be a very rare
|
||||||
|
feature indeed is the ability in FORTRAN 90 to check the status of
|
||||||
|
the pointers. This would enable you to make robust programs.
|
||||||
|
|
||||||
|
There is a slight complication, though, as uninitialised pointers
|
||||||
|
have an undefined status. This is checked for the present run-time
|
||||||
|
environment in this part of the program. Other properties and
|
||||||
|
pecularities are checked in a subsequent test.
|
||||||
|
|
||||||
|
@UNDEFINED-POINTERS-STATE
|
||||||
|
Checking the state of uninitialised pointers:
|
||||||
|
@UNDEFINED-POINTERS-TRUE
|
||||||
|
Undefined status for pointers: may be TRUE!
|
||||||
|
- you have to be careful!
|
||||||
|
|
||||||
|
@UNDEFINED-POINTERS-FALSE
|
||||||
|
Undefined status for pointers: seems systematically FALSE
|
||||||
|
- you have to be careful though. This test is NOT rigid
|
||||||
|
|
||||||
|
@UNDEFINED-ALLOCATED-STATE
|
||||||
|
Checking the state of uninitialised allocatable arrays:
|
||||||
|
@UNDEFINED-ALLOCATED-TRUE
|
||||||
|
Undefined status for allocatable arrays: may be TRUE!
|
||||||
|
- you have to be careful!
|
||||||
|
|
||||||
|
@UNDEFINED-ALLOCATED-FALSE
|
||||||
|
Undefined status for allocatable arrays: seems systematically FALSE
|
||||||
|
- you have to be careful though. This test is NOT rigid
|
||||||
|
|
||||||
|
@UNDEFINED-POINTERS-ASSOC
|
||||||
|
Checking the association of pointers to uninitialised allocatable arrays:
|
||||||
|
@UNDEFINED-ASSOC-SUCCESS
|
||||||
|
Succeeded in associating a pointer to an uninitialised allocatable array'
|
||||||
|
- you have to be careful!
|
||||||
|
|
||||||
|
@UNDEFINED-ASSOC-FAILURE
|
||||||
|
Failed to associate a pointer to an uninitialised allocatable array'
|
||||||
|
- this might be robust!
|
||||||
|
|
||||||
|
@ALLOCATED-POINTERS
|
||||||
|
Manipulating allocated memory
|
||||||
|
-----------------------------
|
||||||
|
FORTRAN 90 allows two ways of allocating and deallocating memory:
|
||||||
|
- Via ALLOCATABLE arrays
|
||||||
|
- Via POINTER variables
|
||||||
|
|
||||||
|
You may combine these methods, but be careful: it may render the
|
||||||
|
variables useless or you get run-time errors.
|
||||||
|
|
||||||
|
Consequently, this test may cause the program to crash.
|
||||||
|
|
||||||
|
@ALLOCATED-POINTERS-SKIPPED
|
||||||
|
Note:
|
||||||
|
Test is skipped.
|
||||||
|
|
||||||
|
@ALLOCATED-POINTERS-STEP1
|
||||||
|
Step 1:
|
||||||
|
- Allocate some memory via an allocatable array
|
||||||
|
- Deallocate it via a pointer to that memory
|
||||||
|
@ALLOCATED-STEP1-SUCCESS
|
||||||
|
Memory freed via pointer - no problem reported
|
||||||
|
Note: ALLOCATED() on allocatable array indicates:
|
||||||
|
@ALLOCATED-STEP1-WARNING
|
||||||
|
Memory still allocated according to target
|
||||||
|
|
||||||
|
@ALLOCATED-STEP1-NOALLOC
|
||||||
|
Memory no longer allocated according to target
|
||||||
|
|
||||||
|
@ALLOCATED-STEP1-FAILURE
|
||||||
|
Memory could not be freed via pointer
|
||||||
|
|
||||||
|
@ALLOCATED-POINTERS-STEP2
|
||||||
|
Step 2:
|
||||||
|
- Allocate some memory via an allocatable array
|
||||||
|
- Let a pointer point to that memory
|
||||||
|
- Deallocate the memory.
|
||||||
|
- What is the status of the pointer?
|
||||||
|
|
||||||
|
Note:
|
||||||
|
Because of the first test, the original allocatable array may have
|
||||||
|
become useless. This second test uses a second allocatable array.
|
||||||
|
|
||||||
|
@ALLOCATED-STEP2-STATUS
|
||||||
|
Memory to which pointer points has been freed. Check the status of
|
||||||
|
the pointer:
|
||||||
|
@ALLOCATED-STEP2-REASSOCIATE
|
||||||
|
Trying to reassociate the pointer:
|
||||||
|
@ALLOCATED-POINTERS-STEP3
|
||||||
|
Step 3:
|
||||||
|
- Try to free the allocated memory twice
|
||||||
|
|
||||||
|
@ALLOCATED-STEP3-SUCCESS
|
||||||
|
Memory freed twice - no problem reported
|
||||||
|
|
||||||
|
@ALLOCATED-STEP3-FAILURE
|
||||||
|
Memory could not be freed again
|
||||||
|
|
||||||
|
@ARRAY-ASSIGNMENT
|
||||||
|
Array assignments
|
||||||
|
-----------------
|
||||||
|
One of the nice features of FORTRAN 90 is that it allows array
|
||||||
|
manipulations as statements. For instance:
|
||||||
|
REAL , DIMENSION(1:10) :: A
|
||||||
|
REAL , DIMENSION(1:10) :: B
|
||||||
|
|
||||||
|
A = B
|
||||||
|
|
||||||
|
means that each element of B is copied into the corresponding element
|
||||||
|
of A.
|
||||||
|
|
||||||
|
This is just a simple example. You can also shift the elements of the
|
||||||
|
same array:
|
||||||
|
|
||||||
|
A(2:10) = A(1:9)
|
||||||
|
|
||||||
|
or turn the array around:
|
||||||
|
|
||||||
|
A(10:1:-1) = A
|
||||||
|
|
||||||
|
Whether such statements are indeed useful, depends on your application,
|
||||||
|
but they can be done!
|
||||||
|
|
||||||
|
This part of the CHKSYSFF program determines if for a number of cases,
|
||||||
|
the results are indeed as expected. It is not a definitive test and may
|
||||||
|
give more insight in what the statements mean than whether the compiler
|
||||||
|
is capable of handling them, but it seems a good exercise anyway.
|
||||||
|
|
||||||
|
@end-of-file
|
||||||
18
flibs-0.9/flibs/chksys/chksysff.set
Normal file
18
flibs-0.9/flibs/chksys/chksysff.set
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# CHKSYSFF: Which checks to perform
|
||||||
|
# Possible keywords:
|
||||||
|
# @GENERAL - all general (well-behaved) tests
|
||||||
|
# @ALLOCATED-POINTERS - check pointers to allocated memory
|
||||||
|
# @INTERACTIVE - interactively select a set of tests
|
||||||
|
# (all of them disruptive!)
|
||||||
|
#
|
||||||
|
# To include the test, the keyword must begin in the first column
|
||||||
|
# To exclude it, use the word SKIP in front.
|
||||||
|
#
|
||||||
|
# If you want concise information about the tests, put the keyword
|
||||||
|
# SUMMARY in (VERBOSE is just to show the opposite: a full report
|
||||||
|
# is default)
|
||||||
|
#
|
||||||
|
VERBOSE
|
||||||
|
@GENERAL
|
||||||
|
@ALLOCATED-POINTERS
|
||||||
|
SKIP @INTERACTIVE
|
||||||
113
flibs-0.9/flibs/chksys/computing/chkrandom.f90
Normal file
113
flibs-0.9/flibs/chksys/computing/chkrandom.f90
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
! chkrandom.f90 --
|
||||||
|
! Program to check a few properties of the random_number and
|
||||||
|
! random_seed subroutines
|
||||||
|
!
|
||||||
|
! Note:
|
||||||
|
! The program must be called twice in succession
|
||||||
|
!
|
||||||
|
|
||||||
|
module random_numbers
|
||||||
|
contains
|
||||||
|
!
|
||||||
|
! Derived from the documentation of gfortran:
|
||||||
|
! A standard-conforming routine to initialise the RNG
|
||||||
|
!
|
||||||
|
! init_random_seed --
|
||||||
|
! Reset the random number generator via the system clock or via
|
||||||
|
! a predefined sequence
|
||||||
|
!
|
||||||
|
! Arguments:
|
||||||
|
! use_time (Optional) Use the system time or not
|
||||||
|
!
|
||||||
|
subroutine init_random_seed( use_time )
|
||||||
|
implicit none
|
||||||
|
logical, intent(in), optional :: use_time
|
||||||
|
|
||||||
|
integer :: i
|
||||||
|
integer :: seed_size
|
||||||
|
integer, dimension(:), allocatable :: seed
|
||||||
|
integer :: clock = 305721054
|
||||||
|
|
||||||
|
call random_seed( size = seed_size )
|
||||||
|
allocate( seed(seed_size) )
|
||||||
|
|
||||||
|
call random_seed( get = seed )
|
||||||
|
|
||||||
|
if ( use_time ) then
|
||||||
|
call system_clock( count = clock )
|
||||||
|
endif
|
||||||
|
|
||||||
|
seed = clock + 37 * (/ ( i-1, i = 1,seed_size ) /)
|
||||||
|
|
||||||
|
call random_seed( put = seed )
|
||||||
|
|
||||||
|
deallocate( seed )
|
||||||
|
end subroutine
|
||||||
|
end module
|
||||||
|
|
||||||
|
program chkrandom
|
||||||
|
implicit none
|
||||||
|
real :: r
|
||||||
|
real :: rsav
|
||||||
|
integer :: seed_size
|
||||||
|
integer, allocatable, dimension(:) :: seed_data
|
||||||
|
integer, allocatable, dimension(:) :: seed_save
|
||||||
|
logical :: exists
|
||||||
|
|
||||||
|
call system_clock( seed_size )
|
||||||
|
write(*,*) 'Clock: ', seed_size
|
||||||
|
|
||||||
|
!
|
||||||
|
! Check:
|
||||||
|
! Is the sequence always the same or not?
|
||||||
|
!
|
||||||
|
inquire( file = 'chkrandom.sav', exist = exists )
|
||||||
|
if ( exists ) then
|
||||||
|
open( 10, file = 'chkrandom.sav' )
|
||||||
|
read( 10, * ) rsav
|
||||||
|
close( 10 )
|
||||||
|
|
||||||
|
call random_number( r )
|
||||||
|
|
||||||
|
if ( abs(r-rsav) < 1.0e-5 ) then
|
||||||
|
write(*,*) 'The random number generator is initialised to the same sequence'
|
||||||
|
else
|
||||||
|
write(*,*) 'The random number generator uses a different sequence at each start-up'
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
|
||||||
|
write(*,*) 'Simple checks on random number generator'
|
||||||
|
write(*,*) '----------------------------------------'
|
||||||
|
|
||||||
|
call random_number( r )
|
||||||
|
open( 10, file = 'chkrandom.sav' )
|
||||||
|
write( 10, '(f12.8)' ) r
|
||||||
|
close( 10 )
|
||||||
|
endif
|
||||||
|
|
||||||
|
!
|
||||||
|
! Inspect:
|
||||||
|
! Seed for the random number generator
|
||||||
|
!
|
||||||
|
call random_seed( size = seed_size )
|
||||||
|
|
||||||
|
allocate( seed_data(seed_size), seed_save(seed_size) )
|
||||||
|
call random_seed( get = seed_save )
|
||||||
|
|
||||||
|
!
|
||||||
|
! This call might reset the RNG to a different sequence
|
||||||
|
!
|
||||||
|
call random_seed
|
||||||
|
|
||||||
|
call random_seed( get = seed_data )
|
||||||
|
|
||||||
|
write(*,*) 'Size of the seed to the random number generator:', seed_size
|
||||||
|
|
||||||
|
write(*,*) 'Effect of call to RANDOM_SEED without arguments:'
|
||||||
|
if ( all( seed_data == seed_save ) ) then
|
||||||
|
write(*,*) ' RNG is reset to standard sequence'
|
||||||
|
else
|
||||||
|
write(*,*) ' RNG is reset to a different sequence each time'
|
||||||
|
endif
|
||||||
|
|
||||||
|
end program
|
||||||
243
flibs-0.9/flibs/chksys/fp_special.f90
Normal file
243
flibs-0.9/flibs/chksys/fp_special.f90
Normal file
@@ -0,0 +1,243 @@
|
|||||||
|
! fp_special.f90 --
|
||||||
|
! Investigate the behaviour of the program vis-a-vis special
|
||||||
|
! IEEE numbers and floating-point exceptions
|
||||||
|
!
|
||||||
|
! Note:
|
||||||
|
! To get full insight, the program may need to run several times
|
||||||
|
! successively skipping tests.
|
||||||
|
!
|
||||||
|
program fp_special
|
||||||
|
implicit none
|
||||||
|
|
||||||
|
integer :: test, success
|
||||||
|
logical :: exists
|
||||||
|
|
||||||
|
real :: y = 0.0
|
||||||
|
real :: z = 1.0e30
|
||||||
|
|
||||||
|
! Start afresh? If the file "fp_special.done" exists or the
|
||||||
|
! file "fp_special.next' does not.
|
||||||
|
!
|
||||||
|
test = -1
|
||||||
|
|
||||||
|
inquire( file = "fp_special.done", exist = exists )
|
||||||
|
if ( exists ) then
|
||||||
|
open( 10, file = "fp_special.done" )
|
||||||
|
close( 10, status = 'delete' )
|
||||||
|
test = 1
|
||||||
|
else
|
||||||
|
inquire( file = "fp_special.next", exist = exists )
|
||||||
|
if ( .not. exists ) then
|
||||||
|
test = 1
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
open( 10, file = "fp_special.next" )
|
||||||
|
if ( test == -1 ) then
|
||||||
|
read( 10, * ) test, success
|
||||||
|
rewind( 10 )
|
||||||
|
if ( success /= 1 ) then
|
||||||
|
write(*,*) 'Previous test failed! The program aborted'
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
!
|
||||||
|
! Select the next test
|
||||||
|
!
|
||||||
|
if ( test == 1 ) then
|
||||||
|
write( 10, * ) test, 0
|
||||||
|
rewind( 10 )
|
||||||
|
call division_by_zero
|
||||||
|
test = 2
|
||||||
|
endif
|
||||||
|
|
||||||
|
if ( test == 2 ) then
|
||||||
|
write( 10, * ) test, 0
|
||||||
|
rewind( 10 )
|
||||||
|
call not_a_number
|
||||||
|
test = 3
|
||||||
|
endif
|
||||||
|
|
||||||
|
if ( test == 3 ) then
|
||||||
|
write( 10, * ) test, 0
|
||||||
|
rewind( 10 )
|
||||||
|
call overflow
|
||||||
|
test = 4
|
||||||
|
endif
|
||||||
|
|
||||||
|
if ( test == 4 ) then
|
||||||
|
write( 10, * ) test, 0
|
||||||
|
rewind( 10 )
|
||||||
|
call underflow
|
||||||
|
endif
|
||||||
|
|
||||||
|
call negative_zero
|
||||||
|
|
||||||
|
close( 10 )
|
||||||
|
open( 10, file= "fp_special.done" )
|
||||||
|
write( 10, * ) 'Done'
|
||||||
|
close( 10 )
|
||||||
|
|
||||||
|
contains
|
||||||
|
|
||||||
|
! division_by_zero --
|
||||||
|
! Does the compiler support division by zero? Or does the program abort?
|
||||||
|
!
|
||||||
|
! Arguments:
|
||||||
|
! None
|
||||||
|
!
|
||||||
|
subroutine division_by_zero
|
||||||
|
|
||||||
|
real :: x
|
||||||
|
|
||||||
|
write( 10, * ) test+1, 0
|
||||||
|
|
||||||
|
write(*,*) 'Test: division by zero'
|
||||||
|
|
||||||
|
x = 1.0 / y
|
||||||
|
|
||||||
|
write(*,*) ' Test succeeded, the program continues'
|
||||||
|
write(*,*) ' Result of 1/0: ', x
|
||||||
|
if ( x > huge(1.0) ) then
|
||||||
|
write(*,*) ' Result is "infinity"'
|
||||||
|
else
|
||||||
|
write(*,*) ' Result is "huge" - it should be "infinity"'
|
||||||
|
endif
|
||||||
|
|
||||||
|
write( 10, * ) test+1, 1
|
||||||
|
|
||||||
|
end subroutine
|
||||||
|
|
||||||
|
! not_a_number --
|
||||||
|
! Does the compiler support not-a-numbers? Or does the program abort?
|
||||||
|
!
|
||||||
|
! Arguments:
|
||||||
|
! None
|
||||||
|
!
|
||||||
|
subroutine not_a_number
|
||||||
|
|
||||||
|
real :: x
|
||||||
|
|
||||||
|
write( 10, * ) test+1, 0
|
||||||
|
|
||||||
|
write(*,*) 'Test: creating Not-a-number'
|
||||||
|
|
||||||
|
x = 0.0 / y
|
||||||
|
|
||||||
|
write(*,*) ' Test succeeded, the program continues'
|
||||||
|
write(*,*) ' Result of 0/0: ', x
|
||||||
|
if ( x >= 0.0 .or. x <= 0.0 ) then
|
||||||
|
write(*,*) ' Result is 0.0 - it should be "NaN"'
|
||||||
|
else
|
||||||
|
write(*,*) ' Result is "NaN"'
|
||||||
|
endif
|
||||||
|
|
||||||
|
write( 10, * ) test+1, 1
|
||||||
|
|
||||||
|
end subroutine
|
||||||
|
|
||||||
|
! overflow --
|
||||||
|
! Does the compiler support overflow? Or does the program abort?
|
||||||
|
!
|
||||||
|
! Arguments:
|
||||||
|
! None
|
||||||
|
!
|
||||||
|
subroutine overflow
|
||||||
|
|
||||||
|
real :: x
|
||||||
|
|
||||||
|
write( 10, * ) test+1, 0
|
||||||
|
|
||||||
|
write(*,*) 'Test: computations with overflow'
|
||||||
|
|
||||||
|
x = 1.0e20 * z
|
||||||
|
|
||||||
|
write(*,*) ' Test succeeded, the program continues'
|
||||||
|
write(*,*) ' Result of 1.0e20 * 1.0e30: ', x
|
||||||
|
if ( x > huge(1.0) ) then
|
||||||
|
write(*,*) ' Result is "Infinity"'
|
||||||
|
else
|
||||||
|
write(*,*) ' Result is "huge"'
|
||||||
|
endif
|
||||||
|
|
||||||
|
write( 10, * ) test+1, 1
|
||||||
|
|
||||||
|
end subroutine
|
||||||
|
|
||||||
|
! underflow --
|
||||||
|
! Does the compiler support underflow (denormalised numbers)?
|
||||||
|
!
|
||||||
|
! Arguments:
|
||||||
|
! None
|
||||||
|
!
|
||||||
|
subroutine underflow
|
||||||
|
|
||||||
|
real :: x
|
||||||
|
real :: xprev
|
||||||
|
|
||||||
|
write( 10, * ) test+1, 0
|
||||||
|
|
||||||
|
write(*,*) 'Test: computations with underflow'
|
||||||
|
|
||||||
|
x = 1.0
|
||||||
|
do while ( x > tiny(x) )
|
||||||
|
xprev = x
|
||||||
|
x = x / 2.0
|
||||||
|
enddo
|
||||||
|
|
||||||
|
write(*,*) ' Test succeeded, the program continues'
|
||||||
|
write(*,*) ' Result of repeated halving: ', x
|
||||||
|
if ( x == 0.0 ) then
|
||||||
|
write(*,*) ' Note: no underflow - small values are truncated to zero'
|
||||||
|
else
|
||||||
|
write(*,*) ' Small values will gradually go to zero'
|
||||||
|
endif
|
||||||
|
|
||||||
|
write( 10, * ) test+1, 1
|
||||||
|
|
||||||
|
end subroutine
|
||||||
|
|
||||||
|
! negative_zero --
|
||||||
|
! Does the compiler support negative zeros?
|
||||||
|
!
|
||||||
|
! Arguments:
|
||||||
|
! None
|
||||||
|
!
|
||||||
|
subroutine negative_zero
|
||||||
|
|
||||||
|
logical :: supported
|
||||||
|
real :: neg_zero
|
||||||
|
|
||||||
|
supported = .false.
|
||||||
|
|
||||||
|
neg_zero = -0.0
|
||||||
|
if ( sign(1.0,neg_zero) < 0.0 ) then
|
||||||
|
supported = .true.
|
||||||
|
else
|
||||||
|
neg_zero = -tiny(1.0)
|
||||||
|
|
||||||
|
do while ( neg_zero /= 0 )
|
||||||
|
neg_zero = neg_zero / 2.0
|
||||||
|
enddo
|
||||||
|
if ( sign(1.0,neg_zero) < 0.0 ) then
|
||||||
|
supported = .true.
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
if ( supported ) then
|
||||||
|
write(*,*) 'Negative zeros are supported'
|
||||||
|
else
|
||||||
|
write(*,*) 'Negative zeros are NOT supported'
|
||||||
|
endif
|
||||||
|
|
||||||
|
neg_zero = sqrt( -0.0 )
|
||||||
|
|
||||||
|
if ( sign(1.0,neg_zero) < 0.0 ) then
|
||||||
|
write(*,*) 'SQRT(-0) is indeed negative (as required by the IEEE standard)'
|
||||||
|
else
|
||||||
|
write(*,*) 'SQRT(-0) is NOT negative! Inconsistent with the IEEE standard'
|
||||||
|
endif
|
||||||
|
|
||||||
|
end subroutine
|
||||||
|
|
||||||
|
end program
|
||||||
23
flibs-0.9/flibs/chksys/os_interact/chkstop.bat
Normal file
23
flibs-0.9/flibs/chksys/os_interact/chkstop.bat
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
@echo off
|
||||||
|
rem Small check: can a Fortran program return a value via the stop
|
||||||
|
rem statement?
|
||||||
|
|
||||||
|
set f95=g95
|
||||||
|
|
||||||
|
rem %f95% -o stopcode stopcode.f90
|
||||||
|
|
||||||
|
.\stopcode
|
||||||
|
if errorlevel 2 goto toohigh
|
||||||
|
if errorlevel 1 goto correct
|
||||||
|
|
||||||
|
echo "Return code was: 0 - should have been 1"
|
||||||
|
goto end
|
||||||
|
|
||||||
|
:correct
|
||||||
|
echo Correct return code found (1)
|
||||||
|
goto end
|
||||||
|
|
||||||
|
:toohigh
|
||||||
|
echo Return code was too high - should have been 1
|
||||||
|
|
||||||
|
:end
|
||||||
16
flibs-0.9/flibs/chksys/os_interact/chkstop.sh
Normal file
16
flibs-0.9/flibs/chksys/os_interact/chkstop.sh
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# Small check: can a Fortran program return a value via the stop
|
||||||
|
# statement?
|
||||||
|
#
|
||||||
|
f95=g95
|
||||||
|
|
||||||
|
#$f95 -o stopcode stopcode.f90
|
||||||
|
|
||||||
|
./stopcode
|
||||||
|
rc=$?
|
||||||
|
if [ $rc = 1 ]; then
|
||||||
|
echo 'Correct return code found (1)'
|
||||||
|
else
|
||||||
|
echo "Return code was: $rc - should have been 1"
|
||||||
|
fi
|
||||||
36
flibs-0.9/flibs/chksys/os_interact/makefile
Normal file
36
flibs-0.9/flibs/chksys/os_interact/makefile
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
# Makefile for "os_interact" test programs
|
||||||
|
#
|
||||||
|
# $Id: makefile,v 1.1 2008/08/12 13:26:02 arjenmarkus Exp $
|
||||||
|
#
|
||||||
|
include ../../config/config.mk
|
||||||
|
include ../../config/options.mk
|
||||||
|
|
||||||
|
PROGRAMS = dirsep$(EXEEXT) \
|
||||||
|
stopcode$(EXEEXT) \
|
||||||
|
reopen_stdin$(EXEEXT) \
|
||||||
|
|
||||||
|
all: $(PROGRAMS)
|
||||||
|
|
||||||
|
dirsep$(OBJEXT): dirsep.f90
|
||||||
|
$(FC) $(FFLAGS) dirsep.f90
|
||||||
|
|
||||||
|
dirsep$(EXEEXT): dirsep$(OBJEXT)
|
||||||
|
$(LD) $(LDFLAGS) $(LDOUTPUT) dirsep$(OBJEXT)
|
||||||
|
|
||||||
|
stopcode$(OBJEXT): stopcode.f90
|
||||||
|
$(FC) $(FFLAGS) stopcode.f90
|
||||||
|
|
||||||
|
stopcode$(EXEEXT): stopcode$(OBJEXT)
|
||||||
|
$(LD) $(LDFLAGS) $(LDOUTPUT) stopcode$(OBJEXT)
|
||||||
|
|
||||||
|
reopen_stdin$(OBJEXT): reopen_stdin.f90
|
||||||
|
$(FC) $(FFLAGS) reopen_stdin.f90
|
||||||
|
|
||||||
|
reopen_stdin$(EXEEXT): reopen_stdin$(OBJEXT)
|
||||||
|
$(LD) $(LDFLAGS) $(LDOUTPUT) reopen_stdin$(OBJEXT)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(DELETE) *$(OBJEXT)
|
||||||
|
$(DELETE) $(PROGRAMS)
|
||||||
|
$(DELETE) *$(MODEXT)
|
||||||
|
|
||||||
26
flibs-0.9/flibs/chksys/os_interact/readme
Normal file
26
flibs-0.9/flibs/chksys/os_interact/readme
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
Interaction with the operating system
|
||||||
|
-------------------------------------
|
||||||
|
|
||||||
|
This directory contains several programs that have the goal of
|
||||||
|
probing the interaction with the operating system:
|
||||||
|
|
||||||
|
* stopcode.f90:
|
||||||
|
Can the STOP statement be used to return a return code to the
|
||||||
|
operating system?
|
||||||
|
|
||||||
|
Run the program via chkstop.sh (for Linux, OSX and UNIX like systems)
|
||||||
|
or chkstop.bat (for Windows)
|
||||||
|
|
||||||
|
* reopen_stdin.f90:
|
||||||
|
Can you reopen standard input so that after reading the contents
|
||||||
|
of a redirected file, you can interact directly with the user?
|
||||||
|
|
||||||
|
Run the program via reopen.sh (for Linux, OSX and UNIX like systems)
|
||||||
|
or reopen.bat (for Windows)
|
||||||
|
|
||||||
|
* dirsep.f90:
|
||||||
|
This program tests the behaviour of a Fortran program where
|
||||||
|
file names with directories are concerned: do you need to use a
|
||||||
|
backslash or is a forward slash okay too on Windows. It appears that
|
||||||
|
most compilers behave as expected with / on Windows. So there would be
|
||||||
|
no need to distinguish the Windows and the Linux case then. Just use a /.
|
||||||
8
flibs-0.9/flibs/chksys/os_interact/reopen.bat
Normal file
8
flibs-0.9/flibs/chksys/os_interact/reopen.bat
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
@echo off
|
||||||
|
rem Can a Fortran program reopen standard input?
|
||||||
|
|
||||||
|
set f95=g95
|
||||||
|
|
||||||
|
%f95% -o reopen_stdin reopen_stdin.f90
|
||||||
|
|
||||||
|
.\reopen_stdin < reopen.inp
|
||||||
3
flibs-0.9/flibs/chksys/os_interact/reopen.inp
Normal file
3
flibs-0.9/flibs/chksys/os_interact/reopen.inp
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
Line 1
|
||||||
|
Line 2
|
||||||
|
Last line
|
||||||
9
flibs-0.9/flibs/chksys/os_interact/reopen.sh
Normal file
9
flibs-0.9/flibs/chksys/os_interact/reopen.sh
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Can a Fortran program reopen standard input?
|
||||||
|
|
||||||
|
#f95=gfortran
|
||||||
|
f95=g95
|
||||||
|
|
||||||
|
$f95 -o reopen_stdin reopen_stdin.f90
|
||||||
|
|
||||||
|
./reopen_stdin < reopen.inp
|
||||||
56
flibs-0.9/flibs/chksys/os_interact/reopen_stdin.f90
Normal file
56
flibs-0.9/flibs/chksys/os_interact/reopen_stdin.f90
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
! reopen_stdin --
|
||||||
|
! Program to read a file via redirection and then open standard
|
||||||
|
! input for ordinary interaction
|
||||||
|
!
|
||||||
|
! Based on an example by Charles Coldwell
|
||||||
|
! http://groups.google.com/group/comp.lang.fortran/browse_frm/thread/56ca2ee5b9d77453#
|
||||||
|
!
|
||||||
|
program stdin
|
||||||
|
implicit none
|
||||||
|
logical :: readline
|
||||||
|
character(len=40) :: line
|
||||||
|
|
||||||
|
write(*,*) 'Read from redirected file ...'
|
||||||
|
do
|
||||||
|
read (5,*,end=100) line
|
||||||
|
write (6,*) line
|
||||||
|
end do
|
||||||
|
100 close(5)
|
||||||
|
|
||||||
|
!
|
||||||
|
! Open the UNIX/Linux/OSX way
|
||||||
|
!
|
||||||
|
readline = .false.
|
||||||
|
open(unit=5,file="/dev/tty", status='old', err = 110)
|
||||||
|
write(*,*) 'Reopening standard input ... use ctrl-D to close the read'
|
||||||
|
do
|
||||||
|
read (5,*,end=200) line
|
||||||
|
readline = .true.
|
||||||
|
write (6,*) line
|
||||||
|
end do
|
||||||
|
goto 200
|
||||||
|
|
||||||
|
!
|
||||||
|
! Open the Windows way
|
||||||
|
!
|
||||||
|
110 continue
|
||||||
|
readline = .false.
|
||||||
|
write(*,*) 'Reopening standard input ... use ctrl-Z to close the read'
|
||||||
|
open(unit=5,file="con", status='old', err = 120)
|
||||||
|
write(*,*) 'Read from redirected file ...'
|
||||||
|
do
|
||||||
|
read (5,*,end=200) line
|
||||||
|
readline = .true.
|
||||||
|
write (6,*) line
|
||||||
|
end do
|
||||||
|
goto 200
|
||||||
|
|
||||||
|
120 continue
|
||||||
|
write(*,*) 'Did not succeed in reopening standard input!'
|
||||||
|
stop
|
||||||
|
|
||||||
|
200 continue
|
||||||
|
if ( .not. readline ) then
|
||||||
|
write(*,*) 'No line read after reopening standard input!'
|
||||||
|
endif
|
||||||
|
end program stdin
|
||||||
11
flibs-0.9/flibs/chksys/os_interact/stopcode.f90
Normal file
11
flibs-0.9/flibs/chksys/os_interact/stopcode.f90
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
! stopcode.f90 --
|
||||||
|
! Small program to check if the STOP statement can be used to
|
||||||
|
! transmit a return code to the operating system
|
||||||
|
!
|
||||||
|
! The code is to be received by the calling shell script or
|
||||||
|
! batch file. The correct value is 1
|
||||||
|
!
|
||||||
|
program stopcode
|
||||||
|
write(*,*) 'Stopping with return code 1'
|
||||||
|
stop 1
|
||||||
|
end program
|
||||||
392
flibs-0.9/flibs/chksys/syqrout.f
Normal file
392
flibs-0.9/flibs/chksys/syqrout.f
Normal file
@@ -0,0 +1,392 @@
|
|||||||
|
* @begin@ */
|
||||||
|
*
|
||||||
|
* syqrout.f(or) - routines to determine some properties of the
|
||||||
|
* run-time environment for FORTRAN programs
|
||||||
|
*
|
||||||
|
* Copyright (C) 1998 Arjen Markus
|
||||||
|
*
|
||||||
|
* Arjen Markus
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* General information:
|
||||||
|
* This file contains the following routines:
|
||||||
|
* - SYQOS: Determine some capabilities of the operating
|
||||||
|
* system
|
||||||
|
* - SYQBIN: Determine how to open BINARY files (if possible)
|
||||||
|
* - SYQREC: Determine the length unit for direct access files
|
||||||
|
*
|
||||||
|
* @end@
|
||||||
|
*
|
||||||
|
* $Author$
|
||||||
|
* $Date$
|
||||||
|
* $Source$
|
||||||
|
* $Log$
|
||||||
|
*
|
||||||
|
|
||||||
|
* @@------------------------------------------------------------------
|
||||||
|
* Routine: SYQOS
|
||||||
|
* Author: Arjen Markus
|
||||||
|
* Purpose: Determine the type of the operating system
|
||||||
|
* Context: Used by applications
|
||||||
|
* Summary:
|
||||||
|
* Open specific files that will present if the OS is
|
||||||
|
* of some type. The presence of the files indicates the OS.
|
||||||
|
* Create a few files to check the conventions for file
|
||||||
|
* names. This further narrows the possibilities.
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
* Name Type I/O Description
|
||||||
|
* ITYPE INT O Type of OS:
|
||||||
|
* -1 - Could not be determined
|
||||||
|
* 1 - UNIX
|
||||||
|
* 2 - DOS/Windows 3.x
|
||||||
|
* 3 - Windows 95/NT
|
||||||
|
* LNGNAM LOG O Are long file names allowed (> 14 characters)?
|
||||||
|
* IGNCAS LOG O Are file names case-sensitive?
|
||||||
|
* DIRSEP CHAR*1 O Character for separating directories
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
SUBROUTINE SYQOS( ITYPE , LNGNAM , IGNCAS , DIRSEP )
|
||||||
|
*
|
||||||
|
IMPLICIT NONE
|
||||||
|
*
|
||||||
|
INTEGER ITYPE
|
||||||
|
LOGICAL LNGNAM , IGNCAS
|
||||||
|
CHARACTER*(*) DIRSEP
|
||||||
|
*
|
||||||
|
LOGICAL OPEND , EXISTS
|
||||||
|
INTEGER I , LUN , IERR
|
||||||
|
CHARACTER*40 FILNAM
|
||||||
|
CHARACTER*20 FILUX
|
||||||
|
*
|
||||||
|
DATA FILUX / '/bin/sh' /
|
||||||
|
*
|
||||||
|
* -------- Find a free logical unit number first
|
||||||
|
*
|
||||||
|
ITYPE = -2
|
||||||
|
LNGNAM = .FALSE.
|
||||||
|
IGNCAS = .FALSE.
|
||||||
|
*
|
||||||
|
DO 110 I = 10,99
|
||||||
|
INQUIRE( I , OPENED = OPEND )
|
||||||
|
IF ( .NOT. OPEND ) THEN
|
||||||
|
LUN = I
|
||||||
|
GOTO 200
|
||||||
|
ENDIF
|
||||||
|
110 CONTINUE
|
||||||
|
*
|
||||||
|
* -------- If we get to this point, we could not open a file
|
||||||
|
*
|
||||||
|
RETURN
|
||||||
|
*
|
||||||
|
* -------- If the platform is UNIX, then the file /bin/sh will
|
||||||
|
* exist and be readable
|
||||||
|
*
|
||||||
|
200 CONTINUE
|
||||||
|
INQUIRE( FILE = FILUX , EXIST = EXISTS )
|
||||||
|
IF ( EXISTS ) THEN
|
||||||
|
ITYPE = 1
|
||||||
|
DIRSEP = '/'
|
||||||
|
ENDIF
|
||||||
|
*
|
||||||
|
* -------- For all other platforms, there is no fixed file to be
|
||||||
|
* looked for, except perhaps "autoexec.bat" but even then
|
||||||
|
* the procedure is complicated. So rely on the characteristics
|
||||||
|
* of the file names instead:
|
||||||
|
*
|
||||||
|
* Type long names ignore case in names
|
||||||
|
* UNIX yes/no no!
|
||||||
|
* DOS/WIN3.x no yes
|
||||||
|
* WIN95/NT yes yes (?)
|
||||||
|
*
|
||||||
|
* Long file names:
|
||||||
|
* - if not supported, the file name will be truncated or
|
||||||
|
* an error occurs
|
||||||
|
* Ignore case in file names:
|
||||||
|
* - the file can be opened as SYQOS.TST and syqos.tst
|
||||||
|
*
|
||||||
|
* Note:
|
||||||
|
* Some old versions of UNIX do not support long file names
|
||||||
|
* (they are truncated to 14 characters)
|
||||||
|
*
|
||||||
|
FILNAM = 'syqos_long_file_name'
|
||||||
|
OPEN( LUN , FILE = FILNAM , STATUS = 'UNKNOWN' ,
|
||||||
|
& IOSTAT = IERR )
|
||||||
|
IF ( IERR .EQ. 0 ) THEN
|
||||||
|
WRITE( LUN , * ) 'Test'
|
||||||
|
CLOSE( LUN )
|
||||||
|
*
|
||||||
|
IF ( ITYPE .EQ. 1 ) THEN
|
||||||
|
OPEN( LUN , FILE = FILNAM(1:14) , STATUS = 'OLD' ,
|
||||||
|
& IOSTAT = IERR )
|
||||||
|
ELSE
|
||||||
|
OPEN( LUN , FILE = FILNAM(1:8) , STATUS = 'OLD' ,
|
||||||
|
& IOSTAT = IERR )
|
||||||
|
ENDIF
|
||||||
|
*
|
||||||
|
* -------- Are long names supported?
|
||||||
|
*
|
||||||
|
IF ( IERR .EQ. 0 ) THEN
|
||||||
|
LNGNAM = .FALSE.
|
||||||
|
CLOSE( LUN , STATUS = 'DELETE' )
|
||||||
|
ELSE
|
||||||
|
LNGNAM = .TRUE.
|
||||||
|
ENDIF
|
||||||
|
*
|
||||||
|
* -------- Get rid of the file with the long name as well
|
||||||
|
*
|
||||||
|
OPEN( LUN , FILE = FILNAM , STATUS = 'OLD' ,
|
||||||
|
& IOSTAT = IERR )
|
||||||
|
IF ( IERR .EQ. 0 ) THEN
|
||||||
|
CLOSE( LUN , STATUS = 'DELETE' )
|
||||||
|
ENDIF
|
||||||
|
*
|
||||||
|
* -------- An error occurred in the first place
|
||||||
|
*
|
||||||
|
ELSE
|
||||||
|
LNGNAM = .FALSE.
|
||||||
|
ENDIF
|
||||||
|
*
|
||||||
|
* -------- Now test the distinction between uppercase and lowercase
|
||||||
|
*
|
||||||
|
FILNAM = 'syqos_xx'
|
||||||
|
OPEN( LUN , FILE = FILNAM , STATUS = 'UNKNOWN' ,
|
||||||
|
& IOSTAT = IERR )
|
||||||
|
IF ( IERR .EQ. 0 ) THEN
|
||||||
|
WRITE( LUN , * ) 'Test'
|
||||||
|
CLOSE( LUN )
|
||||||
|
*
|
||||||
|
FIlNAM = 'SYQOS_XX'
|
||||||
|
OPEN( LUN , FILE = FILNAM , STATUS = 'OLD' ,
|
||||||
|
& IOSTAT = IERR )
|
||||||
|
*
|
||||||
|
* -------- Are uppercase and lowercase distinct?
|
||||||
|
*
|
||||||
|
IF ( IERR .EQ. 0 ) THEN
|
||||||
|
IGNCAS = .TRUE.
|
||||||
|
CLOSE( LUN , STATUS = 'DELETE' )
|
||||||
|
ELSE
|
||||||
|
LNGNAM = .TRUE.
|
||||||
|
ENDIF
|
||||||
|
*
|
||||||
|
* -------- Get rid of the file with the lowercase name as well
|
||||||
|
*
|
||||||
|
FILNAM = 'syqos_xx'
|
||||||
|
OPEN( LUN , FILE = FILNAM , STATUS = 'OLD' ,
|
||||||
|
& IOSTAT = IERR )
|
||||||
|
IF ( IERR .EQ. 0 ) THEN
|
||||||
|
CLOSE( LUN , STATUS = 'DELETE' )
|
||||||
|
ENDIF
|
||||||
|
*
|
||||||
|
* -------- An error occurred in the first place:
|
||||||
|
* this represents an unsupported situation!
|
||||||
|
*
|
||||||
|
ELSE
|
||||||
|
ITYPE = -1
|
||||||
|
ENDIF
|
||||||
|
*
|
||||||
|
* -------- Finally we can make a good guess about the operating system
|
||||||
|
*
|
||||||
|
IF ( ITYPE .NE. 1 .AND. ITYPE .NE. -1 ) THEN
|
||||||
|
DIRSEP = '\\'
|
||||||
|
IF ( .NOT. LNGNAM .AND. IGNCAS ) ITYPE = 2
|
||||||
|
IF ( LNGNAM ) ITYPE = 3
|
||||||
|
ENDIF
|
||||||
|
*
|
||||||
|
RETURN
|
||||||
|
END
|
||||||
|
|
||||||
|
* @@------------------------------------------------------------------
|
||||||
|
* Routine: SYQBIN
|
||||||
|
* Author: Arjen Markus
|
||||||
|
* Purpose: Determine if and how a BINARY file can be opened
|
||||||
|
* Context: Used by applications
|
||||||
|
* Summary:
|
||||||
|
* Open a scratch-file, with various possible keywords
|
||||||
|
* Write a single number to it to check if that works.
|
||||||
|
* If so, binary files can be opened that way.
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
* Name Type I/O Description
|
||||||
|
* ALLOWD LOG O If true, binary files are allowed. If false,
|
||||||
|
* you need to use unformatted sequential files.
|
||||||
|
* FORM CHAR*20 O Value for keyword FORM=
|
||||||
|
* ACCESS CHAR*20 O Value for keyword ACCESS=
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
SUBROUTINE SYQBIN( ALLOWD , FORM , ACCESS )
|
||||||
|
*
|
||||||
|
* -------- One common extension to the standard
|
||||||
|
*
|
||||||
|
IMPLICIT NONE
|
||||||
|
*
|
||||||
|
LOGICAL ALLOWD
|
||||||
|
CHARACTER*(*) FORM , ACCESS
|
||||||
|
*
|
||||||
|
INTEGER NOTYPE
|
||||||
|
PARAMETER ( NOTYPE = 2 )
|
||||||
|
*
|
||||||
|
INTEGER IERR , LUN , I , ITYPE , IDUMMY
|
||||||
|
CHARACTER*20 FRMTYP(NOTYPE) , ACCTYP(NOTYPE)
|
||||||
|
LOGICAL OPEND
|
||||||
|
*
|
||||||
|
SAVE FRMTYP , ACCTYP , ITYPE
|
||||||
|
DATA ITYPE / -1 /
|
||||||
|
DATA ( FRMTYP(I) , ACCTYP(I) , I = 1,NOTYPE ) /
|
||||||
|
& 'BINARY' , 'SEQUENTIAL' ,
|
||||||
|
& 'UNFORMATTED' , 'TRANSPARENT' /
|
||||||
|
*
|
||||||
|
* -------- Open the scratch file
|
||||||
|
*
|
||||||
|
DO 110 I = 10,99
|
||||||
|
INQUIRE( I , OPENED = OPEND )
|
||||||
|
IF ( .NOT. OPEND ) THEN
|
||||||
|
LUN = I
|
||||||
|
GOTO 200
|
||||||
|
ENDIF
|
||||||
|
110 CONTINUE
|
||||||
|
*
|
||||||
|
* -------- If we end up here, then we did not find a free unit
|
||||||
|
*
|
||||||
|
ALLOWD = .FALSE.
|
||||||
|
FORM = 'UNFORMATTED'
|
||||||
|
ACCESS = 'SEQUENTIAL'
|
||||||
|
RETURN
|
||||||
|
*
|
||||||
|
* -------- Try to open a scratch-file and write to it
|
||||||
|
*
|
||||||
|
200 CONTINUE
|
||||||
|
IDUMMY = 1
|
||||||
|
ITYPE = -1
|
||||||
|
*
|
||||||
|
DO 210 I = 1,NOTYPE
|
||||||
|
OPEN( LUN , IOSTAT = IERR , FORM = FRMTYP(I) ,
|
||||||
|
& ACCESS = ACCTYP(I) )
|
||||||
|
IF ( IERR .EQ. 0 ) THEN
|
||||||
|
WRITE( LUN , IOSTAT = IERR ) IDUMMY
|
||||||
|
CLOSE( LUN )
|
||||||
|
IF ( IERR .EQ. 0 ) THEN
|
||||||
|
ITYPE = I
|
||||||
|
GOTO 300
|
||||||
|
ENDIF
|
||||||
|
ENDIF
|
||||||
|
210 CONTINUE
|
||||||
|
*
|
||||||
|
* -------- Conclusion: set the parameters
|
||||||
|
*
|
||||||
|
300 CONTINUE
|
||||||
|
IF ( ITYPE .EQ. -1 ) THEN
|
||||||
|
ALLOWD = .FALSE.
|
||||||
|
FORM = 'UNFORMATTED'
|
||||||
|
ACCESS = 'SEQUENTIAL'
|
||||||
|
ELSE
|
||||||
|
ALLOWD = .TRUE.
|
||||||
|
FORM = FRMTYP(ITYPE)
|
||||||
|
ACCESS = ACCTYP(I)
|
||||||
|
ENDIF
|
||||||
|
*
|
||||||
|
RETURN
|
||||||
|
END
|
||||||
|
|
||||||
|
* @@------------------------------------------------------------------
|
||||||
|
* Routine: SYQREC
|
||||||
|
* Author: Arjen Markus
|
||||||
|
* Purpose: Determine the length unit for direct access files
|
||||||
|
* Context: Used by applications
|
||||||
|
* Summary:
|
||||||
|
* Open a scratch-file, with record length 1.
|
||||||
|
* Write a CHARACTER*1 string to eight sequential records.
|
||||||
|
* Set a CHARACTER*8 string to an empty string.
|
||||||
|
* Read eight characters from the first record into the
|
||||||
|
* string.
|
||||||
|
* Find out how many characters were filled.
|
||||||
|
*
|
||||||
|
* Arguments:
|
||||||
|
* Name Type I/O Description
|
||||||
|
* NRCBYT INT O Number of characters in a record
|
||||||
|
* of 1 unit (-1 if the file could not
|
||||||
|
* be opened)
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
SUBROUTINE SYQREC( NRCBYT )
|
||||||
|
*
|
||||||
|
* -------- One common extension to the standard
|
||||||
|
*
|
||||||
|
IMPLICIT NONE
|
||||||
|
*
|
||||||
|
INTEGER NRCBYT
|
||||||
|
*
|
||||||
|
INTEGER IERR , LUN , I , J
|
||||||
|
CHARACTER*1 STROUT
|
||||||
|
CHARACTER*8 STRIN , STRDEF
|
||||||
|
LOGICAL OPEND
|
||||||
|
*
|
||||||
|
* -------- Open the scratch file
|
||||||
|
*
|
||||||
|
DO 110 I = 10,99
|
||||||
|
INQUIRE( I , OPENED = OPEND )
|
||||||
|
IF ( .NOT. OPEND ) THEN
|
||||||
|
LUN = I
|
||||||
|
OPEN ( LUN , STATUS = 'SCRATCH' , IOSTAT = IERR ,
|
||||||
|
& FORM = 'UNFORMATTED' ,
|
||||||
|
& ACCESS = 'DIRECT' , RECL = 1 )
|
||||||
|
IF ( IERR .NE. 0 ) THEN
|
||||||
|
GOTO 900
|
||||||
|
ELSE
|
||||||
|
GOTO 200
|
||||||
|
ENDIF
|
||||||
|
ENDIF
|
||||||
|
110 CONTINUE
|
||||||
|
*
|
||||||
|
* -------- If we end up here, then we did not find a free unit
|
||||||
|
*
|
||||||
|
GOTO 900
|
||||||
|
*
|
||||||
|
* -------- Write the eight records
|
||||||
|
*
|
||||||
|
200 CONTINUE
|
||||||
|
STROUT = 'A'
|
||||||
|
DO 210 I = 1,8
|
||||||
|
WRITE( LUN , IOSTAT = IERR , REC = I ) STROUT
|
||||||
|
IF ( IERR .NE. 0 ) THEN
|
||||||
|
CLOSE( LUN )
|
||||||
|
GOTO 900
|
||||||
|
ENDIF
|
||||||
|
210 CONTINUE
|
||||||
|
*
|
||||||
|
* -------- Try reading the eight characters
|
||||||
|
*
|
||||||
|
NRCBYT = 8
|
||||||
|
STRDEF = '12345678'
|
||||||
|
DO 290 I = 1,8
|
||||||
|
STRIN = STRDEF
|
||||||
|
READ( LUN , IOSTAT = IERR , REC = I )
|
||||||
|
& ( STRIN(J:J) , J = 1,I )
|
||||||
|
*
|
||||||
|
* -------- What could we read?
|
||||||
|
* Assumption: if an error occurs, the rest of the input is
|
||||||
|
* not changed!
|
||||||
|
*
|
||||||
|
IF ( IERR .NE. 0 ) THEN
|
||||||
|
DO 220 J = 1,8
|
||||||
|
IF ( STRIN(J:J) .EQ. STRDEF(J:J) ) THEN
|
||||||
|
NRCBYT = J - 1
|
||||||
|
GOTO 300
|
||||||
|
ENDIF
|
||||||
|
220 CONTINUE
|
||||||
|
ENDIF
|
||||||
|
290 CONTINUE
|
||||||
|
*
|
||||||
|
* -------- We have found something
|
||||||
|
*
|
||||||
|
300 CONTINUE
|
||||||
|
CLOSE( LUN )
|
||||||
|
RETURN
|
||||||
|
*
|
||||||
|
* -------- Some type of error
|
||||||
|
*
|
||||||
|
900 CONTINUE
|
||||||
|
NRCBYT = -1
|
||||||
|
RETURN
|
||||||
|
*
|
||||||
|
END
|
||||||
27
flibs-0.9/flibs/config/config.mk
Normal file
27
flibs-0.9/flibs/config/config.mk
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# Options for g95
|
||||||
|
#
|
||||||
|
# Maybe define LDOUTPUT as LDOUTPUT=-o $@
|
||||||
|
#
|
||||||
|
SPACE = \
|
||||||
|
|
||||||
|
SEP = /
|
||||||
|
|
||||||
|
FC = g95
|
||||||
|
FFLAGS_NORMAL = -c
|
||||||
|
FFLAGS_DEBUG = -c -g
|
||||||
|
FFLAGS_OPTIMISE = -c -O
|
||||||
|
|
||||||
|
LD = g95
|
||||||
|
LDFLAGS_NORMAL =
|
||||||
|
LDFLAGS_DEBUG = -g
|
||||||
|
LDFLAGS_OPTIMISE =
|
||||||
|
#LDOUTPUT = -o$(SPACE)
|
||||||
|
LDOUTPUT = -o $@
|
||||||
|
|
||||||
|
LIB = ar r
|
||||||
|
|
||||||
|
OBJEXT = .o
|
||||||
|
EXEEXT =
|
||||||
|
MODEXT = .mod
|
||||||
|
|
||||||
|
DELETE = rm -f
|
||||||
4
flibs-0.9/flibs/config/cvf.mk
Normal file
4
flibs-0.9/flibs/config/cvf.mk
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# Options for Compaq Visual Fortran
|
||||||
|
#
|
||||||
|
|
||||||
|
Dummy for the moment!
|
||||||
5
flibs-0.9/flibs/config/debug.mk
Normal file
5
flibs-0.9/flibs/config/debug.mk
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Options for a build wih debugging enabled
|
||||||
|
#
|
||||||
|
|
||||||
|
FFLAGS = $(FFLAGS_DEBUG)
|
||||||
|
LDFLAGS = $(LDFLAGS_DEBUG)
|
||||||
27
flibs-0.9/flibs/config/g95.mk
Normal file
27
flibs-0.9/flibs/config/g95.mk
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# Options for g95
|
||||||
|
#
|
||||||
|
# Maybe define LDOUTPUT as LDOUTPUT=-o $@
|
||||||
|
#
|
||||||
|
SPACE = \
|
||||||
|
|
||||||
|
SEP = /
|
||||||
|
|
||||||
|
FC = g95
|
||||||
|
FFLAGS_NORMAL = -c
|
||||||
|
FFLAGS_DEBUG = -c -g
|
||||||
|
FFLAGS_OPTIMISE = -c -O
|
||||||
|
|
||||||
|
LD = g95
|
||||||
|
LDFLAGS_NORMAL =
|
||||||
|
LDFLAGS_DEBUG = -g
|
||||||
|
LDFLAGS_OPTIMISE =
|
||||||
|
#LDOUTPUT = -o$(SPACE)
|
||||||
|
LDOUTPUT = -o $@
|
||||||
|
|
||||||
|
LIB = ar r
|
||||||
|
|
||||||
|
OBJEXT = .o
|
||||||
|
EXEEXT =
|
||||||
|
MODEXT = .mod
|
||||||
|
|
||||||
|
DELETE = rm -f
|
||||||
27
flibs-0.9/flibs/config/gfortran.mk
Normal file
27
flibs-0.9/flibs/config/gfortran.mk
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# Options for gfortran
|
||||||
|
#
|
||||||
|
# Maybe define LDOUTPUT as LDOUTPUT=-o $@
|
||||||
|
#
|
||||||
|
SPACE = \
|
||||||
|
|
||||||
|
SEP = /
|
||||||
|
|
||||||
|
FC = gfortran
|
||||||
|
FFLAGS_NORMAL = -c
|
||||||
|
FFLAGS_DEBUG = -c -g
|
||||||
|
FFLAGS_OPTIMISE = -c -O
|
||||||
|
|
||||||
|
LD = gfortran
|
||||||
|
LDFLAGS_NORMAL =
|
||||||
|
LDFLAGS_DEBUG = -g
|
||||||
|
LDFLAGS_OPTIMISE =
|
||||||
|
#LDOUTPUT = -o$(SPACE)
|
||||||
|
LDOUTPUT = -o $@
|
||||||
|
|
||||||
|
LIB = ar r
|
||||||
|
|
||||||
|
OBJEXT = .o
|
||||||
|
EXEEXT =
|
||||||
|
MODEXT = .mod
|
||||||
|
|
||||||
|
DELETE = rm -f
|
||||||
3
flibs-0.9/flibs/config/idc.f90
Normal file
3
flibs-0.9/flibs/config/idc.f90
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
program idc
|
||||||
|
write(*,*) 'Hello'
|
||||||
|
end program
|
||||||
20
flibs-0.9/flibs/config/makefile
Normal file
20
flibs-0.9/flibs/config/makefile
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# Makefile for Ftcl-example "console"
|
||||||
|
#
|
||||||
|
# $Id: makefile,v 1.1 2006/08/13 07:04:55 arjenmarkus Exp $
|
||||||
|
#
|
||||||
|
include ../../config.mk
|
||||||
|
|
||||||
|
PROGRAM = interactive$(EXEEXT)
|
||||||
|
all: $(PROGRAM)
|
||||||
|
|
||||||
|
interactive$(OBJEXT): interactive.f90
|
||||||
|
$(FC) $(FFLAGS) interactive.f90
|
||||||
|
|
||||||
|
$(PROGRAM): interactive$(OBJEXT)
|
||||||
|
$(LD) $(LDFLAGS) $(LDOUTPUT) interactive$(OBJEXT) $(LIBS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
(DELETE) *$(OBJEXT)
|
||||||
|
(DELETE) *$(EXEEXT)
|
||||||
|
(DELETE) *$(MODEXT)
|
||||||
|
|
||||||
5
flibs-0.9/flibs/config/normal.mk
Normal file
5
flibs-0.9/flibs/config/normal.mk
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Options for a normal build
|
||||||
|
#
|
||||||
|
|
||||||
|
FFLAGS = $(FFLAGS_NORMAL)
|
||||||
|
LDFLAGS = $(LDFLAGS_NORMAL)
|
||||||
5
flibs-0.9/flibs/config/optimise.mk
Normal file
5
flibs-0.9/flibs/config/optimise.mk
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Options for a build with optimisation turned on
|
||||||
|
#
|
||||||
|
|
||||||
|
FFLAGS = $(FFLAGS_OPTIMISE)
|
||||||
|
LDFLAGS = $(LDFLAGS_OPTIMISE)
|
||||||
5
flibs-0.9/flibs/config/options.mk
Normal file
5
flibs-0.9/flibs/config/options.mk
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Options for a normal build
|
||||||
|
#
|
||||||
|
|
||||||
|
FFLAGS = $(FFLAGS_NORMAL)
|
||||||
|
LDFLAGS = $(LDFLAGS_NORMAL)
|
||||||
18
flibs-0.9/flibs/config/readme
Normal file
18
flibs-0.9/flibs/config/readme
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
Configuration
|
||||||
|
-------------
|
||||||
|
This directory contains include files defining the properties of various
|
||||||
|
compilers. Via the configure.bat/configure.sh scripts one compiler is
|
||||||
|
chosen and the corresponding include file is copied to the file
|
||||||
|
"config.mk".
|
||||||
|
|
||||||
|
In a similar way the configuration options are chosen and implemented:
|
||||||
|
one of normal.mk, debug.mk and optimise.mk is copied to "options.mk"
|
||||||
|
|
||||||
|
Note:
|
||||||
|
This is indeed the nth garden-variety configuration system, but any
|
||||||
|
general system (autoconf, CMake, Scons to name the best-known) requires
|
||||||
|
either a Linux/UNIX like OS or at least extra software.
|
||||||
|
|
||||||
|
I deemed this project too "small" to warrant such a configuration
|
||||||
|
system. The method used here is easy to expand and the configuration
|
||||||
|
options themselves are simple.
|
||||||
4
flibs-0.9/flibs/config/salford.mk
Normal file
4
flibs-0.9/flibs/config/salford.mk
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# Options for Salford Fortran
|
||||||
|
#
|
||||||
|
|
||||||
|
Dummy for the moment
|
||||||
109
flibs-0.9/flibs/configure.bat
Normal file
109
flibs-0.9/flibs/configure.bat
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
@echo off
|
||||||
|
echo on
|
||||||
|
rem configure.bat --
|
||||||
|
if @%1 == @-help goto help
|
||||||
|
if @%1 == @/help goto help
|
||||||
|
if @%1 == @-? goto help
|
||||||
|
if @%1 == @/? goto help
|
||||||
|
goto analyse
|
||||||
|
|
||||||
|
:help
|
||||||
|
echo Configure Flibs: identify the compiler and set the build options
|
||||||
|
echo .
|
||||||
|
echo To pick a specific compiler, use:
|
||||||
|
echo c:\> configure name options
|
||||||
|
echo Available compilers:
|
||||||
|
echo - cvf - Compaq Visual Fortran
|
||||||
|
echo - salford - Salford Fortran
|
||||||
|
echo - f95 - generic Fortran 95 compiler
|
||||||
|
echo .
|
||||||
|
echo Available build options:
|
||||||
|
echo -debug
|
||||||
|
echo -normal
|
||||||
|
echo -optimise
|
||||||
|
echo .
|
||||||
|
echo Run this batch file from the central directory!
|
||||||
|
pause
|
||||||
|
goto veryend
|
||||||
|
|
||||||
|
rem
|
||||||
|
rem Identify the build options ...
|
||||||
|
rem
|
||||||
|
:analyse
|
||||||
|
cd config
|
||||||
|
if errorlevel 1 goto error
|
||||||
|
if exist config.mk del config.mk
|
||||||
|
if exist options.mk del options.mk
|
||||||
|
copy normal.mk options.mk
|
||||||
|
if @%1 == @-debug copy debug.mk options.mk
|
||||||
|
if @%1 == @-optimise copy optimise.mk options.mk
|
||||||
|
if @%2 == @-debug copy debug.mk options.mk
|
||||||
|
if @%2 == @-optimise copy optimise.mk options.mk
|
||||||
|
|
||||||
|
echo Identifying compiler ... %1
|
||||||
|
if @%1 == @ goto start
|
||||||
|
if @%1 == @cvf goto cmp_cvf
|
||||||
|
if @%1 == @salford goto cmp_salford
|
||||||
|
if @%1 == @f95 goto cmp_generic
|
||||||
|
if @%2 == @cvf goto cmp_cvf
|
||||||
|
if @%2 == @salford goto cmp_salford
|
||||||
|
if @%2 == @salford goto cmp_generic
|
||||||
|
|
||||||
|
echo Unknown compiler: %1 - searching for known compilers instead
|
||||||
|
|
||||||
|
:start
|
||||||
|
|
||||||
|
rem -----------------------------------------------------------
|
||||||
|
rem Compaq Visual Fortran
|
||||||
|
rem -----------------------------------------------------------
|
||||||
|
rem
|
||||||
|
:cmp_cvf
|
||||||
|
df.exe /compile_only idc.f90
|
||||||
|
if errorlevel 1 goto after_df
|
||||||
|
|
||||||
|
echo Compiler: Compaq Visual Fortran
|
||||||
|
copy cvf.mk config.mk
|
||||||
|
goto end
|
||||||
|
:after_df
|
||||||
|
|
||||||
|
rem -----------------------------------------------------------
|
||||||
|
rem Salford Ftn95
|
||||||
|
rem -----------------------------------------------------------
|
||||||
|
rem
|
||||||
|
:cmp_salford
|
||||||
|
ftn95.exe idc.f90
|
||||||
|
if errorlevel 1 goto after_salf
|
||||||
|
|
||||||
|
echo Compiler: Salford Fortran
|
||||||
|
copy salford.mk config.mk
|
||||||
|
goto end
|
||||||
|
:after_salf
|
||||||
|
|
||||||
|
rem -----------------------------------------------------------
|
||||||
|
rem Generic Fortran 95 compiler
|
||||||
|
rem -----------------------------------------------------------
|
||||||
|
rem
|
||||||
|
:cmp_generic
|
||||||
|
f95.exe idc.f90
|
||||||
|
if errorlevel 1 goto after_generic
|
||||||
|
|
||||||
|
echo Compiler: Generic Fortran 95 compiler
|
||||||
|
copy f95.mk config.mk
|
||||||
|
goto end
|
||||||
|
:after_generic
|
||||||
|
|
||||||
|
rem
|
||||||
|
rem No suitable compiler found
|
||||||
|
rem
|
||||||
|
echo No suitable compiler could be identified
|
||||||
|
goto end
|
||||||
|
|
||||||
|
:error
|
||||||
|
echo Error:
|
||||||
|
echo Subdirectory "config" not found. Please start this batch file in
|
||||||
|
the echo central directory
|
||||||
|
goto veryend
|
||||||
|
|
||||||
|
:end
|
||||||
|
cd ..
|
||||||
|
:veryend
|
||||||
112
flibs-0.9/flibs/configure.sh
Normal file
112
flibs-0.9/flibs/configure.sh
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
#!/usr/bin/sh
|
||||||
|
# Configuration for Flibs: find a suitable compiler and set build options
|
||||||
|
#
|
||||||
|
if test @$1 = "@-help" -o @$1 = "@-?" ;then
|
||||||
|
echo Configure Flibs: identify the compiler and set the build options
|
||||||
|
echo .
|
||||||
|
echo To pick a specific compiler, use:
|
||||||
|
echo % configure name options
|
||||||
|
echo Available compilers:
|
||||||
|
echo - gfortran - Gnu\'s Fortran 95 compiler
|
||||||
|
echo - g95 - Alternative Fortran 95 compiler
|
||||||
|
echo - f95 - generic Fortran 95 compiler
|
||||||
|
echo ""
|
||||||
|
echo Available build options:
|
||||||
|
echo -debug
|
||||||
|
echo -normal
|
||||||
|
echo -optimise
|
||||||
|
echo ""
|
||||||
|
echo Run this batch file from the central directory!
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd config
|
||||||
|
|
||||||
|
#
|
||||||
|
# Clean up
|
||||||
|
#
|
||||||
|
rm -f config.mk
|
||||||
|
rm -f options.mk
|
||||||
|
|
||||||
|
#
|
||||||
|
# Build options
|
||||||
|
#
|
||||||
|
options=normal
|
||||||
|
|
||||||
|
if test @$1 == "@-normal" -o @$2 == "@-normal" ;then
|
||||||
|
options=normal
|
||||||
|
fi
|
||||||
|
if test @$1 == "@-debug" -o @$2 == "@-debug" ;then
|
||||||
|
options=debug
|
||||||
|
fi
|
||||||
|
if test @$1 == "@-optimise" -o @$2 == "@-optimise" ;then
|
||||||
|
options=optimise
|
||||||
|
fi
|
||||||
|
|
||||||
|
cp $options.mk options.mk
|
||||||
|
|
||||||
|
#
|
||||||
|
# Identify the compiler
|
||||||
|
#
|
||||||
|
check=""
|
||||||
|
|
||||||
|
if test @$1 == "@gfortran" -o @$2 == "@gfortran" ;then
|
||||||
|
check=gfortran
|
||||||
|
fi
|
||||||
|
if test @$1 == "@g95" -o @$2 == "@g95" ;then
|
||||||
|
check=g95
|
||||||
|
fi
|
||||||
|
if test @$1 == "@f95" -o @$2 == "@f95" ;then
|
||||||
|
check=f95
|
||||||
|
fi
|
||||||
|
|
||||||
|
found=0
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
# Compiler: gfortran
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
if test $found -eq 0 -a \( "$check" == "" -o "$check" == "gfortran" \) ;then
|
||||||
|
echo Checking gfortran ...
|
||||||
|
gfortran idc.f90
|
||||||
|
if test $? -eq 0 ;then
|
||||||
|
found=1
|
||||||
|
compiler=gfortran
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
# Compiler: g95
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
if test $found -eq 0 -a \( "$check" == "" -o "$check" == "g95" \) ;then
|
||||||
|
echo Checking g95 ...
|
||||||
|
g95 idc.f90
|
||||||
|
if test $? -eq 0 ;then
|
||||||
|
found=1
|
||||||
|
compiler=g95
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
# Compiler: f95
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
if test $found -eq 0 -a \( "$check" == "" -o "$check" == "f95" \) ;then
|
||||||
|
echo Checking f95 ...
|
||||||
|
f95 idc.f90
|
||||||
|
if test $? -eq 0 ;then
|
||||||
|
found=1
|
||||||
|
compiler=f95
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
#
|
||||||
|
# Now that we have found a compiler, copy the settings
|
||||||
|
#
|
||||||
|
if test $found -eq 1 ;then
|
||||||
|
echo Compiler: $compiler
|
||||||
|
cp $compiler.mk config.mk
|
||||||
|
else
|
||||||
|
echo No suitable compiler found!
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd ..
|
||||||
|
exit
|
||||||
221
flibs-0.9/flibs/doc/array_valued.txt
Normal file
221
flibs-0.9/flibs/doc/array_valued.txt
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
Note on array-valued functions
|
||||||
|
|
||||||
|
One feature of Fortran that deserves more attention in my opinion
|
||||||
|
is the use of _array-valued functions_. In particular this feature
|
||||||
|
can be used to achieve a high-level programming style, much like what
|
||||||
|
John Backus advocated in his ACM speech (Backus, ...). Many of the
|
||||||
|
intrinsic functions do and Fortran's array operations are further,
|
||||||
|
be it implicit, examples. Here is a simple case of what I am talking
|
||||||
|
about:
|
||||||
|
|
||||||
|
Suppose you have an array of data and you want to print only those values
|
||||||
|
that are larger than some threshold. One way of doing that is:
|
||||||
|
|
||||||
|
do i = 1,size(data)
|
||||||
|
if ( data(i) > threshold ) then
|
||||||
|
write( *, '(f10.4)' ) data(i)
|
||||||
|
endif
|
||||||
|
enddo
|
||||||
|
|
||||||
|
If you use te _pack_ intrinsic function, this can be written more
|
||||||
|
compactly:
|
||||||
|
|
||||||
|
write( *, '(f10.4)' ) pack( data, data > threshold )
|
||||||
|
|
||||||
|
We can also pass the result of _pack_ to another function or subroutine,
|
||||||
|
for instance one that determines basic statistical properties:
|
||||||
|
|
||||||
|
write( *, '(a,f10.4)') 'Mean of values above mean:', &
|
||||||
|
mean( pack( data, data > mean(data) ) )
|
||||||
|
|
||||||
|
with _mean_ looking like:
|
||||||
|
|
||||||
|
real function mean( data )
|
||||||
|
real, dimension(:) :: data
|
||||||
|
|
||||||
|
mean = sum(data)/max(1,size(data))
|
||||||
|
|
||||||
|
end function mean
|
||||||
|
|
||||||
|
Compare this to an approach with work arrays (so that we can
|
||||||
|
reuse the _mean_ function):
|
||||||
|
|
||||||
|
meanv = mean(data)
|
||||||
|
count = 0
|
||||||
|
|
||||||
|
do i = 1,size(data)
|
||||||
|
if ( data(i) > meanv ) then
|
||||||
|
count = count + 1
|
||||||
|
work(count) = data(i)
|
||||||
|
endif
|
||||||
|
enddo
|
||||||
|
|
||||||
|
write( *, '(a,f10.4)') 'Mean of values above mean:', &
|
||||||
|
mean( work(1:count) )
|
||||||
|
|
||||||
|
|
||||||
|
Or, bypassing the _mean_ function, because it is so simple:
|
||||||
|
|
||||||
|
meanv = mean(data) ! We do need to determine the threshold
|
||||||
|
|
||||||
|
sumv = 0.0
|
||||||
|
count = 0
|
||||||
|
do i = 1,size(data)
|
||||||
|
if ( data(i) > meanv ) then
|
||||||
|
count = count + 1
|
||||||
|
sumv = sumv + data(i)
|
||||||
|
endif
|
||||||
|
enddo
|
||||||
|
|
||||||
|
write( *, '(a,f10.4)') 'Mean of values above mean:', &
|
||||||
|
sumv/max(1,count)
|
||||||
|
|
||||||
|
So, using such functions can lead to more compact, and, in
|
||||||
|
many cases, clearer code. But they do have drawbacks:
|
||||||
|
|
||||||
|
- You can not access individual elements directly, for instance,
|
||||||
|
to determine the second largest element of an array, you
|
||||||
|
need to store the result of a sort function to a proper
|
||||||
|
array first.
|
||||||
|
- Similarly, if you need the result in more than one place,
|
||||||
|
you have to copy them to an actual array or pass them
|
||||||
|
to a function or subroutine.
|
||||||
|
- The functions produce intermediate arrays that need to be
|
||||||
|
allocated and deallocated at appropriate times. This may
|
||||||
|
influence the performance of the program.
|
||||||
|
|
||||||
|
The next two examples are more elaborate: a number-theoretical
|
||||||
|
problem and a compact implementation of the QuickSort algorithm.
|
||||||
|
|
||||||
|
The first requires a bit of explanation: it is a number-theoretical
|
||||||
|
problem regarding the spacing of irrational numbers (book...). The
|
||||||
|
numbers considered are: n alpha mod 1, n = 1 .. N. If we sort these
|
||||||
|
numbers, the spacing between successive numbers can take only one
|
||||||
|
of three distinct values (here the interval [0,1) is wrapped, so
|
||||||
|
that 0.9 and 0.1 are 0.2 apart, not 0.8). The program below
|
||||||
|
demonstrates this:
|
||||||
|
|
||||||
|
It constructs an array of these numbers, sorts them (using a
|
||||||
|
simple algorithm):
|
||||||
|
|
||||||
|
program nneighbours
|
||||||
|
implicit none
|
||||||
|
integer :: i
|
||||||
|
|
||||||
|
write(*,'(f10.4)') cdiff( sort( (/ (mod(i**2*sqrt(2.0),1.0) ,i=1,20) /) ) )
|
||||||
|
|
||||||
|
contains
|
||||||
|
|
||||||
|
function cdiff( array )
|
||||||
|
real, dimension(:) :: array
|
||||||
|
real, dimension(size(array)) :: cdiff
|
||||||
|
|
||||||
|
cdiff = abs( array - cshift(array,1) )
|
||||||
|
cdiff = min( cdiff, 1.0 - cdiff )
|
||||||
|
end function
|
||||||
|
|
||||||
|
function sort( array )
|
||||||
|
real, dimension(:) :: array
|
||||||
|
real, dimension(size(array)) :: sort
|
||||||
|
|
||||||
|
real :: temp
|
||||||
|
integer :: i, j
|
||||||
|
|
||||||
|
sort = array
|
||||||
|
do i = 1,size(sort)
|
||||||
|
do j = i+1,size(sort)
|
||||||
|
if ( sort(i) > sort(j) ) then
|
||||||
|
temp = sort(i)
|
||||||
|
sort(i) = sort(j)
|
||||||
|
sort(j) = temp
|
||||||
|
endif
|
||||||
|
enddo
|
||||||
|
enddo
|
||||||
|
end function
|
||||||
|
end program
|
||||||
|
|
||||||
|
A more traditional program would look like this:
|
||||||
|
|
||||||
|
program nneighbours
|
||||||
|
implicit none
|
||||||
|
integer :: i
|
||||||
|
integer, parameter :: n = 20
|
||||||
|
real, dimension(n) :: data
|
||||||
|
real, dimension(n) :: data
|
||||||
|
|
||||||
|
do i = 1,n
|
||||||
|
data(i) = mod(i*sqrt(2.0),1.0)
|
||||||
|
enddo
|
||||||
|
|
||||||
|
call sort( data )
|
||||||
|
call cdiff( data )
|
||||||
|
|
||||||
|
write(*,'(f10.4)') data
|
||||||
|
|
||||||
|
contains
|
||||||
|
|
||||||
|
subroutine cdiff( array )
|
||||||
|
real, dimension(:) :: array
|
||||||
|
real, dimension(size(array)) :: work
|
||||||
|
integer :: i
|
||||||
|
|
||||||
|
do i = 2,size(array)
|
||||||
|
work(i) = array(i) - array(i-1)
|
||||||
|
enddo
|
||||||
|
work(1) = arrry(1) - array(size(array)
|
||||||
|
|
||||||
|
do i = 1,size(array)
|
||||||
|
array(i) = min( abs(work(i)), abs(1.0-work(i))
|
||||||
|
enddo
|
||||||
|
end subroutine
|
||||||
|
|
||||||
|
subroutine sort( array )
|
||||||
|
real, dimension(:) :: array
|
||||||
|
|
||||||
|
real :: temp
|
||||||
|
integer :: i, j
|
||||||
|
|
||||||
|
do i = 1,size(array)
|
||||||
|
do j = i+1,size(array)
|
||||||
|
if ( array(i) > array(j) ) then
|
||||||
|
temp = sort(i)
|
||||||
|
array(i) = array(j)
|
||||||
|
array(j) = temp
|
||||||
|
endif
|
||||||
|
enddo
|
||||||
|
enddo
|
||||||
|
end function
|
||||||
|
end program
|
||||||
|
|
||||||
|
With array constructors we can do even more surprising things. This
|
||||||
|
implementation of the well-known QuickSort algorithm may not be fast
|
||||||
|
(and it consumes more memory than necessary), but it is rather
|
||||||
|
compact:
|
||||||
|
|
||||||
|
recursive function qsort_reals( data ) result( sorted )
|
||||||
|
real, dimension(:), intent(in) :: data
|
||||||
|
real, dimension(1:size(data)) :: sorted
|
||||||
|
|
||||||
|
if ( size(data) > 1 ) then
|
||||||
|
sorted = (/ qsort_reals( pack( data(2:), data(2:) > data(1) ) ), &
|
||||||
|
data(1), &
|
||||||
|
qsort_reals( pack( data(2:), data(2:) <= data(1) ) ) /)
|
||||||
|
else
|
||||||
|
sorted = data
|
||||||
|
endif
|
||||||
|
end function
|
||||||
|
|
||||||
|
I leave the construction of a more traditional version as an exercise.
|
||||||
|
You can also experiment with a more robust version that has better
|
||||||
|
worse-case behaviour.
|
||||||
|
|
||||||
|
This style of programming is not always the best way to solve a
|
||||||
|
problem: the QuickSort routine above creates multiple copies of the
|
||||||
|
array during the recursion, but if used carefully, it helps create
|
||||||
|
programs that are easy to understand and easily seen to be correct.
|
||||||
|
|
||||||
|
Literature
|
||||||
|
|
||||||
|
J. Backus
|
||||||
|
|
||||||
|
Number-theory book
|
||||||
118
flibs-0.9/flibs/doc/automdiff.man
Normal file
118
flibs-0.9/flibs/doc/automdiff.man
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
[comment {-*- flibs -*- doctools manpage}]
|
||||||
|
[manpage_begin automatic_differentiation n 1.0]
|
||||||
|
[copyright {2006 Arjen Markus <arjenmarkus@sourceforge.net>}]
|
||||||
|
[moddesc flibs]
|
||||||
|
[titledesc {Implement the "automatic differentation" technique}]
|
||||||
|
|
||||||
|
[description]
|
||||||
|
|
||||||
|
The [strong automatic_differentiation] module defines a derived
|
||||||
|
type that enables you (via overloading common mathematical
|
||||||
|
functions and operators) to:
|
||||||
|
|
||||||
|
[list_begin bullet]
|
||||||
|
[bullet]
|
||||||
|
Define a mathematical function in the usual way
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
Evaluate that function [strong and] its first derivative at the same
|
||||||
|
time
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
without having to program that first derivative.
|
||||||
|
|
||||||
|
[para]
|
||||||
|
|
||||||
|
The module uses real numbers of the kind "wp" as defined in the
|
||||||
|
auxiliary module [strong select_precision].
|
||||||
|
|
||||||
|
[para]
|
||||||
|
|
||||||
|
(I was pointed to this technique by Simon Geard, a couple of years ago,
|
||||||
|
in the context of one of the many language shootouts on the Internet.)
|
||||||
|
|
||||||
|
|
||||||
|
[section "EXAMPLE"]
|
||||||
|
|
||||||
|
In numerical methods like Newton-Raphson for finding a root of the
|
||||||
|
equation "f(x) = 0", you need the first derivative:
|
||||||
|
|
||||||
|
[example {
|
||||||
|
x(k+1) = x(k) - f(x(k)) / f'(x(k))
|
||||||
|
}]
|
||||||
|
|
||||||
|
Rather than implementing the function and its first derivatives as
|
||||||
|
separate functions, using this module you can dispense with manually
|
||||||
|
determining the first derivative:
|
||||||
|
|
||||||
|
[example {
|
||||||
|
program root
|
||||||
|
use automatic_differentation
|
||||||
|
|
||||||
|
type(AUTODERIV) :: x
|
||||||
|
type(AUTODERIV) :: res
|
||||||
|
integer :: i
|
||||||
|
|
||||||
|
!
|
||||||
|
! First estimate
|
||||||
|
!
|
||||||
|
x = derivvar( 1.0_wp )
|
||||||
|
|
||||||
|
do i = 1,10
|
||||||
|
res = f(x)
|
||||||
|
x = x - res.v / res.dv
|
||||||
|
enddo
|
||||||
|
|
||||||
|
write(*,*) 'Root: ', x.v
|
||||||
|
contains
|
||||||
|
|
||||||
|
type(AUTODERIV) function f(x)
|
||||||
|
type(AUTODERIV) :: x
|
||||||
|
|
||||||
|
f = x + cos(x)
|
||||||
|
|
||||||
|
end function f
|
||||||
|
end program
|
||||||
|
}]
|
||||||
|
|
||||||
|
|
||||||
|
[section "DATA TYPES AND ROUTINES"]
|
||||||
|
The module defines a single data type, AUTODERIV, and one specific
|
||||||
|
function, derivvar().
|
||||||
|
|
||||||
|
[list_begin definitions]
|
||||||
|
|
||||||
|
[call [cmd "use automatic_differentiation"]]
|
||||||
|
The name of the module
|
||||||
|
|
||||||
|
[call [cmd "type(AUTODERIV)"]]
|
||||||
|
The type has two fields:
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "real(wp)" v]
|
||||||
|
The value of the variable/function (or any intermediate result)
|
||||||
|
|
||||||
|
[arg_def "real(wp)" dv]
|
||||||
|
The first derivative
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "x = derivvar( value )"]]
|
||||||
|
Use this function to properly initialise the program
|
||||||
|
variable x as a "mathematical" variable. (It sets the derivative
|
||||||
|
of x to 1, because otherwise it would be regarded as a constant).
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "real(wp)" value]
|
||||||
|
The value of the "mathematical" variable.
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
[manpage_end]
|
||||||
154
flibs-0.9/flibs/doc/backtrack.man
Normal file
154
flibs-0.9/flibs/doc/backtrack.man
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
[comment {-*- flibs -*- doctools manpage}]
|
||||||
|
[manpage_begin flibs/backtracking n 1.1]
|
||||||
|
[copyright {2006 Arjen Markus <arjenmarkus@sourceforge.net>}]
|
||||||
|
[moddesc flibs]
|
||||||
|
[titledesc {Backtracking}]
|
||||||
|
|
||||||
|
[description]
|
||||||
|
|
||||||
|
The module [emph Backtracking] implements in a general way a well-known
|
||||||
|
algorithm to solve certain combinatorial problems. The module actually
|
||||||
|
consists of a single routine that forms the framework of the algorithm
|
||||||
|
and is to be used in conjunction with a small set of user-defined
|
||||||
|
routines that implement the specific problem.
|
||||||
|
|
||||||
|
[para]
|
||||||
|
The backtracking technique is especially useful if you can build a
|
||||||
|
solution in stages. The classic example is the "eight queens" problem,
|
||||||
|
where you must place eight queens on a chess board in such a way that
|
||||||
|
none can get another in one move. A little thought shows that
|
||||||
|
each queen must be placed in its own column (or row). Placing the first
|
||||||
|
queen in the first column gives us eight possibilities. Placing the
|
||||||
|
second is only possible if it is not within the range of the first one.
|
||||||
|
|
||||||
|
[para]
|
||||||
|
If it is, it makes no sense to continue so we can eliminate in the
|
||||||
|
second step a whole subset of possible configurations, namely those with
|
||||||
|
the second queeen within range of the first.
|
||||||
|
We can continue building up a partial solution in this way until we
|
||||||
|
finally have eight queens on the board.
|
||||||
|
|
||||||
|
[para]
|
||||||
|
The idea of the module is that all the data that describe a possible
|
||||||
|
partial solution to the problem are contained in a derived type called
|
||||||
|
SOLUTION_DATA. Then the user-defined routine [emph generate] generates
|
||||||
|
a new set of partial solutions based on this.
|
||||||
|
|
||||||
|
[para]
|
||||||
|
The new set is examined to see if any is acceptable within the context
|
||||||
|
of the problem, which is done via another user-defined routine.
|
||||||
|
|
||||||
|
[para]
|
||||||
|
Each acceptable solution within this new step may give rise to its own
|
||||||
|
set of further solutions. This way the partial solutions are extended in
|
||||||
|
each step until finally a complete solution is found.
|
||||||
|
|
||||||
|
[section ROUTINES]
|
||||||
|
The module backtracking contains
|
||||||
|
|
||||||
|
[list_begin definitions]
|
||||||
|
|
||||||
|
[call [cmd "call runtests( testproc )"]]
|
||||||
|
Routine to start the unit tests. It checks if the file "funit.run"
|
||||||
|
exists. If so, it will call the subroutine [emph testproc] that was
|
||||||
|
passed. Otherwise it will simply return, so that the ordinary program
|
||||||
|
execution may continue.
|
||||||
|
[nl]
|
||||||
|
If the subroutine testproc returns, the program stops.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
[arg_def "subroutine" testproc]
|
||||||
|
Subroutine that calls the individual test routines. It takes no
|
||||||
|
arguments. It wil generally exist of a series of calls to the
|
||||||
|
routine [emph test] - see below.
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call test( proc, text )"]]
|
||||||
|
Routine to run the individual unit test routine (emph proc). It decides
|
||||||
|
if the test has not run yet and if so, the test routine is called.
|
||||||
|
Otherwise it is skipped.
|
||||||
|
[nl]
|
||||||
|
[emph test] takes care of all administrative details.
|
||||||
|
[nl]
|
||||||
|
Note: to make it possible to use [emph private] unit test routines,
|
||||||
|
the source code of this subroutine is kept in a separate file,
|
||||||
|
[emph funit_test.f90] that should be included in an appropriate
|
||||||
|
place in the program's sources. This way, you can make it a private
|
||||||
|
routine in each module. The only public access to the unit testing
|
||||||
|
routines is then via the subroutine [emph testproc] that is passed to
|
||||||
|
[emph runtests].
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
[arg_def "subroutine" proc]
|
||||||
|
Subroutine that implements an individual unit test. It takes no
|
||||||
|
arguments. Within each such subroutine the complete unit test is run.
|
||||||
|
|
||||||
|
[arg_def "character(len=*), intent(in)" text]
|
||||||
|
Text describing the particular unit test. It is printed in the log
|
||||||
|
file.
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call assert_true( cond, text )"]]
|
||||||
|
Routine to check that a condition is true. If not, a message is printed
|
||||||
|
in the log file and the number of failures is increased.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
[arg_def "logical" cond]
|
||||||
|
The condition to be checked
|
||||||
|
|
||||||
|
[arg_def "character(len=*), intent(in)" text]
|
||||||
|
Text describing the condition
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "exists = funit_file_exists( filename )"]]
|
||||||
|
Logical function to check that a particular file exists
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
[arg_def "character(len=*), intent(in)" filename]
|
||||||
|
Name of the file to be checked
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call funit_get_lun( lun )"]]
|
||||||
|
Subroutine to get a free LU-number
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
[arg_def "integer, intent(out)" lun]
|
||||||
|
Next free LU-number
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call funit_remove_file( filename )"]]
|
||||||
|
Subroutine to remove (delete) a file
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
[arg_def "character(len=*), intent(in)" filename]
|
||||||
|
Name of the file to be removed
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call funit_make_empty_file( filename )"]]
|
||||||
|
Subroutine to make a new, empty file
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
[arg_def "character(len=*), intent(in)" filename]
|
||||||
|
Name of the file to be created
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[section TODO]
|
||||||
|
The following things are still left to do:
|
||||||
|
[list_begin bullet]
|
||||||
|
[bullet]
|
||||||
|
Proper inclusion of the routine [emph prolog] and [emph epilog]
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
Extension of the set of assertion routines
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[manpage_end]
|
||||||
245
flibs-0.9/flibs/doc/binstreams.html
Normal file
245
flibs-0.9/flibs/doc/binstreams.html
Normal file
@@ -0,0 +1,245 @@
|
|||||||
|
<! -- -*- flibs -*- doctools manpage
|
||||||
|
-->
|
||||||
|
<html><head>
|
||||||
|
<title>binary_streams - flibs </title>
|
||||||
|
</head>
|
||||||
|
<! -- Generated from file 'binstreams.man' by tcllib/doctools with format 'html'
|
||||||
|
-->
|
||||||
|
<! -- Copyright © 2006 Arjen Markus <arjenmarkus@sourceforge.net>
|
||||||
|
-->
|
||||||
|
<! -- CVS: $Id$ binary_streams.n
|
||||||
|
-->
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1> binary_streams(n) 1.0 "flibs"</h1>
|
||||||
|
<h2><a name="name">NAME</a></h2>
|
||||||
|
<p>
|
||||||
|
<p> binary_streams - Implement binary streams
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h2><a name="table_of_contents">TABLE OF CONTENTS</a></h2>
|
||||||
|
<p> <a href="#table_of_contents">TABLE OF CONTENTS</a><br>
|
||||||
|
<a href="#synopsis">SYNOPSIS</a><br>
|
||||||
|
<a href="#description">DESCRIPTION</a><br>
|
||||||
|
<a href="#data_types_and_routines">DATA TYPES AND ROUTINES</a><br>
|
||||||
|
<a href="#implementation_notes">IMPLEMENTATION NOTES</a><br>
|
||||||
|
<a href="#copyright">COPYRIGHT</a><br>
|
||||||
|
<h2><a name="synopsis">SYNOPSIS</a></h2>
|
||||||
|
<p>
|
||||||
|
<table border=1 width=100% cellspacing=0 cellpadding=0><tr bgcolor=lightyellow><td bgcolor=lightyellow><table 0 width=100% cellspacing=0 cellpadding=0><tr valign=top ><td ><a href="#1"><b class='cmd'>use binary_streams</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#2"><b class='cmd'>type(BINARY_STREAM)</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#3"><b class='cmd'>call binstream_open( stream, lun, filename, error )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#4"><b class='cmd'>call binstream_close( stream )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#5"><b class='cmd'>call binstream_seek( stream, start, offset )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#6"><b class='cmd'>pos = binstream_tell( stream )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#7"><b class='cmd'>call binstream_read( stream, var, error )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#8"><b class='cmd'>call binstream_write( stream, var, error )</b> </a></td></tr>
|
||||||
|
</table></td></tr></table>
|
||||||
|
<h2><a name="description">DESCRIPTION</a></h2>
|
||||||
|
<p>
|
||||||
|
|
||||||
|
The <em>binary_streams</em> module defines a set of subroutines and
|
||||||
|
functions that allows you to read a file as if it were a "stream"
|
||||||
|
of bytes, rather than, as is more usual a set of records.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
|
||||||
|
The module uses direct-access file I/O but hides the fact that
|
||||||
|
you read from individual records. By providing two routines to
|
||||||
|
query and set the position of the next read/write action and by
|
||||||
|
automatically positioning a "file pointer" otherwise, the module offers
|
||||||
|
the benefits of both direct-access files and sequential files.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
|
||||||
|
<em>Note:</em> In Fortran 2003, the notion of "streams" is formalised.
|
||||||
|
This module will be superfluous with compilers supporting Fortran 2003.
|
||||||
|
Also there are a number of issues that may or may not come into play on
|
||||||
|
a particular system - see the section on <a href="#implementation_notes">IMPLEMENTATION NOTES</a>.
|
||||||
|
|
||||||
|
|
||||||
|
<h2><a name="data_types_and_routines">DATA TYPES AND ROUTINES</a></h2>
|
||||||
|
<p>
|
||||||
|
The module defines a single data type, BINARY_STREAM, and several
|
||||||
|
functions and subroutines:
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt><a name="1"><b class='cmd'>use binary_streams</b> </a><dd>
|
||||||
|
|
||||||
|
The name of the module
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt><a name="2"><b class='cmd'>type(BINARY_STREAM)</b> </a><dd>
|
||||||
|
|
||||||
|
Files are opened and the necessary data are kept in variables of
|
||||||
|
this type.
|
||||||
|
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt><a name="3"><b class='cmd'>call binstream_open( stream, lun, filename, error )</b> </a><dd>
|
||||||
|
|
||||||
|
Open the file "filename" using the LU-number "lun". If some error
|
||||||
|
occurs, the argument "error" is set to true.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(binary_stream) <i class='arg'>stream</i><dd>
|
||||||
|
The variable by which to reference the file
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>integer, intent(in) <i class='arg'>lun</i><dd>
|
||||||
|
The LU-number to connect the file to
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>character(len=*), intent(in) <i class='arg'>filename</i><dd>
|
||||||
|
The name of the file to open
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>logical, intent(out) <i class='arg'>error</i><dd>
|
||||||
|
Argument indicating whether opening the file was successful or not.
|
||||||
|
Note that the file is opened with read/write access (though not
|
||||||
|
explicitly) and that it is opened in such a way that the record length
|
||||||
|
is 4 bytes. If this is not possible (for any number of reasons), an
|
||||||
|
error is returned.
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="4"><b class='cmd'>call binstream_close( stream )</b> </a><dd>
|
||||||
|
|
||||||
|
Close the file that was opened as a stream.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(binary_stream) <i class='arg'>stream</i><dd>
|
||||||
|
The variable by which to reference the file
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="5"><b class='cmd'>call binstream_seek( stream, start, offset )</b> </a><dd>
|
||||||
|
|
||||||
|
Set the position in the file (either from the start or from the current
|
||||||
|
position).
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(binary_stream) <i class='arg'>stream</i><dd>
|
||||||
|
The variable by which to reference the file
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>logical, intent(in) <i class='arg'>start</i><dd>
|
||||||
|
If true, the offset is from the start of the file. Otherwise it is an
|
||||||
|
offset from the current position.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>integer, intent(in) <i class='arg'>offset</i><dd>
|
||||||
|
The number of bytes to skip from the given position. Zero means either
|
||||||
|
the start of the file or the same position.
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="6"><b class='cmd'>pos = binstream_tell( stream )</b> </a><dd>
|
||||||
|
|
||||||
|
Return the current position in the file (in bytes, the first byte is
|
||||||
|
taken as 0).
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(binary_stream) <i class='arg'>stream</i><dd>
|
||||||
|
The variable by which to reference the file
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="7"><b class='cmd'>call binstream_read( stream, var, error )</b> </a><dd>
|
||||||
|
|
||||||
|
Read a variable "var" from the current position in the file.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(binary_stream) <i class='arg'>stream</i><dd>
|
||||||
|
The variable by which to reference the file
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>(...), intent(out) <i class='arg'>var</i><dd>
|
||||||
|
The variable to be read. It can be either a character string, a
|
||||||
|
(default) integer, a (default) real, a (default) logical or a
|
||||||
|
double-precision real. Also one- and two-dimensional arrays of these
|
||||||
|
types are supported.
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="8"><b class='cmd'>call binstream_write( stream, var, error )</b> </a><dd>
|
||||||
|
|
||||||
|
Write a variable "var" at the current position in the file.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(binary_stream) <i class='arg'>stream</i><dd>
|
||||||
|
The variable by which to reference the file
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>(...), intent(in) <i class='arg'>var</i><dd>
|
||||||
|
The variable to be written. It can be either a character string, a
|
||||||
|
(default) integer, a (default) real, a (default) logical or a
|
||||||
|
double-precision real. Also one- and two-dimensional arrays of these
|
||||||
|
types are supported.
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<h2><a name="implementation_notes">IMPLEMENTATION NOTES</a></h2>
|
||||||
|
<p>
|
||||||
|
The module makes a number of assumptions:
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
Any file can be opened as a direct-acess file with any
|
||||||
|
record length
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
To avoid complicated code the files are opened with
|
||||||
|
records of 4 bytes long (ordinary the record length is 4
|
||||||
|
or 1 - the length unit is system-dependent!). This means
|
||||||
|
that systems where the unit is not 1 or 4 bytes are not
|
||||||
|
supported - this could include 64-bits systems.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
The end of a file may not be accurately detected. This
|
||||||
|
is due to the behaviour of direct-access files: the
|
||||||
|
last record may not be complete, if the file size is
|
||||||
|
a multiple of 4 bytes.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
A default integer is assumed to be 4 bytes, as is
|
||||||
|
a default real and a default logical. A double precision
|
||||||
|
real is assumed to be 8 bytes long. There is NO provision
|
||||||
|
for situations where this is not true.
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2><a name="copyright">COPYRIGHT</a></h2>
|
||||||
|
<p>
|
||||||
|
Copyright © 2006 Arjen Markus <arjenmarkus@sourceforge.net><br>
|
||||||
|
</body></html>
|
||||||
|
|
||||||
256
flibs-0.9/flibs/doc/cgi/cgi_protocol.html
Normal file
256
flibs-0.9/flibs/doc/cgi/cgi_protocol.html
Normal file
@@ -0,0 +1,256 @@
|
|||||||
|
<! -- -*- flibs -*- doctools manpage
|
||||||
|
-->
|
||||||
|
<html><head>
|
||||||
|
<title>cgi_protocol - flibs </title>
|
||||||
|
</head>
|
||||||
|
<! -- Generated from file 'cgi_protocol.man' by tcllib/doctools with format 'html'
|
||||||
|
-->
|
||||||
|
<! -- Copyright © 2008 Arjen Markus <arjenmarkus@sourceforge.net>
|
||||||
|
-->
|
||||||
|
<! -- CVS: $Id$ cgi_protocol.n
|
||||||
|
-->
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1> cgi_protocol(n) 1.0 "flibs"</h1>
|
||||||
|
<h2><a name="name">NAME</a></h2>
|
||||||
|
<p>
|
||||||
|
<p> cgi_protocol - Module for supporting the Internet CGI protocol
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h2><a name="table_of_contents">TABLE OF CONTENTS</a></h2>
|
||||||
|
<p> <a href="#table_of_contents">TABLE OF CONTENTS</a><br>
|
||||||
|
<a href="#synopsis">SYNOPSIS</a><br>
|
||||||
|
<a href="#description">DESCRIPTION</a><br>
|
||||||
|
<a href="#data_types_and_routines">DATA TYPES AND ROUTINES</a><br>
|
||||||
|
<a href="#notes">NOTES</a><br>
|
||||||
|
<a href="#copyright">COPYRIGHT</a><br>
|
||||||
|
<h2><a name="synopsis">SYNOPSIS</a></h2>
|
||||||
|
<p>
|
||||||
|
<table border=1 width=100% cellspacing=0 cellpadding=0><tr bgcolor=lightyellow><td bgcolor=lightyellow><table 0 width=100% cellspacing=0 cellpadding=0><tr valign=top ><td ><a href="#1"><b class='cmd'>dict_struct</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#2"><b class='cmd'>dict_data</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#3"><b class='cmd'>call cgi_begin( html, dict, luout )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#4"><b class='cmd'>call cgi_header( type )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#5"><b class='cmd'>call cgi_end</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#6"><b class='cmd'>call cgi_error( msg, template )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#7"><b class='cmd'>call cgi_get_session( dict, value )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#8"><b class='cmd'>call cgi_get( dict, varname, value )</b> </a></td></tr>
|
||||||
|
</table></td></tr></table>
|
||||||
|
<h2><a name="description">DESCRIPTION</a></h2>
|
||||||
|
<p>
|
||||||
|
|
||||||
|
When you want to create web applications, the CGI (common gateway
|
||||||
|
interface) is one of the means to integrate your underlying programs
|
||||||
|
with the web server. The protocol itself is, at least superficially,
|
||||||
|
simple enough, but you need to take care of a number of details.
|
||||||
|
It is these details that the <em>cgi_protocol</em> module seeks to take
|
||||||
|
care of.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The global structure of a program that uses this module to
|
||||||
|
communicate with the web server is basically:
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
Get the data from the web server, via <em>cgi_begin</em>
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
Handle these input data and write the corresponding HTML-file
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
Notify the web server the result is available and stop
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2><a name="data_types_and_routines">DATA TYPES AND ROUTINES</a></h2>
|
||||||
|
<p>
|
||||||
|
The module defines the following data types:
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt><a name="1"><b class='cmd'>dict_struct</b> </a><dd>
|
||||||
|
|
||||||
|
A derived type holding a list of keyword-value pairs. Each value is of the
|
||||||
|
type "dict_data" (see below). The routine <em>cgi_begin</em> fills such a
|
||||||
|
structure to hold all form variables and their values.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt><a name="2"><b class='cmd'>dict_data</b> </a><dd>
|
||||||
|
|
||||||
|
The derived type whose contents is the string value of a particular form
|
||||||
|
variable. It has one component: value, a string of 200 characters long
|
||||||
|
(the actual length is set via the parameter "dict_value_length", so you
|
||||||
|
can easily change it if this should prove necessary).
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
The module defines the following routines:
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt><a name="3"><b class='cmd'>call cgi_begin( html, dict, luout )</b> </a><dd>
|
||||||
|
|
||||||
|
Routine to start the interaction with the web server. It
|
||||||
|
automatically determines the protocol to be used and fills the
|
||||||
|
"dictionary" dict with the values of the form variables for easy
|
||||||
|
retrieval. The last parameter, luout, should be used to write the
|
||||||
|
results to the web server.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>integer, intent(in) <i class='arg'>html</i><dd>
|
||||||
|
Type of output that will be written. Should be one of the following
|
||||||
|
parameters:
|
||||||
|
<br><br>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
output_html - the output will be HTML text (the corresponding CGI header
|
||||||
|
is written by this routine)
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
output_text - the output will be plain ASCII text (the corresponding CGI
|
||||||
|
header is written by this routine)
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
output_no_header - it is not known yet what the output type will be -
|
||||||
|
you can decide this on the basis of the form input. Use <em>cgi_header</em>
|
||||||
|
to write the appropriate header later.
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
output_html_delayed, output_text_delayed - (not implemented yet)
|
||||||
|
indicate that the computation will take a while, so that a simple
|
||||||
|
message is written first.
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<dt>type(dict_struct), pointer <i class='arg'>dict</i><dd>
|
||||||
|
Variable to hold alll the form variables and their values. You pass
|
||||||
|
this variable to <em>cgi_get()</em> to retrieve these values. You can also
|
||||||
|
store new variables and values, if this is useful (via the plain
|
||||||
|
dictionary routines).
|
||||||
|
<br><br>
|
||||||
|
<em>Note:</em>
|
||||||
|
Initialise it to "null()" before calling the routine.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>integer, intent(out) <i class='arg'>luout</i><dd>
|
||||||
|
LU-number for writing output to the web server. Always use this
|
||||||
|
LU-number, not "*" to write the output.
|
||||||
|
<br><br>
|
||||||
|
<em>Note:</em>
|
||||||
|
If "standard output" is used in the protocol, then this LU-number is
|
||||||
|
set to 6 - this is not completely portable of course.
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="4"><b class='cmd'>call cgi_header( type )</b> </a><dd>
|
||||||
|
|
||||||
|
Write the CGI header information
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
<dt>integer, intent(in) <i class='arg'>type</i><dd>
|
||||||
|
Type of output that will be written. See above
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="5"><b class='cmd'>call cgi_end</b> </a><dd>
|
||||||
|
|
||||||
|
Indicate to the server that we are done. The routine stops the program.
|
||||||
|
<br><br>
|
||||||
|
<em>Note:</em>
|
||||||
|
If the run-time library produces extra output as a consequence
|
||||||
|
of finishing the program, then you may want to use compile options to
|
||||||
|
suppress that output. The <em>g95</em> compiler for instance reports any
|
||||||
|
memory that has not been freed. Such output may end up in your HTML
|
||||||
|
output!
|
||||||
|
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt><a name="6"><b class='cmd'>call cgi_error( msg, template )</b> </a><dd>
|
||||||
|
|
||||||
|
Report a fatal error in the form of HTML text
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
<dt>character(len=*), intent(in) <i class='arg'>msg</i><dd>
|
||||||
|
Message to be written
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>character(len=*), intent(in), optional <i class='arg'>template</i><dd>
|
||||||
|
Name of a file to be used as a template. If not given, a simple page
|
||||||
|
will be written instead. The string "MSG" in that template is replaced
|
||||||
|
by the contents of the variable msg.
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="7"><b class='cmd'>call cgi_get_session( dict, value )</b> </a><dd>
|
||||||
|
|
||||||
|
Get the value of the "sessionid" variable. This variable is
|
||||||
|
already present in the form or it is set by this routine to a (more or
|
||||||
|
less) unique value.
|
||||||
|
<br><br>
|
||||||
|
To use it as a session identifier (if your application requires a
|
||||||
|
continued conversation with the user), make sure each subsequent HTML
|
||||||
|
reply contains a line like:
|
||||||
|
<p><table><tr><td bgcolor=black> </td><td><pre class='sample'>
|
||||||
|
<input type="hidden" name="sessionid" value="(contents of the string)">
|
||||||
|
</pre></td></tr></table></p>
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
<dt>character(len=*), intent(out) <i class='arg'>value</i><dd>
|
||||||
|
The unique session ID
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="8"><b class='cmd'>call cgi_get( dict, varname, value )</b> </a><dd>
|
||||||
|
|
||||||
|
Get the value of a variable defined in the HTML form. If the variable is
|
||||||
|
not actually present, the value is left unchanged.
|
||||||
|
<br><br>
|
||||||
|
If you want to check if a form variable by the name of <em>varname</em>
|
||||||
|
actually exists, you can use the <em>dict_has_key</em> function, defined
|
||||||
|
by the <em>dictionary</em> module.
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
<dt>type(DICT_STRUCT), pointer <i class='arg'>dict</i><dd>
|
||||||
|
The dictionary as returned originally by <em>cgi_begin</em> (you may want
|
||||||
|
to add new values and variables yourself for easy reference).
|
||||||
|
<br><br>
|
||||||
|
<dt>character(len=*), intent(in) <i class='arg'>varname</i><dd>
|
||||||
|
The name of the variable to retrieve
|
||||||
|
<br><br>
|
||||||
|
<dt>character(len=*)|real|integer|logical, intent(inout) <i class='arg'>value</i><dd>
|
||||||
|
The value (if the variable exists) - it can be a string, (single
|
||||||
|
precision) real, integer or logical.
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
<h2><a name="notes">NOTES</a></h2>
|
||||||
|
<p>
|
||||||
|
The current implementation assumes that the compiler supports the new
|
||||||
|
intrinsic routine <em>get_environment_variable</em>. If this is not the
|
||||||
|
case, then it is possible to mimick this routine (with a bit of
|
||||||
|
trickery), but that has not been implemented yet in this version.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
There is no support as yet for a delayed response. The idea is that the
|
||||||
|
program sends a short note to the web server, to inform the user that
|
||||||
|
the final result takes a few minutes (or longer) and that he/she can
|
||||||
|
find it at such and such a location.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The <em>cgi_protocol</em> module uses the dictionary module underneath.
|
||||||
|
For convenience the source code for that module is contained within the
|
||||||
|
source directory for the <em>cgi_protocol</em>.
|
||||||
|
|
||||||
|
<h2><a name="copyright">COPYRIGHT</a></h2>
|
||||||
|
<p>
|
||||||
|
Copyright © 2008 Arjen Markus <arjenmarkus@sourceforge.net><br>
|
||||||
|
</body></html>
|
||||||
|
|
||||||
191
flibs-0.9/flibs/doc/cgi/cgi_protocol.man
Normal file
191
flibs-0.9/flibs/doc/cgi/cgi_protocol.man
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
[comment {-*- flibs -*- doctools manpage}]
|
||||||
|
[manpage_begin cgi_protocol n 1.0]
|
||||||
|
[copyright {2008 Arjen Markus <arjenmarkus@sourceforge.net>}]
|
||||||
|
[moddesc flibs]
|
||||||
|
[titledesc {Module for supporting the Internet CGI protocol}]
|
||||||
|
|
||||||
|
[description]
|
||||||
|
|
||||||
|
When you want to create web applications, the CGI (common gateway
|
||||||
|
interface) is one of the means to integrate your underlying programs
|
||||||
|
with the web server. The protocol itself is, at least superficially,
|
||||||
|
simple enough, but you need to take care of a number of details.
|
||||||
|
It is these details that the [emph cgi_protocol] module seeks to take
|
||||||
|
care of.
|
||||||
|
|
||||||
|
[para]
|
||||||
|
The global structure of a program that uses this module to
|
||||||
|
communicate with the web server is basically:
|
||||||
|
|
||||||
|
[list_begin bullet]
|
||||||
|
[bullet]
|
||||||
|
Get the data from the web server, via [emph cgi_begin]
|
||||||
|
[bullet]
|
||||||
|
Handle these input data and write the corresponding HTML-file
|
||||||
|
[bullet]
|
||||||
|
Notify the web server the result is available and stop
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
[section "DATA TYPES AND ROUTINES"]
|
||||||
|
The module defines the following data types:
|
||||||
|
|
||||||
|
[list_begin definitions]
|
||||||
|
|
||||||
|
[call [cmd "dict_struct"]]
|
||||||
|
A derived type holding a list of keyword-value pairs. Each value is of the
|
||||||
|
type "dict_data" (see below). The routine [emph cgi_begin] fills such a
|
||||||
|
structure to hold all form variables and their values.
|
||||||
|
|
||||||
|
[call [cmd "dict_data"]]
|
||||||
|
The derived type whose contents is the string value of a particular form
|
||||||
|
variable. It has one component: value, a string of 200 characters long
|
||||||
|
(the actual length is set via the parameter "dict_value_length", so you
|
||||||
|
can easily change it if this should prove necessary).
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
The module defines the following routines:
|
||||||
|
|
||||||
|
[list_begin definitions]
|
||||||
|
|
||||||
|
[call [cmd "call cgi_begin( html, dict, luout )"]]
|
||||||
|
Routine to start the interaction with the web server. It
|
||||||
|
automatically determines the protocol to be used and fills the
|
||||||
|
"dictionary" dict with the values of the form variables for easy
|
||||||
|
retrieval. The last parameter, luout, should be used to write the
|
||||||
|
results to the web server.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "integer, intent(in)" html]
|
||||||
|
Type of output that will be written. Should be one of the following
|
||||||
|
parameters:
|
||||||
|
[list_begin bullet]
|
||||||
|
[bullet]
|
||||||
|
output_html - the output will be HTML text (the corresponding CGI header
|
||||||
|
is written by this routine)
|
||||||
|
[bullet]
|
||||||
|
output_text - the output will be plain ASCII text (the corresponding CGI
|
||||||
|
header is written by this routine)
|
||||||
|
[bullet]
|
||||||
|
output_no_header - it is not known yet what the output type will be -
|
||||||
|
you can decide this on the basis of the form input. Use [emph cgi_header]
|
||||||
|
to write the appropriate header later.
|
||||||
|
[bullet]
|
||||||
|
output_html_delayed, output_text_delayed - (not implemented yet)
|
||||||
|
indicate that the computation will take a while, so that a simple
|
||||||
|
message is written first.
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
[arg_def "type(dict_struct), pointer" dict]
|
||||||
|
Variable to hold alll the form variables and their values. You pass
|
||||||
|
this variable to [emph cgi_get()] to retrieve these values. You can also
|
||||||
|
store new variables and values, if this is useful (via the plain
|
||||||
|
dictionary routines).
|
||||||
|
[nl]
|
||||||
|
[emph Note:]
|
||||||
|
Initialise it to "null()" before calling the routine.
|
||||||
|
|
||||||
|
[arg_def "integer, intent(out)" luout]
|
||||||
|
LU-number for writing output to the web server. Always use this
|
||||||
|
LU-number, not "*" to write the output.
|
||||||
|
[nl]
|
||||||
|
[emph Note:]
|
||||||
|
If "standard output" is used in the protocol, then this LU-number is
|
||||||
|
set to 6 - this is not completely portable of course.
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call cgi_header( type )"]]
|
||||||
|
Write the CGI header information
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
[arg_def "integer, intent(in)" type]
|
||||||
|
Type of output that will be written. See above
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call cgi_end"]]
|
||||||
|
Indicate to the server that we are done. The routine stops the program.
|
||||||
|
[nl]
|
||||||
|
[emph Note:]
|
||||||
|
If the run-time library produces extra output as a consequence
|
||||||
|
of finishing the program, then you may want to use compile options to
|
||||||
|
suppress that output. The [emph g95] compiler for instance reports any
|
||||||
|
memory that has not been freed. Such output may end up in your HTML
|
||||||
|
output!
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call cgi_error( msg, template )"]]
|
||||||
|
Report a fatal error in the form of HTML text
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
[arg_def "character(len=*), intent(in)" msg]
|
||||||
|
Message to be written
|
||||||
|
|
||||||
|
[arg_def "character(len=*), intent(in), optional" template]
|
||||||
|
Name of a file to be used as a template. If not given, a simple page
|
||||||
|
will be written instead. The string "MSG" in that template is replaced
|
||||||
|
by the contents of the variable msg.
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call cgi_get_session( dict, value )"]]
|
||||||
|
Get the value of the "sessionid" variable. This variable is
|
||||||
|
already present in the form or it is set by this routine to a (more or
|
||||||
|
less) unique value.
|
||||||
|
[nl]
|
||||||
|
To use it as a session identifier (if your application requires a
|
||||||
|
continued conversation with the user), make sure each subsequent HTML
|
||||||
|
reply contains a line like:
|
||||||
|
[example {
|
||||||
|
<input type="hidden" name="sessionid" value="(contents of the string)">
|
||||||
|
}]
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
[arg_def "character(len=*), intent(out)" value]
|
||||||
|
The unique session ID
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call cgi_get( dict, varname, value )"]]
|
||||||
|
Get the value of a variable defined in the HTML form. If the variable is
|
||||||
|
not actually present, the value is left unchanged.
|
||||||
|
[nl]
|
||||||
|
If you want to check if a form variable by the name of [term varname]
|
||||||
|
actually exists, you can use the [term dict_has_key] function, defined
|
||||||
|
by the [term dictionary] module.
|
||||||
|
[list_begin arg]
|
||||||
|
[arg_def "type(DICT_STRUCT), pointer" dict]
|
||||||
|
The dictionary as returned originally by [term cgi_begin] (you may want
|
||||||
|
to add new values and variables yourself for easy reference).
|
||||||
|
[arg_def "character(len=*), intent(in)" varname]
|
||||||
|
The name of the variable to retrieve
|
||||||
|
[arg_def "character(len=*)|real|integer|logical, intent(inout)" value]
|
||||||
|
The value (if the variable exists) - it can be a string, (single
|
||||||
|
precision) real, integer or logical.
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[section NOTES]
|
||||||
|
The current implementation assumes that the compiler supports the new
|
||||||
|
intrinsic routine [emph get_environment_variable]. If this is not the
|
||||||
|
case, then it is possible to mimick this routine (with a bit of
|
||||||
|
trickery), but that has not been implemented yet in this version.
|
||||||
|
|
||||||
|
[para]
|
||||||
|
There is no support as yet for a delayed response. The idea is that the
|
||||||
|
program sends a short note to the web server, to inform the user that
|
||||||
|
the final result takes a few minutes (or longer) and that he/she can
|
||||||
|
find it at such and such a location.
|
||||||
|
|
||||||
|
[para]
|
||||||
|
The [emph cgi_protocol] module uses the dictionary module underneath.
|
||||||
|
For convenience the source code for that module is contained within the
|
||||||
|
source directory for the [emph cgi_protocol].
|
||||||
|
|
||||||
|
[manpage_end]
|
||||||
157
flibs-0.9/flibs/doc/checking/checking.html
Normal file
157
flibs-0.9/flibs/doc/checking/checking.html
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
|
||||||
|
<html><head>
|
||||||
|
<title>checking - flibs </title>
|
||||||
|
</head>
|
||||||
|
<! -- Generated from file 'checking.man' by tcllib/doctools with format 'html'
|
||||||
|
-->
|
||||||
|
<! -- Copyright © 2007 Arjen Markus <arjenmarkus@sourceforge.net>
|
||||||
|
-->
|
||||||
|
<! -- CVS: $Id: checking.html,v 1.1 2008/06/13 10:22:46 relaxmike Exp $ checking.n
|
||||||
|
-->
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1> checking(n) 1.0 "flibs"</h1>
|
||||||
|
<h2><a name="name">NAME</a></h2>
|
||||||
|
<p>
|
||||||
|
<p> checking - Instrument source code for tracing execution
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h2><a name="table_of_contents">TABLE OF CONTENTS</a></h2>
|
||||||
|
<p> <a href="#table_of_contents">TABLE OF CONTENTS</a><br>
|
||||||
|
<a href="#description">DESCRIPTION</a><br>
|
||||||
|
<a href="#usage">Usage</a><br>
|
||||||
|
<a href="#notes">Notes</a><br>
|
||||||
|
<a href="#copyright">COPYRIGHT</a><br>
|
||||||
|
<h2><a name="description">DESCRIPTION</a></h2>
|
||||||
|
<p>
|
||||||
|
|
||||||
|
If you need to understand a program written by somebody else,
|
||||||
|
it is often useful to run it in a debugger to see what it is
|
||||||
|
doing, but that can be time-consuming. Adding write statements
|
||||||
|
to the program is an alternative, but again time-consuming.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The module <em>w_</em> is meant, in conjunction with the Tcl program
|
||||||
|
<em>instrument.tcl</em> to automate the process of adding such
|
||||||
|
write statements.
|
||||||
|
|
||||||
|
The write statements that are added record:
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
Calls to a subroutine (which routine, where)
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
Returns from the subroutine
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
Gotos within the main program or subroutine
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
Opening/closing of files
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
Stop statements
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
Messages indicating what is happening in the program are written
|
||||||
|
to the screen (unit * to be more precise), because that way no
|
||||||
|
extra logical unit is consumed and it is easier to see the
|
||||||
|
program's actions in conjunction to the output it produces.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The design goals were:
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
The code transformations should be simple (because these would
|
||||||
|
be easier to implement!)
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
The code transformations should not change the program's logic
|
||||||
|
(of course!)
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
The module uses <em>alternative returns</em> to succeed in achieving
|
||||||
|
these goals, even though they are marked as <em>depricated</em> in the
|
||||||
|
Fortran 90 standard.
|
||||||
|
|
||||||
|
|
||||||
|
<h2><a name="usage">Usage</a></h2>
|
||||||
|
<p>
|
||||||
|
Using the module and the instrumentation program is easy:
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
Run the Tcl program <em>instrument.tcl</em> in the directory with source
|
||||||
|
files:
|
||||||
|
|
||||||
|
<p><table><tr><td bgcolor=black> </td><td><pre class='sample'>
|
||||||
|
> tclsh <directory containing the source>/instrument.tcl
|
||||||
|
</pre></td></tr></table></p>
|
||||||
|
|
||||||
|
This will create an instrumented version of all source files in the
|
||||||
|
directory that have an extension .f, .for or .f90. The original files
|
||||||
|
are first renamed, so that they can be retrieved. (See the
|
||||||
|
tests/checking directory for an example).
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
Add the file "w_.f90" to the list of source files for building the
|
||||||
|
program.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
Build the program by the means you ordinarily use.
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
<h2><a name="notes">Notes</a></h2>
|
||||||
|
<p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
It can not easily log where functions are called, as
|
||||||
|
calls to functions are much more difficult to identify in the
|
||||||
|
source code than subroutine calls. Still, the source code for
|
||||||
|
functions is instrumented in the same way as subroutines
|
||||||
|
(with the exception of pure and elemental functions and
|
||||||
|
subroutines!)
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
The instrumentation program is not foolproof: the generated
|
||||||
|
source will not be correct Fortran, if you use variable names
|
||||||
|
equal to keywords such as "return" or "open". (It is not a
|
||||||
|
full parser of Fortran code, it merely detects certain string
|
||||||
|
patterns and acts accordingly)
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
The name "w_" was chosen, because it is unlikely to be used in
|
||||||
|
any ordinary program as the name of a module or routine.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
Running the Tcl program requires either an installation of Tcl
|
||||||
|
or a standalone Tcl "runtime program" (tclkit).
|
||||||
|
<br><br>
|
||||||
|
For the first: have a look at http://www.activestate.com/tcl
|
||||||
|
<br><br>
|
||||||
|
For the second: http://www.equi4.com/tclkit/index.html
|
||||||
|
<br><br>
|
||||||
|
The advantage of the tclkit family of programs is that installation is
|
||||||
|
simply a matter of copying one single file, an executable program and
|
||||||
|
de-installation is a matter of deleting that program.
|
||||||
|
<br><br>
|
||||||
|
The advantage of the complete installation is that it comes with
|
||||||
|
an extensive set of examples, libraries and documentation on Tcl/Tk.
|
||||||
|
<br><br>
|
||||||
|
(Note: I chose Tcl as the implementation language for this program,
|
||||||
|
because it is very easy to manipulate strings in Tcl. It could be
|
||||||
|
reprogrammed in Fortran - the string matching via regular expressions is
|
||||||
|
the hardest part, but even that can be done by standard means)
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<h2><a name="copyright">COPYRIGHT</a></h2>
|
||||||
|
<p>
|
||||||
|
Copyright © 2007 Arjen Markus <arjenmarkus@sourceforge.net><br>
|
||||||
|
</body></html>
|
||||||
121
flibs-0.9/flibs/doc/checking/checking.man
Normal file
121
flibs-0.9/flibs/doc/checking/checking.man
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
[comment {-*- flibs -*- doctools manpage}]
|
||||||
|
[manpage_begin checking n 1.0]
|
||||||
|
[copyright {2007 Arjen Markus <arjenmarkus@sourceforge.net>}]
|
||||||
|
[moddesc flibs]
|
||||||
|
[titledesc {Instrument source code for tracing execution}]
|
||||||
|
|
||||||
|
[description]
|
||||||
|
|
||||||
|
If you need to understand a program written by somebody else,
|
||||||
|
it is often useful to run it in a debugger to see what it is
|
||||||
|
doing, but that can be time-consuming. Adding write statements
|
||||||
|
to the program is an alternative, but again time-consuming.
|
||||||
|
|
||||||
|
[para]
|
||||||
|
The module [emph w_] is meant, in conjunction with the Tcl program
|
||||||
|
[emph instrument.tcl] to automate the process of adding such
|
||||||
|
write statements.
|
||||||
|
|
||||||
|
The write statements that are added record:
|
||||||
|
[list_begin bullet]
|
||||||
|
[bullet]
|
||||||
|
Calls to a subroutine (which routine, where)
|
||||||
|
[bullet]
|
||||||
|
Returns from the subroutine
|
||||||
|
[bullet]
|
||||||
|
Gotos within the main program or subroutine
|
||||||
|
[bullet]
|
||||||
|
Opening/closing of files
|
||||||
|
[bullet]
|
||||||
|
Stop statements
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
Messages indicating what is happening in the program are written
|
||||||
|
to the screen (unit * to be more precise), because that way no
|
||||||
|
extra logical unit is consumed and it is easier to see the
|
||||||
|
program's actions in conjunction to the output it produces.
|
||||||
|
|
||||||
|
[para]
|
||||||
|
The design goals were:
|
||||||
|
[list_begin bullet]
|
||||||
|
[bullet]
|
||||||
|
The code transformations should be simple (because these would
|
||||||
|
be easier to implement!)
|
||||||
|
[bullet]
|
||||||
|
The code transformations should not change the program's logic
|
||||||
|
(of course!)
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
The module uses [emph "alternative returns"] to succeed in achieving
|
||||||
|
these goals, even though they are marked as [emph depricated] in the
|
||||||
|
Fortran 90 standard.
|
||||||
|
|
||||||
|
|
||||||
|
[section Usage]
|
||||||
|
Using the module and the instrumentation program is easy:
|
||||||
|
[list_begin bullet]
|
||||||
|
[bullet]
|
||||||
|
Run the Tcl program [emph instrument.tcl] in the directory with source
|
||||||
|
files:
|
||||||
|
|
||||||
|
[example {
|
||||||
|
> tclsh <directory containing the source>/instrument.tcl
|
||||||
|
}]
|
||||||
|
|
||||||
|
This will create an instrumented version of all source files in the
|
||||||
|
directory that have an extension .f, .for or .f90. The original files
|
||||||
|
are first renamed, so that they can be retrieved. (See the
|
||||||
|
tests/checking directory for an example).
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
Add the file "w_.f90" to the list of source files for building the
|
||||||
|
program.
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
Build the program by the means you ordinarily use.
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[section Notes]
|
||||||
|
[list_begin bullet]
|
||||||
|
[bullet]
|
||||||
|
It can not easily log where functions are called, as
|
||||||
|
calls to functions are much more difficult to identify in the
|
||||||
|
source code than subroutine calls. Still, the source code for
|
||||||
|
functions is instrumented in the same way as subroutines
|
||||||
|
(with the exception of pure and elemental functions and
|
||||||
|
subroutines!)
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
The instrumentation program is not foolproof: the generated
|
||||||
|
source will not be correct Fortran, if you use variable names
|
||||||
|
equal to keywords such as "return" or "open". (It is not a
|
||||||
|
full parser of Fortran code, it merely detects certain string
|
||||||
|
patterns and acts accordingly)
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
The name "w_" was chosen, because it is unlikely to be used in
|
||||||
|
any ordinary program as the name of a module or routine.
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
Running the Tcl program requires either an installation of Tcl
|
||||||
|
or a standalone Tcl "runtime program" (tclkit).
|
||||||
|
[nl]
|
||||||
|
For the first: have a look at http://www.activestate.com/tcl
|
||||||
|
[nl]
|
||||||
|
For the second: http://www.equi4.com/tclkit/index.html
|
||||||
|
[nl]
|
||||||
|
The advantage of the tclkit family of programs is that installation is
|
||||||
|
simply a matter of copying one single file, an executable program and
|
||||||
|
de-installation is a matter of deleting that program.
|
||||||
|
[nl]
|
||||||
|
The advantage of the complete installation is that it comes with
|
||||||
|
an extensive set of examples, libraries and documentation on Tcl/Tk.
|
||||||
|
[nl]
|
||||||
|
(Note: I chose Tcl as the implementation language for this program,
|
||||||
|
because it is very easy to manipulate strings in Tcl. It could be
|
||||||
|
reprogrammed in Fortran - the string matching via regular expressions is
|
||||||
|
the hardest part, but even that can be done by standard means)
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[manpage_end]
|
||||||
323
flibs-0.9/flibs/doc/computing/annealing.html
Normal file
323
flibs-0.9/flibs/doc/computing/annealing.html
Normal file
@@ -0,0 +1,323 @@
|
|||||||
|
<! -- -*- flibs -*- doctools manpage
|
||||||
|
-->
|
||||||
|
<html><head>
|
||||||
|
<title>simulated_annealing - flibs </title>
|
||||||
|
</head>
|
||||||
|
<! -- Generated from file 'annealing.man' by tcllib/doctools with format 'html'
|
||||||
|
-->
|
||||||
|
<! -- Copyright © 2008 Arjen Markus <arjenmarkus@sourceforge.net>
|
||||||
|
-->
|
||||||
|
<! -- CVS: $Id$ simulated_annealing.n
|
||||||
|
-->
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1> simulated_annealing(n) 1.0 "flibs"</h1>
|
||||||
|
<h2><a name="name">NAME</a></h2>
|
||||||
|
<p>
|
||||||
|
<p> simulated_annealing - Implement a "simulated annealing" algorithm
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h2><a name="table_of_contents">TABLE OF CONTENTS</a></h2>
|
||||||
|
<p> <a href="#table_of_contents">TABLE OF CONTENTS</a><br>
|
||||||
|
<a href="#synopsis">SYNOPSIS</a><br>
|
||||||
|
<a href="#description">DESCRIPTION</a><br>
|
||||||
|
<a href="#data_types_and_routines">DATA TYPES AND ROUTINES</a><br>
|
||||||
|
<a href="#interface_issues">INTERFACE ISSUES</a><br>
|
||||||
|
<a href="#copyright">COPYRIGHT</a><br>
|
||||||
|
<h2><a name="synopsis">SYNOPSIS</a></h2>
|
||||||
|
<p>
|
||||||
|
<table border=1 width=100% cellspacing=0 cellpadding=0><tr bgcolor=lightyellow><td bgcolor=lightyellow><table 0 width=100% cellspacing=0 cellpadding=0><tr valign=top ><td ><a href="#1"><b class='cmd'>use simulated_annealing</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#2"><b class='cmd'>type(ANNEALING_PARAMETERS)</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#3"><b class='cmd'>call set_parameters( params, update, initial_temp, temp_reduction, number_iterations, scale_factor, automatic_scaling, verbose)</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#4"><b class='cmd'>call get_next_step( params, range, x, value, task</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#5"><b class='cmd'>call find_minimum( params, range, x, func, value )</b> </a></td></tr>
|
||||||
|
</table></td></tr></table>
|
||||||
|
<h2><a name="description">DESCRIPTION</a></h2>
|
||||||
|
<p>
|
||||||
|
|
||||||
|
The <em>simulated_annealing</em> module allows you to find the minimum
|
||||||
|
of an arbitrary function of N variables using a straightforward
|
||||||
|
simulated annealing algorithm.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The idea is that the variables can vary independently each within a
|
||||||
|
given interval. For each set of values generated in this way, the
|
||||||
|
function that is to be minimized is evaluated. The new set of values is
|
||||||
|
accepted as the new estimate of the minimum in two situations:
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
The value of the function is lower than the current minimum
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
A generated random number is low enough, that is the expression
|
||||||
|
<p><table><tr><td bgcolor=black> </td><td><pre class='sample'>
|
||||||
|
r < exp(-(new value - old value)/scaled temperature)
|
||||||
|
</pre></td></tr></table></p>
|
||||||
|
is true.
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
The "temperature" is reduced by a constant factor after a given number
|
||||||
|
of iterations, thus making the second case more and more improbable. If
|
||||||
|
there are no new estimates, the iteration stops.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Theoretically, <em>simulated annealing</em> is able to find the global
|
||||||
|
minimum of a function, but it would require infinite time to actually
|
||||||
|
achieve it.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The module implements the basic technique and if the interface to the
|
||||||
|
function is more complex than the subroutine <em>find_minimum</em>
|
||||||
|
assumes, then you can use the code for that routine as a template for a
|
||||||
|
customised version (see below for some ideas regarding such more
|
||||||
|
general functionality).
|
||||||
|
|
||||||
|
|
||||||
|
<h2><a name="data_types_and_routines">DATA TYPES AND ROUTINES</a></h2>
|
||||||
|
<p>
|
||||||
|
The module defines a single data type, ANNEALING_PARAMETERS and several
|
||||||
|
subroutines:
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt><a name="1"><b class='cmd'>use simulated_annealing</b> </a><dd>
|
||||||
|
|
||||||
|
The name of the module. The module itself uses the module
|
||||||
|
<em>select_precision</em> to select single or double precision reals.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt><a name="2"><b class='cmd'>type(ANNEALING_PARAMETERS)</b> </a><dd>
|
||||||
|
|
||||||
|
The type holds the parameters and state variables needed for the
|
||||||
|
iteration. You can set the fields via the subroutine
|
||||||
|
<em>set_parameters</em>.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt><a name="3"><b class='cmd'>call set_parameters( params, update, initial_temp, temp_reduction, number_iterations, scale_factor, automatic_scaling, verbose)</b> </a><dd>
|
||||||
|
|
||||||
|
|
||||||
|
Subroutine to set the individual parameters for the algorithm. (All
|
||||||
|
arguments are optional, except <em>params</em> and <em>update</em>)
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(ANNEALING_PARAMETERS) <i class='arg'>params</i><dd>
|
||||||
|
Derived type holding all parameters (and internal state variables) for
|
||||||
|
the iteration.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>logical <i class='arg'>update</i><dd>
|
||||||
|
If true, only the arguments that are present in the call are used to
|
||||||
|
update the fields in <em>params</em>. Otherwise the structure is first
|
||||||
|
initialised.
|
||||||
|
<br><br>
|
||||||
|
Note: this is probably not a very useful feature.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>real(wp) <i class='arg'>initial_temp</i><dd>
|
||||||
|
Initial "temperature" (defaults to 1). A larger value means it will be
|
||||||
|
easier for the vector representing the estimated minimum to wander
|
||||||
|
about.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>real(wp) <i class='arg'>temp_reduction</i><dd>
|
||||||
|
Factor by which to reduce the temperature (defaults to 0.95). A smaller
|
||||||
|
value means the iteration will settle quicker, but possibly misses the
|
||||||
|
global minimum. A value closer to 1 means the process will take longer,
|
||||||
|
but the result will be more accurate.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>integer <i class='arg'>number_iterations</i><dd>
|
||||||
|
Number of estimates to be examined before reducing the "temperature"
|
||||||
|
(defaults to 100).
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>real(wp) <i class='arg'>scale_factor</i><dd>
|
||||||
|
Factor by which to scale the value before. The idea is that with a well
|
||||||
|
chose scale factor the simulation is more or less independent from the
|
||||||
|
actual values (defaults to 1).
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>logical <i class='arg'>automatic_scaling</i><dd>
|
||||||
|
Whether to first automatically determine a reasonable scale factor or
|
||||||
|
not.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>logical <i class='arg'>verbose</i><dd>
|
||||||
|
Whether to print the intermediate results before reducing the
|
||||||
|
temperature or not.
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="4"><b class='cmd'>call get_next_step( params, range, x, value, task</b> </a><dd>
|
||||||
|
|
||||||
|
Low-level routine that exmaines the function value and decides what the
|
||||||
|
next step will be.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(ANNEALING_PARAMETERS) <i class='arg'>params</i><dd>
|
||||||
|
Derived type holding all parameters (and internal state variables) for
|
||||||
|
the iteration.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>real(wp), dimension(2,:) <i class='arg'>range</i><dd>
|
||||||
|
The minimum and maximum value for each independent variable.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>real(wp), dimension(:) <i class='arg'>x</i><dd>
|
||||||
|
Current estimate of each independent variable where the minimum is
|
||||||
|
attained.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>real(wp) <i class='arg'>value</i><dd>
|
||||||
|
Value of the function at x.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>integer <i class='arg'>task</i><dd>
|
||||||
|
Task to be performed: anneal_init, anneal_print, anneal_value or
|
||||||
|
anneal_done.
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<dt><a name="5"><b class='cmd'>call find_minimum( params, range, x, func, value )</b> </a><dd>
|
||||||
|
|
||||||
|
Routine implementing the procedure to find the minimum.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(ANNEALING_PARAMETERS) <i class='arg'>params</i><dd>
|
||||||
|
Derived type holding all parameters (and internal state variables) for
|
||||||
|
the iteration.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>real(wp), dimension(2,:) <i class='arg'>range</i><dd>
|
||||||
|
The minimum and maximum value for each independent variable.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>real(wp), dimension(:) <i class='arg'>x</i><dd>
|
||||||
|
Upon return, estimate of each independent variable where the minimum is
|
||||||
|
attained.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>real(wp) <i class='arg'>value</i><dd>
|
||||||
|
Estimate of the minimum value of the function (the value at x).
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>real(wp) function <i class='arg'>func(x)</i><dd>
|
||||||
|
The function must have the interface:
|
||||||
|
<p><table><tr><td bgcolor=black> </td><td><pre class='sample'>
|
||||||
|
interface
|
||||||
|
function f(x)
|
||||||
|
use select_precision
|
||||||
|
real(wp), dimension(:), intent(in) :: x
|
||||||
|
real(wp) :: func
|
||||||
|
end function
|
||||||
|
end interface
|
||||||
|
</pre></td></tr></table></p>
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
<h2><a name="interface_issues">INTERFACE ISSUES</a></h2>
|
||||||
|
<p>
|
||||||
|
The interface to the function to be minimized is fixed. This is an
|
||||||
|
unfortunate limitation of Fortran 95. But there are at least two ways
|
||||||
|
around it:
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
If the function requires one or more parameters, or a set of
|
||||||
|
measured data, then it can be useful to store these first as module
|
||||||
|
variables and then call <em>find_minimum</em> with as argument a function
|
||||||
|
in that module that can access the data:
|
||||||
|
<p><table><tr><td bgcolor=black> </td><td><pre class='sample'>
|
||||||
|
module measured_data
|
||||||
|
use select_precision
|
||||||
|
real(wp), dimension(:), allocatable, save :: data
|
||||||
|
contains
|
||||||
|
|
||||||
|
subroutine store_data( array )
|
||||||
|
real(wp), dimension(:) :: data
|
||||||
|
... copy the data
|
||||||
|
end subroutine store_data
|
||||||
|
|
||||||
|
real(wp) function f(x)
|
||||||
|
real(wp), dimension(:) :: x
|
||||||
|
... use x and data to determine the value of f
|
||||||
|
end function f
|
||||||
|
end module
|
||||||
|
</pre></td></tr></table></p>
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
Use the code for <em>find_minimum</em> to implement the evaluation of the
|
||||||
|
function in the way required. The code is fairly straightforward:
|
||||||
|
|
||||||
|
{exampe {
|
||||||
|
subroutine find_minimum( params, range, x, func, value )
|
||||||
|
type(ANNEALING_PARAMETERS), intent(inout) :: params
|
||||||
|
real(wp), dimension(:,:), intent(in) :: range
|
||||||
|
real(wp), dimension(:), intent(inout) :: x
|
||||||
|
real(wp), intent(out) :: value
|
||||||
|
|
||||||
|
interface
|
||||||
|
function func( x )
|
||||||
|
use select_precision
|
||||||
|
real(wp), dimension(:), intent(in) :: x
|
||||||
|
real(wp) :: func
|
||||||
|
end function
|
||||||
|
end interface
|
||||||
|
|
||||||
|
integer :: task
|
||||||
|
|
||||||
|
task = annealing_init
|
||||||
|
|
||||||
|
do
|
||||||
|
call get_next_step( params, range, x, value, task )
|
||||||
|
|
||||||
|
select case ( task )
|
||||||
|
case ( annealing_value )
|
||||||
|
!
|
||||||
|
! Fill in the evaluation of the function
|
||||||
|
!
|
||||||
|
! You can put the customised code here
|
||||||
|
!
|
||||||
|
value = func(x)
|
||||||
|
|
||||||
|
case ( annealing_report )
|
||||||
|
!
|
||||||
|
! Fill in the reporting code
|
||||||
|
!
|
||||||
|
write(*,'(a,e12.4)') 'Value so far: ', value
|
||||||
|
write(*,'(a,(5e12.4),/)') ' Vector: ', x
|
||||||
|
write(*,'(2(a,i5))') ' Accepted: ', &
|
||||||
|
params%accepted, ' from ', params%number_iterations
|
||||||
|
|
||||||
|
case ( annealing_done )
|
||||||
|
exit
|
||||||
|
end select
|
||||||
|
enddo
|
||||||
|
|
||||||
|
end subroutine find_minimum
|
||||||
|
}]
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2><a name="copyright">COPYRIGHT</a></h2>
|
||||||
|
<p>
|
||||||
|
Copyright © 2008 Arjen Markus <arjenmarkus@sourceforge.net><br>
|
||||||
|
</body></html>
|
||||||
|
|
||||||
260
flibs-0.9/flibs/doc/computing/annealing.man
Normal file
260
flibs-0.9/flibs/doc/computing/annealing.man
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
[comment {-*- flibs -*- doctools manpage}]
|
||||||
|
[manpage_begin simulated_annealing n 1.0]
|
||||||
|
[copyright {2008 Arjen Markus <arjenmarkus@sourceforge.net>}]
|
||||||
|
[moddesc flibs]
|
||||||
|
[titledesc {Implement a "simulated annealing" algorithm}]
|
||||||
|
|
||||||
|
[description]
|
||||||
|
|
||||||
|
The [strong simulated_annealing] module allows you to find the minimum
|
||||||
|
of an arbitrary function of N variables using a straightforward
|
||||||
|
simulated annealing algorithm.
|
||||||
|
|
||||||
|
[para]
|
||||||
|
The idea is that the variables can vary independently each within a
|
||||||
|
given interval. For each set of values generated in this way, the
|
||||||
|
function that is to be minimized is evaluated. The new set of values is
|
||||||
|
accepted as the new estimate of the minimum in two situations:
|
||||||
|
|
||||||
|
[list_begin bullet]
|
||||||
|
[bullet]
|
||||||
|
The value of the function is lower than the current minimum
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
A generated random number is low enough, that is the expression
|
||||||
|
[example {
|
||||||
|
r < exp(-(new value - old value)/scaled temperature)
|
||||||
|
}]
|
||||||
|
is true.
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
The "temperature" is reduced by a constant factor after a given number
|
||||||
|
of iterations, thus making the second case more and more improbable. If
|
||||||
|
there are no new estimates, the iteration stops.
|
||||||
|
|
||||||
|
[para]
|
||||||
|
Theoretically, [emph "simulated annealing"] is able to find the global
|
||||||
|
minimum of a function, but it would require infinite time to actually
|
||||||
|
achieve it.
|
||||||
|
|
||||||
|
[para]
|
||||||
|
The module implements the basic technique and if the interface to the
|
||||||
|
function is more complex than the subroutine [term find_minimum]
|
||||||
|
assumes, then you can use the code for that routine as a template for a
|
||||||
|
customised version (see below for some ideas regarding such more
|
||||||
|
general functionality).
|
||||||
|
|
||||||
|
|
||||||
|
[section "DATA TYPES AND ROUTINES"]
|
||||||
|
The module defines a single data type, ANNEALING_PARAMETERS and several
|
||||||
|
subroutines:
|
||||||
|
|
||||||
|
[list_begin definitions]
|
||||||
|
|
||||||
|
[call [cmd "use simulated_annealing"]]
|
||||||
|
The name of the module. The module itself uses the module
|
||||||
|
[term select_precision] to select single or double precision reals.
|
||||||
|
|
||||||
|
[call [cmd "type(ANNEALING_PARAMETERS)"]]
|
||||||
|
The type holds the parameters and state variables needed for the
|
||||||
|
iteration. You can set the fields via the subroutine
|
||||||
|
[term set_parameters].
|
||||||
|
|
||||||
|
[call [cmd "call set_parameters( params, update, initial_temp, \
|
||||||
|
temp_reduction, number_iterations, scale_factor, automatic_scaling, verbose)"]]
|
||||||
|
|
||||||
|
Subroutine to set the individual parameters for the algorithm. (All
|
||||||
|
arguments are optional, except [term params] and [term update])
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(ANNEALING_PARAMETERS)" params]
|
||||||
|
Derived type holding all parameters (and internal state variables) for
|
||||||
|
the iteration.
|
||||||
|
|
||||||
|
[arg_def "logical" update]
|
||||||
|
If true, only the arguments that are present in the call are used to
|
||||||
|
update the fields in [term params]. Otherwise the structure is first
|
||||||
|
initialised.
|
||||||
|
[nl]
|
||||||
|
Note: this is probably not a very useful feature.
|
||||||
|
|
||||||
|
[arg_def "real(wp)" initial_temp]
|
||||||
|
Initial "temperature" (defaults to 1). A larger value means it will be
|
||||||
|
easier for the vector representing the estimated minimum to wander
|
||||||
|
about.
|
||||||
|
|
||||||
|
[arg_def "real(wp)" temp_reduction]
|
||||||
|
Factor by which to reduce the temperature (defaults to 0.95). A smaller
|
||||||
|
value means the iteration will settle quicker, but possibly misses the
|
||||||
|
global minimum. A value closer to 1 means the process will take longer,
|
||||||
|
but the result will be more accurate.
|
||||||
|
|
||||||
|
[arg_def "integer" number_iterations]
|
||||||
|
Number of estimates to be examined before reducing the "temperature"
|
||||||
|
(defaults to 100).
|
||||||
|
|
||||||
|
[arg_def "real(wp)" scale_factor]
|
||||||
|
Factor by which to scale the value before. The idea is that with a well
|
||||||
|
chose scale factor the simulation is more or less independent from the
|
||||||
|
actual values (defaults to 1).
|
||||||
|
|
||||||
|
[arg_def "logical" automatic_scaling]
|
||||||
|
Whether to first automatically determine a reasonable scale factor or
|
||||||
|
not.
|
||||||
|
|
||||||
|
[arg_def "logical" verbose]
|
||||||
|
Whether to print the intermediate results before reducing the
|
||||||
|
temperature or not.
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call get_next_step( params, range, x, value, task"]]
|
||||||
|
Low-level routine that exmaines the function value and decides what the
|
||||||
|
next step will be.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(ANNEALING_PARAMETERS)" params]
|
||||||
|
Derived type holding all parameters (and internal state variables) for
|
||||||
|
the iteration.
|
||||||
|
|
||||||
|
[arg_def "real(wp), dimension(2,:)" range]
|
||||||
|
The minimum and maximum value for each independent variable.
|
||||||
|
|
||||||
|
[arg_def "real(wp), dimension(:)" x]
|
||||||
|
Current estimate of each independent variable where the minimum is
|
||||||
|
attained.
|
||||||
|
|
||||||
|
[arg_def "real(wp)" value]
|
||||||
|
Value of the function at x.
|
||||||
|
|
||||||
|
[arg_def "integer" task]
|
||||||
|
Task to be performed: anneal_init, anneal_print, anneal_value or
|
||||||
|
anneal_done.
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
[call [cmd "call find_minimum( params, range, x, func, value )"]]
|
||||||
|
Routine implementing the procedure to find the minimum.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(ANNEALING_PARAMETERS)" params]
|
||||||
|
Derived type holding all parameters (and internal state variables) for
|
||||||
|
the iteration.
|
||||||
|
|
||||||
|
[arg_def "real(wp), dimension(2,:)" range]
|
||||||
|
The minimum and maximum value for each independent variable.
|
||||||
|
|
||||||
|
[arg_def "real(wp), dimension(:)" x]
|
||||||
|
Upon return, estimate of each independent variable where the minimum is
|
||||||
|
attained.
|
||||||
|
|
||||||
|
[arg_def "real(wp)" value]
|
||||||
|
Estimate of the minimum value of the function (the value at x).
|
||||||
|
|
||||||
|
[arg_def "real(wp) function" func(x)]
|
||||||
|
The function must have the interface:
|
||||||
|
[example {
|
||||||
|
interface
|
||||||
|
function f(x)
|
||||||
|
use select_precision
|
||||||
|
real(wp), dimension(:), intent(in) :: x
|
||||||
|
real(wp) :: func
|
||||||
|
end function
|
||||||
|
end interface
|
||||||
|
}]
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[section "INTERFACE ISSUES"]
|
||||||
|
The interface to the function to be minimized is fixed. This is an
|
||||||
|
unfortunate limitation of Fortran 95. But there are at least two ways
|
||||||
|
around it:
|
||||||
|
|
||||||
|
[list_begin bullet]
|
||||||
|
[bullet]
|
||||||
|
If the function requires one or more parameters, or a set of
|
||||||
|
measured data, then it can be useful to store these first as module
|
||||||
|
variables and then call [term find_minimum] with as argument a function
|
||||||
|
in that module that can access the data:
|
||||||
|
[example {
|
||||||
|
module measured_data
|
||||||
|
use select_precision
|
||||||
|
real(wp), dimension(:), allocatable, save :: data
|
||||||
|
contains
|
||||||
|
|
||||||
|
subroutine store_data( array )
|
||||||
|
real(wp), dimension(:) :: data
|
||||||
|
... copy the data
|
||||||
|
end subroutine store_data
|
||||||
|
|
||||||
|
real(wp) function f(x)
|
||||||
|
real(wp), dimension(:) :: x
|
||||||
|
... use x and data to determine the value of f
|
||||||
|
end function f
|
||||||
|
end module
|
||||||
|
}]
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
Use the code for [term find_minimum] to implement the evaluation of the
|
||||||
|
function in the way required. The code is fairly straightforward:
|
||||||
|
|
||||||
|
{exampe {
|
||||||
|
subroutine find_minimum( params, range, x, func, value )
|
||||||
|
type(ANNEALING_PARAMETERS), intent(inout) :: params
|
||||||
|
real(wp), dimension(:,:), intent(in) :: range
|
||||||
|
real(wp), dimension(:), intent(inout) :: x
|
||||||
|
real(wp), intent(out) :: value
|
||||||
|
|
||||||
|
interface
|
||||||
|
function func( x )
|
||||||
|
use select_precision
|
||||||
|
real(wp), dimension(:), intent(in) :: x
|
||||||
|
real(wp) :: func
|
||||||
|
end function
|
||||||
|
end interface
|
||||||
|
|
||||||
|
integer :: task
|
||||||
|
|
||||||
|
task = annealing_init
|
||||||
|
|
||||||
|
do
|
||||||
|
call get_next_step( params, range, x, value, task )
|
||||||
|
|
||||||
|
select case ( task )
|
||||||
|
case ( annealing_value )
|
||||||
|
!
|
||||||
|
! Fill in the evaluation of the function
|
||||||
|
!
|
||||||
|
! You can put the customised code here
|
||||||
|
!
|
||||||
|
value = func(x)
|
||||||
|
|
||||||
|
case ( annealing_report )
|
||||||
|
!
|
||||||
|
! Fill in the reporting code
|
||||||
|
!
|
||||||
|
write(*,'(a,e12.4)') 'Value so far: ', value
|
||||||
|
write(*,'(a,(5e12.4),/)') ' Vector: ', x
|
||||||
|
write(*,'(2(a,i5))') ' Accepted: ', &
|
||||||
|
params%accepted, ' from ', params%number_iterations
|
||||||
|
|
||||||
|
case ( annealing_done )
|
||||||
|
exit
|
||||||
|
end select
|
||||||
|
enddo
|
||||||
|
|
||||||
|
end subroutine find_minimum
|
||||||
|
}]
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
[manpage_end]
|
||||||
262
flibs-0.9/flibs/doc/computing/automdiff.html
Normal file
262
flibs-0.9/flibs/doc/computing/automdiff.html
Normal file
@@ -0,0 +1,262 @@
|
|||||||
|
<! -- -*- flibs -*- doctools manpage
|
||||||
|
-->
|
||||||
|
<html><head>
|
||||||
|
<title>automatic_differentiation - flibs </title>
|
||||||
|
</head>
|
||||||
|
<! -- Generated from file 'automdiff.man' by tcllib/doctools with format 'html'
|
||||||
|
-->
|
||||||
|
<! -- Copyright © 2006 Arjen Markus <arjenmarkus@sourceforge.net>
|
||||||
|
-->
|
||||||
|
<! -- CVS: $Id: automdiff.html,v 1.2 2008/09/09 04:29:29 arjenmarkus Exp $ automatic_differentiation.n
|
||||||
|
-->
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1> automatic_differentiation(n) 1.0 "flibs"</h1>
|
||||||
|
<h2><a name="name">NAME</a></h2>
|
||||||
|
<p>
|
||||||
|
<p> automatic_differentiation - Implement the "automatic differentation" technique
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h2><a name="table_of_contents">TABLE OF CONTENTS</a></h2>
|
||||||
|
<p> <a href="#table_of_contents">TABLE OF CONTENTS</a><br>
|
||||||
|
<a href="#synopsis">SYNOPSIS</a><br>
|
||||||
|
<a href="#description">DESCRIPTION</a><br>
|
||||||
|
<a href="#example">EXAMPLE</a><br>
|
||||||
|
<a href="#data_types_and_routines">DATA TYPES AND ROUTINES</a><br>
|
||||||
|
<a href="#possible_extensions">POSSIBLE EXTENSIONS</a><br>
|
||||||
|
<a href="#copyright">COPYRIGHT</a><br>
|
||||||
|
<h2><a name="synopsis">SYNOPSIS</a></h2>
|
||||||
|
<p>
|
||||||
|
<table border=1 width=100% cellspacing=0 cellpadding=0><tr bgcolor=lightyellow><td bgcolor=lightyellow><table 0 width=100% cellspacing=0 cellpadding=0><tr valign=top ><td ><a href="#1"><b class='cmd'>use automatic_differentiation</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#2"><b class='cmd'>type(AUTODERIV)</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#3"><b class='cmd'>x = derivvar( value )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#4"><b class='cmd'>call find_root( f, xinit, tolerance, root, found )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#5"><b class='cmd'>call find_root_iter( fvalue, root, tolerance, found )</b> </a></td></tr>
|
||||||
|
</table></td></tr></table>
|
||||||
|
<h2><a name="description">DESCRIPTION</a></h2>
|
||||||
|
<p>
|
||||||
|
|
||||||
|
The <em>automatic_differentiation</em> module defines a derived
|
||||||
|
type that enables you (via overloading common mathematical
|
||||||
|
functions and operators) to:
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
Define a mathematical function in the usual way
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
Evaluate that function <em>and</em> its first derivative at the same
|
||||||
|
time
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
without having to program that first derivative.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
|
||||||
|
The module uses real numbers of the kind "wp" as defined in the
|
||||||
|
auxiliary module <em>select_precision</em>.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
|
||||||
|
(I was pointed to this technique by Simon Geard, a couple of years ago,
|
||||||
|
in the context of one of the many language shootouts on the Internet.)
|
||||||
|
|
||||||
|
|
||||||
|
<h2><a name="example">EXAMPLE</a></h2>
|
||||||
|
<p>
|
||||||
|
|
||||||
|
In numerical methods like Newton-Raphson for finding a root of the
|
||||||
|
equation "f(x) = 0", you need the first derivative:
|
||||||
|
|
||||||
|
<p><table><tr><td bgcolor=black> </td><td><pre class='sample'>
|
||||||
|
x(k+1) = x(k) - f(x(k)) / f'(x(k))
|
||||||
|
</pre></td></tr></table></p>
|
||||||
|
|
||||||
|
Rather than implementing the function and its first derivatives as
|
||||||
|
separate functions, using this module you can dispense with manually
|
||||||
|
determining the first derivative:
|
||||||
|
|
||||||
|
<p><table><tr><td bgcolor=black> </td><td><pre class='sample'>
|
||||||
|
program root
|
||||||
|
use automatic_differentation
|
||||||
|
|
||||||
|
type(AUTODERIV) :: x
|
||||||
|
type(AUTODERIV) :: res
|
||||||
|
integer :: i
|
||||||
|
|
||||||
|
!
|
||||||
|
! First estimate
|
||||||
|
!
|
||||||
|
x = derivvar( 1.0_wp )
|
||||||
|
|
||||||
|
do i = 1,10
|
||||||
|
res = f(x)
|
||||||
|
x = x - res.v / res.dv
|
||||||
|
enddo
|
||||||
|
|
||||||
|
write(*,*) 'Root: ', x.v
|
||||||
|
contains
|
||||||
|
|
||||||
|
type(AUTODERIV) function f(x)
|
||||||
|
type(AUTODERIV) :: x
|
||||||
|
|
||||||
|
f = x + cos(x)
|
||||||
|
|
||||||
|
end function f
|
||||||
|
end program
|
||||||
|
</pre></td></tr></table></p>
|
||||||
|
|
||||||
|
|
||||||
|
<h2><a name="data_types_and_routines">DATA TYPES AND ROUTINES</a></h2>
|
||||||
|
<p>
|
||||||
|
The module defines a single data type, AUTODERIV, and one specific
|
||||||
|
function, derivvar().
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt><a name="1"><b class='cmd'>use automatic_differentiation</b> </a><dd>
|
||||||
|
|
||||||
|
The name of the module
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt><a name="2"><b class='cmd'>type(AUTODERIV)</b> </a><dd>
|
||||||
|
|
||||||
|
The type has two fields:
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>real(wp) <i class='arg'>v</i><dd>
|
||||||
|
The value of the variable/function (or any intermediate result)
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>real(wp) <i class='arg'>dv</i><dd>
|
||||||
|
The first derivative
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="3"><b class='cmd'>x = derivvar( value )</b> </a><dd>
|
||||||
|
|
||||||
|
Use this function to properly initialise the program
|
||||||
|
variable x as a "mathematical" variable. (It sets the derivative
|
||||||
|
of x to 1, because otherwise it would be regarded as a constant).
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>real(wp) <i class='arg'>value</i><dd>
|
||||||
|
The value of the "mathematical" variable.
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<dt><a name="4"><b class='cmd'>call find_root( f, xinit, tolerance, root, found )</b> </a><dd>
|
||||||
|
|
||||||
|
This subroutine is a simple implementation of the Newton-Raphson
|
||||||
|
method to find roots. The function f takes one argument, x.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
<dt>type(AUTODERIV) function <i class='arg'>f(x)</i><dd>
|
||||||
|
The function must have the interface:
|
||||||
|
<p><table><tr><td bgcolor=black> </td><td><pre class='sample'>
|
||||||
|
interface
|
||||||
|
function f(x)
|
||||||
|
use automatic_differentiation_type
|
||||||
|
type(AUTODERIV), intent(in) :: x
|
||||||
|
type(AUTODERIV) :: f
|
||||||
|
end function
|
||||||
|
end interface
|
||||||
|
</pre></td></tr></table></p>
|
||||||
|
|
||||||
|
Its return value is the function value at point x and its first
|
||||||
|
derivative.
|
||||||
|
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>type(AUTODERIV), intent(in) <i class='arg'>xinit</i><dd>
|
||||||
|
Initial estimate of the root - the end result may depend on this choice.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>real(wp) <i class='arg'>tolerance</i><dd>
|
||||||
|
Maximum allowable error in the absolute value of the root. If the
|
||||||
|
difference between the old and the new estimate is smaller than this
|
||||||
|
value, the iteration stops.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>type(AUTODERIV), intent(out) <i class='arg'>root</i><dd>
|
||||||
|
Final estimate of the root.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>logical <i class='arg'>found</i><dd>
|
||||||
|
Indicator whether a root was found or not. There is a maximum
|
||||||
|
number of iterations and the root must not grow too large.
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="5"><b class='cmd'>call find_root_iter( fvalue, root, tolerance, found )</b> </a><dd>
|
||||||
|
|
||||||
|
This subroutine performs a single iteration in the Newton-Raphson
|
||||||
|
method to find roots. It can be used to implement a more general version
|
||||||
|
of <em>find_root</em>, for instance if the interface to the function
|
||||||
|
contains one or more asjustable parameters.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
<dt>type(AUTODERIV) <i class='arg'>fvalue</i><dd>
|
||||||
|
The value of the function (plus its first derivative)
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>type(AUTODERIV), intent(in) <i class='arg'>root</i><dd>
|
||||||
|
Current estimate of the root
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>real(wp) <i class='arg'>tolerance</i><dd>
|
||||||
|
Maximum allowable error in the absolute value of the root. If the
|
||||||
|
difference between the old and the new estimate is smaller than this
|
||||||
|
value, the indicator <em>found</em> is set to true.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>logical <i class='arg'>found</i><dd>
|
||||||
|
Indicator whether a root was found or not.
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
<h2><a name="possible_extensions">POSSIBLE EXTENSIONS</a></h2>
|
||||||
|
<p>
|
||||||
|
You can extend the module in at least two ways:
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
Determine the second derivative, the third and so on. This is
|
||||||
|
straightforward enough, but the formulae will get fairly complex after
|
||||||
|
the second derivative.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
Determine the derivative of a function of two or more variables. This
|
||||||
|
will require a bit more: such functions have a vector-valued
|
||||||
|
derivative and each independent variable will have to have a
|
||||||
|
vector-valued derivative as well. For instance:
|
||||||
|
<br><br>
|
||||||
|
A function f(x,y) evaluated at (1,2), would take as the actual arguments
|
||||||
|
x = (1,1,0) (so no variation in the second direction) and y = (2,0,1)
|
||||||
|
(no variation in the first direction).
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2><a name="copyright">COPYRIGHT</a></h2>
|
||||||
|
<p>
|
||||||
|
Copyright © 2006 Arjen Markus <arjenmarkus@sourceforge.net><br>
|
||||||
|
</body></html>
|
||||||
|
|
||||||
203
flibs-0.9/flibs/doc/computing/automdiff.man
Normal file
203
flibs-0.9/flibs/doc/computing/automdiff.man
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
[comment {-*- flibs -*- doctools manpage}]
|
||||||
|
[manpage_begin automatic_differentiation n 1.0]
|
||||||
|
[copyright {2006 Arjen Markus <arjenmarkus@sourceforge.net>}]
|
||||||
|
[moddesc flibs]
|
||||||
|
[titledesc {Implement the "automatic differentation" technique}]
|
||||||
|
|
||||||
|
[description]
|
||||||
|
|
||||||
|
The [strong automatic_differentiation] module defines a derived
|
||||||
|
type that enables you (via overloading common mathematical
|
||||||
|
functions and operators) to:
|
||||||
|
|
||||||
|
[list_begin bullet]
|
||||||
|
[bullet]
|
||||||
|
Define a mathematical function in the usual way
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
Evaluate that function [strong and] its first derivative at the same
|
||||||
|
time
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
without having to program that first derivative.
|
||||||
|
|
||||||
|
[para]
|
||||||
|
|
||||||
|
The module uses real numbers of the kind "wp" as defined in the
|
||||||
|
auxiliary module [strong select_precision].
|
||||||
|
|
||||||
|
[para]
|
||||||
|
|
||||||
|
(I was pointed to this technique by Simon Geard, a couple of years ago,
|
||||||
|
in the context of one of the many language shootouts on the Internet.)
|
||||||
|
|
||||||
|
|
||||||
|
[section "EXAMPLE"]
|
||||||
|
|
||||||
|
In numerical methods like Newton-Raphson for finding a root of the
|
||||||
|
equation "f(x) = 0", you need the first derivative:
|
||||||
|
|
||||||
|
[example {
|
||||||
|
x(k+1) = x(k) - f(x(k)) / f'(x(k))
|
||||||
|
}]
|
||||||
|
|
||||||
|
Rather than implementing the function and its first derivatives as
|
||||||
|
separate functions, using this module you can dispense with manually
|
||||||
|
determining the first derivative:
|
||||||
|
|
||||||
|
[example {
|
||||||
|
program root
|
||||||
|
use automatic_differentation
|
||||||
|
|
||||||
|
type(AUTODERIV) :: x
|
||||||
|
type(AUTODERIV) :: res
|
||||||
|
integer :: i
|
||||||
|
|
||||||
|
!
|
||||||
|
! First estimate
|
||||||
|
!
|
||||||
|
x = derivvar( 1.0_wp )
|
||||||
|
|
||||||
|
do i = 1,10
|
||||||
|
res = f(x)
|
||||||
|
x = x - res.v / res.dv
|
||||||
|
enddo
|
||||||
|
|
||||||
|
write(*,*) 'Root: ', x.v
|
||||||
|
contains
|
||||||
|
|
||||||
|
type(AUTODERIV) function f(x)
|
||||||
|
type(AUTODERIV) :: x
|
||||||
|
|
||||||
|
f = x + cos(x)
|
||||||
|
|
||||||
|
end function f
|
||||||
|
end program
|
||||||
|
}]
|
||||||
|
|
||||||
|
|
||||||
|
[section "DATA TYPES AND ROUTINES"]
|
||||||
|
The module defines a single data type, AUTODERIV, and one specific
|
||||||
|
function, derivvar().
|
||||||
|
|
||||||
|
[list_begin definitions]
|
||||||
|
|
||||||
|
[call [cmd "use automatic_differentiation"]]
|
||||||
|
The name of the module
|
||||||
|
|
||||||
|
[call [cmd "type(AUTODERIV)"]]
|
||||||
|
The type has two fields:
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "real(wp)" v]
|
||||||
|
The value of the variable/function (or any intermediate result)
|
||||||
|
|
||||||
|
[arg_def "real(wp)" dv]
|
||||||
|
The first derivative
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "x = derivvar( value )"]]
|
||||||
|
Use this function to properly initialise the program
|
||||||
|
variable x as a "mathematical" variable. (It sets the derivative
|
||||||
|
of x to 1, because otherwise it would be regarded as a constant).
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "real(wp)" value]
|
||||||
|
The value of the "mathematical" variable.
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
[call [cmd "call find_root( f, xinit, tolerance, root, found )"]]
|
||||||
|
This subroutine is a simple implementation of the Newton-Raphson
|
||||||
|
method to find roots. The function f takes one argument, x.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
[arg_def "type(AUTODERIV) function" f(x)]
|
||||||
|
The function must have the interface:
|
||||||
|
[example {
|
||||||
|
interface
|
||||||
|
function f(x)
|
||||||
|
use automatic_differentiation_type
|
||||||
|
type(AUTODERIV), intent(in) :: x
|
||||||
|
type(AUTODERIV) :: f
|
||||||
|
end function
|
||||||
|
end interface
|
||||||
|
}]
|
||||||
|
|
||||||
|
Its return value is the function value at point x and its first
|
||||||
|
derivative.
|
||||||
|
|
||||||
|
|
||||||
|
[arg_def "type(AUTODERIV), intent(in)" xinit]
|
||||||
|
Initial estimate of the root - the end result may depend on this choice.
|
||||||
|
|
||||||
|
[arg_def "real(wp)" tolerance]
|
||||||
|
Maximum allowable error in the absolute value of the root. If the
|
||||||
|
difference between the old and the new estimate is smaller than this
|
||||||
|
value, the iteration stops.
|
||||||
|
|
||||||
|
[arg_def "type(AUTODERIV), intent(out)" root]
|
||||||
|
Final estimate of the root.
|
||||||
|
|
||||||
|
[arg_def "logical" found]
|
||||||
|
Indicator whether a root was found or not. There is a maximum
|
||||||
|
number of iterations and the root must not grow too large.
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call find_root_iter( fvalue, root, tolerance, found )"]]
|
||||||
|
This subroutine performs a single iteration in the Newton-Raphson
|
||||||
|
method to find roots. It can be used to implement a more general version
|
||||||
|
of [strong find_root], for instance if the interface to the function
|
||||||
|
contains one or more asjustable parameters.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
[arg_def "type(AUTODERIV)" fvalue]
|
||||||
|
The value of the function (plus its first derivative)
|
||||||
|
|
||||||
|
[arg_def "type(AUTODERIV), intent(in)" root]
|
||||||
|
Current estimate of the root
|
||||||
|
|
||||||
|
[arg_def "real(wp)" tolerance]
|
||||||
|
Maximum allowable error in the absolute value of the root. If the
|
||||||
|
difference between the old and the new estimate is smaller than this
|
||||||
|
value, the indicator [strong found] is set to true.
|
||||||
|
|
||||||
|
[arg_def "logical" found]
|
||||||
|
Indicator whether a root was found or not.
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[section "POSSIBLE EXTENSIONS"]
|
||||||
|
You can extend the module in at least two ways:
|
||||||
|
|
||||||
|
[list_begin bullet]
|
||||||
|
[bullet]
|
||||||
|
Determine the second derivative, the third and so on. This is
|
||||||
|
straightforward enough, but the formulae will get fairly complex after
|
||||||
|
the second derivative.
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
Determine the derivative of a function of two or more variables. This
|
||||||
|
will require a bit more: such functions have a vector-valued
|
||||||
|
derivative and each independent variable will have to have a
|
||||||
|
vector-valued derivative as well. For instance:
|
||||||
|
[nl]
|
||||||
|
A function f(x,y) evaluated at (1,2), would take as the actual arguments
|
||||||
|
x = (1,1,0) (so no variation in the second direction) and y = (2,0,1)
|
||||||
|
(no variation in the first direction).
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
[manpage_end]
|
||||||
210
flibs-0.9/flibs/doc/computing/backtrack.html
Normal file
210
flibs-0.9/flibs/doc/computing/backtrack.html
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
<! -- -*- flibs -*- doctools manpage
|
||||||
|
-->
|
||||||
|
<html><head>
|
||||||
|
<title>flibs/backtracking - flibs </title>
|
||||||
|
</head>
|
||||||
|
<! -- Generated from file 'backtrack.man' by tcllib/doctools with format 'html'
|
||||||
|
-->
|
||||||
|
<! -- Copyright © 2006 Arjen Markus <arjenmarkus@sourceforge.net>
|
||||||
|
-->
|
||||||
|
<! -- CVS: $Id: backtrack.html,v 1.1 2008/09/09 04:29:30 arjenmarkus Exp $ flibs/backtracking.n
|
||||||
|
-->
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1> flibs/backtracking(n) 1.1 "flibs"</h1>
|
||||||
|
<h2><a name="name">NAME</a></h2>
|
||||||
|
<p>
|
||||||
|
<p> flibs/backtracking - Backtracking
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h2><a name="table_of_contents">TABLE OF CONTENTS</a></h2>
|
||||||
|
<p> <a href="#table_of_contents">TABLE OF CONTENTS</a><br>
|
||||||
|
<a href="#synopsis">SYNOPSIS</a><br>
|
||||||
|
<a href="#description">DESCRIPTION</a><br>
|
||||||
|
<a href="#routines">ROUTINES</a><br>
|
||||||
|
<a href="#todo">TODO</a><br>
|
||||||
|
<a href="#copyright">COPYRIGHT</a><br>
|
||||||
|
<h2><a name="synopsis">SYNOPSIS</a></h2>
|
||||||
|
<p>
|
||||||
|
<table border=1 width=100% cellspacing=0 cellpadding=0><tr bgcolor=lightyellow><td bgcolor=lightyellow><table 0 width=100% cellspacing=0 cellpadding=0><tr valign=top ><td ><a href="#1"><b class='cmd'>call runtests( testproc )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#2"><b class='cmd'>call test( proc, text )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#3"><b class='cmd'>call assert_true( cond, text )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#4"><b class='cmd'>exists = funit_file_exists( filename )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#5"><b class='cmd'>call funit_get_lun( lun )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#6"><b class='cmd'>call funit_remove_file( filename )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#7"><b class='cmd'>call funit_make_empty_file( filename )</b> </a></td></tr>
|
||||||
|
</table></td></tr></table>
|
||||||
|
<h2><a name="description">DESCRIPTION</a></h2>
|
||||||
|
<p>
|
||||||
|
|
||||||
|
The module <em>Backtracking</em> implements in a general way a well-known
|
||||||
|
algorithm to solve certain combinatorial problems. The module actually
|
||||||
|
consists of a single routine that forms the framework of the algorithm
|
||||||
|
and is to be used in conjunction with a small set of user-defined
|
||||||
|
routines that implement the specific problem.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The backtracking technique is especially useful if you can build a
|
||||||
|
solution in stages. The classic example is the "eight queens" problem,
|
||||||
|
where you must place eight queens on a chess board in such a way that
|
||||||
|
none can get another in one move. A little thought shows that
|
||||||
|
each queen must be placed in its own column (or row). Placing the first
|
||||||
|
queen in the first column gives us eight possibilities. Placing the
|
||||||
|
second is only possible if it is not within the range of the first one.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
If it is, it makes no sense to continue so we can eliminate in the
|
||||||
|
second step a whole subset of possible configurations, namely those with
|
||||||
|
the second queeen within range of the first.
|
||||||
|
We can continue building up a partial solution in this way until we
|
||||||
|
finally have eight queens on the board.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The idea of the module is that all the data that describe a possible
|
||||||
|
partial solution to the problem are contained in a derived type called
|
||||||
|
SOLUTION_DATA. Then the user-defined routine <em>generate</em> generates
|
||||||
|
a new set of partial solutions based on this.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The new set is examined to see if any is acceptable within the context
|
||||||
|
of the problem, which is done via another user-defined routine.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Each acceptable solution within this new step may give rise to its own
|
||||||
|
set of further solutions. This way the partial solutions are extended in
|
||||||
|
each step until finally a complete solution is found.
|
||||||
|
|
||||||
|
<h2><a name="routines">ROUTINES</a></h2>
|
||||||
|
<p>
|
||||||
|
The module backtracking contains
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt><a name="1"><b class='cmd'>call runtests( testproc )</b> </a><dd>
|
||||||
|
|
||||||
|
Routine to start the unit tests. It checks if the file "funit.run"
|
||||||
|
exists. If so, it will call the subroutine <em>testproc</em> that was
|
||||||
|
passed. Otherwise it will simply return, so that the ordinary program
|
||||||
|
execution may continue.
|
||||||
|
<br><br>
|
||||||
|
If the subroutine testproc returns, the program stops.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
<dt>subroutine <i class='arg'>testproc</i><dd>
|
||||||
|
Subroutine that calls the individual test routines. It takes no
|
||||||
|
arguments. It wil generally exist of a series of calls to the
|
||||||
|
routine <em>test</em> - see below.
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="2"><b class='cmd'>call test( proc, text )</b> </a><dd>
|
||||||
|
|
||||||
|
Routine to run the individual unit test routine (emph proc). It decides
|
||||||
|
if the test has not run yet and if so, the test routine is called.
|
||||||
|
Otherwise it is skipped.
|
||||||
|
<br><br>
|
||||||
|
<em>test</em> takes care of all administrative details.
|
||||||
|
<br><br>
|
||||||
|
Note: to make it possible to use <em>private</em> unit test routines,
|
||||||
|
the source code of this subroutine is kept in a separate file,
|
||||||
|
<em>funit_test.f90</em> that should be included in an appropriate
|
||||||
|
place in the program's sources. This way, you can make it a private
|
||||||
|
routine in each module. The only public access to the unit testing
|
||||||
|
routines is then via the subroutine <em>testproc</em> that is passed to
|
||||||
|
<em>runtests</em>.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
<dt>subroutine <i class='arg'>proc</i><dd>
|
||||||
|
Subroutine that implements an individual unit test. It takes no
|
||||||
|
arguments. Within each such subroutine the complete unit test is run.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>character(len=*), intent(in) <i class='arg'>text</i><dd>
|
||||||
|
Text describing the particular unit test. It is printed in the log
|
||||||
|
file.
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="3"><b class='cmd'>call assert_true( cond, text )</b> </a><dd>
|
||||||
|
|
||||||
|
Routine to check that a condition is true. If not, a message is printed
|
||||||
|
in the log file and the number of failures is increased.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
<dt>logical <i class='arg'>cond</i><dd>
|
||||||
|
The condition to be checked
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>character(len=*), intent(in) <i class='arg'>text</i><dd>
|
||||||
|
Text describing the condition
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="4"><b class='cmd'>exists = funit_file_exists( filename )</b> </a><dd>
|
||||||
|
|
||||||
|
Logical function to check that a particular file exists
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
<dt>character(len=*), intent(in) <i class='arg'>filename</i><dd>
|
||||||
|
Name of the file to be checked
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="5"><b class='cmd'>call funit_get_lun( lun )</b> </a><dd>
|
||||||
|
|
||||||
|
Subroutine to get a free LU-number
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
<dt>integer, intent(out) <i class='arg'>lun</i><dd>
|
||||||
|
Next free LU-number
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="6"><b class='cmd'>call funit_remove_file( filename )</b> </a><dd>
|
||||||
|
|
||||||
|
Subroutine to remove (delete) a file
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
<dt>character(len=*), intent(in) <i class='arg'>filename</i><dd>
|
||||||
|
Name of the file to be removed
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="7"><b class='cmd'>call funit_make_empty_file( filename )</b> </a><dd>
|
||||||
|
|
||||||
|
Subroutine to make a new, empty file
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
<dt>character(len=*), intent(in) <i class='arg'>filename</i><dd>
|
||||||
|
Name of the file to be created
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
<h2><a name="todo">TODO</a></h2>
|
||||||
|
<p>
|
||||||
|
The following things are still left to do:
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
Proper inclusion of the routine <em>prolog</em> and <em>epilog</em>
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
Extension of the set of assertion routines
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
<h2><a name="copyright">COPYRIGHT</a></h2>
|
||||||
|
<p>
|
||||||
|
Copyright © 2006 Arjen Markus <arjenmarkus@sourceforge.net><br>
|
||||||
|
</body></html>
|
||||||
|
|
||||||
154
flibs-0.9/flibs/doc/computing/backtrack.man
Normal file
154
flibs-0.9/flibs/doc/computing/backtrack.man
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
[comment {-*- flibs -*- doctools manpage}]
|
||||||
|
[manpage_begin flibs/backtracking n 1.1]
|
||||||
|
[copyright {2006 Arjen Markus <arjenmarkus@sourceforge.net>}]
|
||||||
|
[moddesc flibs]
|
||||||
|
[titledesc {Backtracking}]
|
||||||
|
|
||||||
|
[description]
|
||||||
|
|
||||||
|
The module [emph Backtracking] implements in a general way a well-known
|
||||||
|
algorithm to solve certain combinatorial problems. The module actually
|
||||||
|
consists of a single routine that forms the framework of the algorithm
|
||||||
|
and is to be used in conjunction with a small set of user-defined
|
||||||
|
routines that implement the specific problem.
|
||||||
|
|
||||||
|
[para]
|
||||||
|
The backtracking technique is especially useful if you can build a
|
||||||
|
solution in stages. The classic example is the "eight queens" problem,
|
||||||
|
where you must place eight queens on a chess board in such a way that
|
||||||
|
none can get another in one move. A little thought shows that
|
||||||
|
each queen must be placed in its own column (or row). Placing the first
|
||||||
|
queen in the first column gives us eight possibilities. Placing the
|
||||||
|
second is only possible if it is not within the range of the first one.
|
||||||
|
|
||||||
|
[para]
|
||||||
|
If it is, it makes no sense to continue so we can eliminate in the
|
||||||
|
second step a whole subset of possible configurations, namely those with
|
||||||
|
the second queeen within range of the first.
|
||||||
|
We can continue building up a partial solution in this way until we
|
||||||
|
finally have eight queens on the board.
|
||||||
|
|
||||||
|
[para]
|
||||||
|
The idea of the module is that all the data that describe a possible
|
||||||
|
partial solution to the problem are contained in a derived type called
|
||||||
|
SOLUTION_DATA. Then the user-defined routine [emph generate] generates
|
||||||
|
a new set of partial solutions based on this.
|
||||||
|
|
||||||
|
[para]
|
||||||
|
The new set is examined to see if any is acceptable within the context
|
||||||
|
of the problem, which is done via another user-defined routine.
|
||||||
|
|
||||||
|
[para]
|
||||||
|
Each acceptable solution within this new step may give rise to its own
|
||||||
|
set of further solutions. This way the partial solutions are extended in
|
||||||
|
each step until finally a complete solution is found.
|
||||||
|
|
||||||
|
[section ROUTINES]
|
||||||
|
The module backtracking contains
|
||||||
|
|
||||||
|
[list_begin definitions]
|
||||||
|
|
||||||
|
[call [cmd "call runtests( testproc )"]]
|
||||||
|
Routine to start the unit tests. It checks if the file "funit.run"
|
||||||
|
exists. If so, it will call the subroutine [emph testproc] that was
|
||||||
|
passed. Otherwise it will simply return, so that the ordinary program
|
||||||
|
execution may continue.
|
||||||
|
[nl]
|
||||||
|
If the subroutine testproc returns, the program stops.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
[arg_def "subroutine" testproc]
|
||||||
|
Subroutine that calls the individual test routines. It takes no
|
||||||
|
arguments. It wil generally exist of a series of calls to the
|
||||||
|
routine [emph test] - see below.
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call test( proc, text )"]]
|
||||||
|
Routine to run the individual unit test routine (emph proc). It decides
|
||||||
|
if the test has not run yet and if so, the test routine is called.
|
||||||
|
Otherwise it is skipped.
|
||||||
|
[nl]
|
||||||
|
[emph test] takes care of all administrative details.
|
||||||
|
[nl]
|
||||||
|
Note: to make it possible to use [emph private] unit test routines,
|
||||||
|
the source code of this subroutine is kept in a separate file,
|
||||||
|
[emph funit_test.f90] that should be included in an appropriate
|
||||||
|
place in the program's sources. This way, you can make it a private
|
||||||
|
routine in each module. The only public access to the unit testing
|
||||||
|
routines is then via the subroutine [emph testproc] that is passed to
|
||||||
|
[emph runtests].
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
[arg_def "subroutine" proc]
|
||||||
|
Subroutine that implements an individual unit test. It takes no
|
||||||
|
arguments. Within each such subroutine the complete unit test is run.
|
||||||
|
|
||||||
|
[arg_def "character(len=*), intent(in)" text]
|
||||||
|
Text describing the particular unit test. It is printed in the log
|
||||||
|
file.
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call assert_true( cond, text )"]]
|
||||||
|
Routine to check that a condition is true. If not, a message is printed
|
||||||
|
in the log file and the number of failures is increased.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
[arg_def "logical" cond]
|
||||||
|
The condition to be checked
|
||||||
|
|
||||||
|
[arg_def "character(len=*), intent(in)" text]
|
||||||
|
Text describing the condition
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "exists = funit_file_exists( filename )"]]
|
||||||
|
Logical function to check that a particular file exists
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
[arg_def "character(len=*), intent(in)" filename]
|
||||||
|
Name of the file to be checked
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call funit_get_lun( lun )"]]
|
||||||
|
Subroutine to get a free LU-number
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
[arg_def "integer, intent(out)" lun]
|
||||||
|
Next free LU-number
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call funit_remove_file( filename )"]]
|
||||||
|
Subroutine to remove (delete) a file
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
[arg_def "character(len=*), intent(in)" filename]
|
||||||
|
Name of the file to be removed
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call funit_make_empty_file( filename )"]]
|
||||||
|
Subroutine to make a new, empty file
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
[arg_def "character(len=*), intent(in)" filename]
|
||||||
|
Name of the file to be created
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[section TODO]
|
||||||
|
The following things are still left to do:
|
||||||
|
[list_begin bullet]
|
||||||
|
[bullet]
|
||||||
|
Proper inclusion of the routine [emph prolog] and [emph epilog]
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
Extension of the set of assertion routines
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[manpage_end]
|
||||||
384
flibs-0.9/flibs/doc/computing/libdate.html
Normal file
384
flibs-0.9/flibs/doc/computing/libdate.html
Normal file
@@ -0,0 +1,384 @@
|
|||||||
|
<! -- -*- flibs -*- doctools manpage
|
||||||
|
-->
|
||||||
|
<html><head>
|
||||||
|
<title>libdate - flibs </title>
|
||||||
|
</head>
|
||||||
|
<! -- Generated from file 'libdate.man' by tcllib/doctools with format 'html'
|
||||||
|
-->
|
||||||
|
<! -- Copyright © 2008 Arjan van Dijk <arjan dot van dijk at rivm dot nl> -- Copyright © 2008 Arjen Markus <arjenmarkus at sourceforge dot net>
|
||||||
|
-->
|
||||||
|
<! -- CVS: $Id: libdate.html,v 1.1 2008/10/02 09:02:33 arjenmarkus Exp $ libdate.n
|
||||||
|
-->
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1> libdate(n) 1.0 "flibs"</h1>
|
||||||
|
<h2><a name="name">NAME</a></h2>
|
||||||
|
<p>
|
||||||
|
<p> libdate - Manipulating date/time information
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h2><a name="table_of_contents">TABLE OF CONTENTS</a></h2>
|
||||||
|
<p> <a href="#table_of_contents">TABLE OF CONTENTS</a><br>
|
||||||
|
<a href="#synopsis">SYNOPSIS</a><br>
|
||||||
|
<a href="#description">DESCRIPTION</a><br>
|
||||||
|
<a href="#derived_types_and_routines">DERIVED TYPES AND ROUTINES</a><br>
|
||||||
|
<a href="#acknowledgements">ACKNOWLEDGEMENTS</a><br>
|
||||||
|
<a href="#copyright">COPYRIGHT</a><br>
|
||||||
|
<h2><a name="synopsis">SYNOPSIS</a></h2>
|
||||||
|
<p>
|
||||||
|
<table border=1 width=100% cellspacing=0 cellpadding=0><tr bgcolor=lightyellow><td bgcolor=lightyellow><table 0 width=100% cellspacing=0 cellpadding=0><tr valign=top ><td ><a href="#1"><b class='cmd'>type(DATETYPE) date</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#2"><b class='cmd'>type(JULIANDATETYPE) julian</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#3"><b class='cmd'>relational operators</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#4"><b class='cmd'>newdate = basedate + timestep</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#5"><b class='cmd'>newdate = basedate - timestep</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#6"><b class='cmd'>newstep = factor * timestep</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#7"><b class='cmd'>newstep = timestep * factor</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#8"><b class='cmd'>timelag_in_days = timelag( date1, date2 )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#9"><b class='cmd'>seconds = delayseconds( timestep )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#10"><b class='cmd'>isleap = leapyear( date )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#11"><b class='cmd'>daynumber = doy( date )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#12"><b class='cmd'>earlier = mindate( date1, date2 )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#13"><b class='cmd'>later = maxdate( date1, date2 )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#14"><b class='cmd'>call format_date( date, pattern, datestring )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#15"><b class='cmd'>julian = date2julian( date )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#16"><b class='cmd'>date = julian2date( julian )</b> </a></td></tr>
|
||||||
|
</table></td></tr></table>
|
||||||
|
<h2><a name="description">DESCRIPTION</a></h2>
|
||||||
|
<p>
|
||||||
|
|
||||||
|
The <em>libdate</em> module defines a derived type and several functions
|
||||||
|
and subroutines to deal with date/time information:
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
Store date and time in the form of year, month, day, hour, minute
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
Compare dates
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
Basic arithmetic
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
Formatting date and time as a string based on a pattern
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<em>Note:</em> Timezones and seconds are <em>not</em> taken into account.
|
||||||
|
Also, there are no provisions to take care of the various historical
|
||||||
|
introductions of the Gregorian calendar.
|
||||||
|
|
||||||
|
|
||||||
|
<h2><a name="derived_types_and_routines">DERIVED TYPES AND ROUTINES</a></h2>
|
||||||
|
<p>
|
||||||
|
|
||||||
|
The module <em>libdate</em> defines two separate derived types, DATETYPE
|
||||||
|
and JULIANDATETYPE, though this second type is mainly meant for internal
|
||||||
|
use:
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt><a name="1"><b class='cmd'>type(DATETYPE) date</b> </a><dd>
|
||||||
|
|
||||||
|
This type has the following fields: year, month, day, hour, minute, in
|
||||||
|
that order, so that <em>thisdate = datetype( 2007, 1, 29, 17, 0)</em>
|
||||||
|
defines a date 29 january 2007 and a time 17:00.
|
||||||
|
<br><br>
|
||||||
|
A duration is expressed in days, hours and minutes:
|
||||||
|
<em>period = datetype( 0, 0, 2, 1, 0)</em> means a period of 2 days and
|
||||||
|
and 1 hour. (When adding a duration to a date/time the month and year
|
||||||
|
fields are ignored, as they are not additive).
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt><a name="2"><b class='cmd'>type(JULIANDATETYPE) julian</b> </a><dd>
|
||||||
|
|
||||||
|
Julian dates are used internally to make the computations easier. You
|
||||||
|
should not need to use them explicitly, unless you want to implement
|
||||||
|
new functionality.
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
The following functions, subroutines and operators are available:
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt><a name="3"><b class='cmd'>relational operators</b> </a><dd>
|
||||||
|
|
||||||
|
You can compare two dates using the standard operators
|
||||||
|
<em>.EQ.</em>, <em>.NE.</em>, <em>.GE.</em>, <em>.GT.</em>, <em>.LE.</em>,
|
||||||
|
<em>.LT.</em>, with conventional meaning
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt><a name="4"><b class='cmd'>newdate = basedate + timestep</b> </a><dd>
|
||||||
|
|
||||||
|
Add a duration to a date. The second date/time is considered to be the
|
||||||
|
duration.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(DATETYPE) <i class='arg'>basedate</i><dd>
|
||||||
|
The base date/time to which the duration is to be added.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>type(DATETYPE) <i class='arg'>timestep</i><dd>
|
||||||
|
The duration that will be added. Only the day, hour and minute fields
|
||||||
|
are considered.
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="5"><b class='cmd'>newdate = basedate - timestep</b> </a><dd>
|
||||||
|
|
||||||
|
Subtract a duration from a date. The second date/time is considered to
|
||||||
|
be the duration.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(DATETYPE) <i class='arg'>basedate</i><dd>
|
||||||
|
The base date/time from which the duration is to be subtracted.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>type(DATETYPE) <i class='arg'>timestep</i><dd>
|
||||||
|
The duration that will be subtracted. Only the day, hour and minute
|
||||||
|
fields are considered.
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="6"><b class='cmd'>newstep = factor * timestep</b> </a><dd>
|
||||||
|
|
||||||
|
Multiply a timestep by a real or integer factor. For the timestep,
|
||||||
|
only the day, hour and minute are considered.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>integer/real <i class='arg'>factor</i><dd>
|
||||||
|
Factor to be applied
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>type(DATETYPE) <i class='arg'>timestep</i><dd>
|
||||||
|
The duration that will be scaled.
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="7"><b class='cmd'>newstep = timestep * factor</b> </a><dd>
|
||||||
|
|
||||||
|
Multiply a timestep by a real or integer factor. For the timestep,
|
||||||
|
only the day, hour and minute are considered. (The order of teh
|
||||||
|
arguments is reversed).
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt><a name="8"><b class='cmd'>timelag_in_days = timelag( date1, date2 )</b> </a><dd>
|
||||||
|
|
||||||
|
Compute the time difference between two dates. Return the value in days.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(DATETYPE) <i class='arg'>date1</i><dd>
|
||||||
|
First date
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>type(DATETYPE) <i class='arg'>date2</i><dd>
|
||||||
|
Second date. If this date is earlier than the first date, the difference
|
||||||
|
is positive.
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="9"><b class='cmd'>seconds = delayseconds( timestep )</b> </a><dd>
|
||||||
|
|
||||||
|
Compute the number of seconds in a timestep
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(DATETYPE) <i class='arg'>timestep</i><dd>
|
||||||
|
Timestep to be converted to seconds
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="10"><b class='cmd'>isleap = leapyear( date )</b> </a><dd>
|
||||||
|
|
||||||
|
Determine if the year in the date structure is a leap year or not
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(DATETYPE) <i class='arg'>date</i><dd>
|
||||||
|
Date/time to be considered (only the year is of interest of course).
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="11"><b class='cmd'>daynumber = doy( date )</b> </a><dd>
|
||||||
|
|
||||||
|
Compute the day of the year
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(DATETYPE) <i class='arg'>date</i><dd>
|
||||||
|
Date/time to be considered.
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="12"><b class='cmd'>earlier = mindate( date1, date2 )</b> </a><dd>
|
||||||
|
|
||||||
|
Return the earlier of the two dates
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(DATETYPE) <i class='arg'>date1</i><dd>
|
||||||
|
First date/time to be considered.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>type(DATETYPE) <i class='arg'>date2</i><dd>
|
||||||
|
Second date/time to be considered.
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="13"><b class='cmd'>later = maxdate( date1, date2 )</b> </a><dd>
|
||||||
|
|
||||||
|
Return the later of the two dates
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(DATETYPE) <i class='arg'>date1</i><dd>
|
||||||
|
First date/time to be considered.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>type(DATETYPE) <i class='arg'>date2</i><dd>
|
||||||
|
Second date/time to be considered.
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="14"><b class='cmd'>call format_date( date, pattern, datestring )</b> </a><dd>
|
||||||
|
|
||||||
|
Format a date according to a pattern.
|
||||||
|
<br><br>
|
||||||
|
The pattern may contain any of the following format codes:
|
||||||
|
<br><br>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<em>dd</em> - Day of month ("01" for instance)
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
<em>ds</em> - Day of month ("1" for instance, s for space)
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
<em>DDD</em> - Day of the year
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
<em>HH</em> - Hour (00-23)
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
<em>HS</em> - Hour (0-23)
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
<em>mm</em> - Month ("01" for january)
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
<em>ms</em> - Month ("1" for january, s for space)
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
<em>MM</em> - Minutes within the hour (00-59)
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
<em>MS</em> - Minutes within the hour (0-59)
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
<em>YY</em> - Year with the century
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
<em>yyyy</em> - Year with the century
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(DATETYPE) <i class='arg'>date</i><dd>
|
||||||
|
Date to be converted
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>character(len=*) <i class='arg'>pattern</i><dd>
|
||||||
|
String containing the format pattern
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>character(len=*) <i class='arg'>datestring</i><dd>
|
||||||
|
String containing the result. The contents will not be longer
|
||||||
|
than the pattern.
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="15"><b class='cmd'>julian = date2julian( date )</b> </a><dd>
|
||||||
|
|
||||||
|
Convert a date/time structure to Julian date. Mainly for internal use.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(DATETYPE) <i class='arg'>date</i><dd>
|
||||||
|
Date/time structure to be converted.
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
<dt><a name="16"><b class='cmd'>date = julian2date( julian )</b> </a><dd>
|
||||||
|
|
||||||
|
Convert a Julian date to a date/time structure. Mainly for internal use.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(JULIANDATETYPE) <i class='arg'>julian</i><dd>
|
||||||
|
Julian date to be converted.
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
<h2><a name="acknowledgements">ACKNOWLEDGEMENTS</a></h2>
|
||||||
|
<p>
|
||||||
|
This module was written and contributed by Arjan van Dijk. Small
|
||||||
|
modifications and the addition of the <em>format_date</em> routine by
|
||||||
|
Arjen Markus.
|
||||||
|
|
||||||
|
<h2><a name="copyright">COPYRIGHT</a></h2>
|
||||||
|
<p>
|
||||||
|
Copyright © 2008 Arjan van Dijk <arjan dot van dijk at rivm dot nl><br>
|
||||||
|
Copyright © 2008 Arjen Markus <arjenmarkus at sourceforge dot net><br>
|
||||||
|
</body></html>
|
||||||
|
|
||||||
283
flibs-0.9/flibs/doc/computing/libdate.man
Normal file
283
flibs-0.9/flibs/doc/computing/libdate.man
Normal file
@@ -0,0 +1,283 @@
|
|||||||
|
[comment {-*- flibs -*- doctools manpage}]
|
||||||
|
[manpage_begin libdate n 1.0]
|
||||||
|
[copyright {2008 Arjan van Dijk <arjan dot van dijk at rivm dot nl>}]
|
||||||
|
[copyright {2008 Arjen Markus <arjenmarkus at sourceforge dot net>}]
|
||||||
|
[moddesc flibs]
|
||||||
|
[titledesc {Manipulating date/time information}]
|
||||||
|
|
||||||
|
[description]
|
||||||
|
|
||||||
|
The [term libdate] module defines a derived type and several functions
|
||||||
|
and subroutines to deal with date/time information:
|
||||||
|
|
||||||
|
[list_begin bullet]
|
||||||
|
[bullet]
|
||||||
|
Store date and time in the form of year, month, day, hour, minute
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
Compare dates
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
Basic arithmetic
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
Formatting date and time as a string based on a pattern
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
[strong Note:] Timezones and seconds are [strong not] taken into account.
|
||||||
|
Also, there are no provisions to take care of the various historical
|
||||||
|
introductions of the Gregorian calendar.
|
||||||
|
|
||||||
|
|
||||||
|
[section "DERIVED TYPES AND ROUTINES"]
|
||||||
|
|
||||||
|
The module [term libdate] defines two separate derived types, DATETYPE
|
||||||
|
and JULIANDATETYPE, though this second type is mainly meant for internal
|
||||||
|
use:
|
||||||
|
|
||||||
|
[list_begin definitions]
|
||||||
|
|
||||||
|
[call [cmd "type(DATETYPE) date"]]
|
||||||
|
This type has the following fields: year, month, day, hour, minute, in
|
||||||
|
that order, so that [term "thisdate = datetype( 2007, 1, 29, 17, 0)"]
|
||||||
|
defines a date 29 january 2007 and a time 17:00.
|
||||||
|
[nl]
|
||||||
|
A duration is expressed in days, hours and minutes:
|
||||||
|
[term "period = datetype( 0, 0, 2, 1, 0)"] means a period of 2 days and
|
||||||
|
and 1 hour. (When adding a duration to a date/time the month and year
|
||||||
|
fields are ignored, as they are not additive).
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
[call [cmd "type(JULIANDATETYPE) julian"]]
|
||||||
|
Julian dates are used internally to make the computations easier. You
|
||||||
|
should not need to use them explicitly, unless you want to implement
|
||||||
|
new functionality.
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
The following functions, subroutines and operators are available:
|
||||||
|
|
||||||
|
[list_begin definitions]
|
||||||
|
|
||||||
|
[call [cmd "relational operators"]]
|
||||||
|
You can compare two dates using the standard operators
|
||||||
|
[term .EQ.], [term .NE.], [term .GE.], [term .GT.], [term .LE.],
|
||||||
|
[term .LT.], with conventional meaning
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "newdate = basedate + timestep"]]
|
||||||
|
Add a duration to a date. The second date/time is considered to be the
|
||||||
|
duration.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(DATETYPE)" basedate]
|
||||||
|
The base date/time to which the duration is to be added.
|
||||||
|
|
||||||
|
[arg_def "type(DATETYPE)" timestep]
|
||||||
|
The duration that will be added. Only the day, hour and minute fields
|
||||||
|
are considered.
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "newdate = basedate - timestep"]]
|
||||||
|
Subtract a duration from a date. The second date/time is considered to
|
||||||
|
be the duration.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(DATETYPE)" basedate]
|
||||||
|
The base date/time from which the duration is to be subtracted.
|
||||||
|
|
||||||
|
[arg_def "type(DATETYPE)" timestep]
|
||||||
|
The duration that will be subtracted. Only the day, hour and minute
|
||||||
|
fields are considered.
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "newstep = factor * timestep"]]
|
||||||
|
Multiply a timestep by a real or integer factor. For the timestep,
|
||||||
|
only the day, hour and minute are considered.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "integer/real" factor]
|
||||||
|
Factor to be applied
|
||||||
|
|
||||||
|
[arg_def "type(DATETYPE)" timestep]
|
||||||
|
The duration that will be scaled.
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "newstep = timestep * factor"]]
|
||||||
|
Multiply a timestep by a real or integer factor. For the timestep,
|
||||||
|
only the day, hour and minute are considered. (The order of teh
|
||||||
|
arguments is reversed).
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "timelag_in_days = timelag( date1, date2 )"]]
|
||||||
|
Compute the time difference between two dates. Return the value in days.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(DATETYPE)" date1]
|
||||||
|
First date
|
||||||
|
|
||||||
|
[arg_def "type(DATETYPE)" date2]
|
||||||
|
Second date. If this date is earlier than the first date, the difference
|
||||||
|
is positive.
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "seconds = delayseconds( timestep )"]]
|
||||||
|
Compute the number of seconds in a timestep
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(DATETYPE)" timestep]
|
||||||
|
Timestep to be converted to seconds
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "isleap = leapyear( date )"]]
|
||||||
|
Determine if the year in the date structure is a leap year or not
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(DATETYPE)" date]
|
||||||
|
Date/time to be considered (only the year is of interest of course).
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "daynumber = doy( date )"]]
|
||||||
|
Compute the day of the year
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(DATETYPE)" date]
|
||||||
|
Date/time to be considered.
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "earlier = mindate( date1, date2 )"]]
|
||||||
|
Return the earlier of the two dates
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(DATETYPE)" date1]
|
||||||
|
First date/time to be considered.
|
||||||
|
|
||||||
|
[arg_def "type(DATETYPE)" date2]
|
||||||
|
Second date/time to be considered.
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "later = maxdate( date1, date2 )"]]
|
||||||
|
Return the later of the two dates
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(DATETYPE)" date1]
|
||||||
|
First date/time to be considered.
|
||||||
|
|
||||||
|
[arg_def "type(DATETYPE)" date2]
|
||||||
|
Second date/time to be considered.
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call format_date( date, pattern, datestring )"]]
|
||||||
|
Format a date according to a pattern.
|
||||||
|
[nl]
|
||||||
|
The pattern may contain any of the following format codes:
|
||||||
|
[list_begin bullet]
|
||||||
|
[bullet]
|
||||||
|
[term dd] - Day of month ("01" for instance)
|
||||||
|
[bullet]
|
||||||
|
[term ds] - Day of month ("1" for instance, s for space)
|
||||||
|
[bullet]
|
||||||
|
[term DDD] - Day of the year
|
||||||
|
[bullet]
|
||||||
|
[term HH] - Hour (00-23)
|
||||||
|
[bullet]
|
||||||
|
[term HS] - Hour (0-23)
|
||||||
|
[bullet]
|
||||||
|
[term mm] - Month ("01" for january)
|
||||||
|
[bullet]
|
||||||
|
[term ms] - Month ("1" for january, s for space)
|
||||||
|
[bullet]
|
||||||
|
[term MM] - Minutes within the hour (00-59)
|
||||||
|
[bullet]
|
||||||
|
[term MS] - Minutes within the hour (0-59)
|
||||||
|
[bullet]
|
||||||
|
[term YY] - Year with the century
|
||||||
|
[bullet]
|
||||||
|
[term yyyy] - Year with the century
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(DATETYPE)" date]
|
||||||
|
Date to be converted
|
||||||
|
|
||||||
|
[arg_def "character(len=*)" pattern]
|
||||||
|
String containing the format pattern
|
||||||
|
|
||||||
|
[arg_def "character(len=*)" datestring]
|
||||||
|
String containing the result. The contents will not be longer
|
||||||
|
than the pattern.
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "julian = date2julian( date )"]]
|
||||||
|
Convert a date/time structure to Julian date. Mainly for internal use.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(DATETYPE)" date]
|
||||||
|
Date/time structure to be converted.
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
[call [cmd "date = julian2date( julian )"]]
|
||||||
|
Convert a Julian date to a date/time structure. Mainly for internal use.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(JULIANDATETYPE)" julian]
|
||||||
|
Julian date to be converted.
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[section "ACKNOWLEDGEMENTS"]
|
||||||
|
This module was written and contributed by Arjan van Dijk. Small
|
||||||
|
modifications and the addition of the [term format_date] routine by
|
||||||
|
Arjen Markus.
|
||||||
|
|
||||||
|
[manpage_end]
|
||||||
60
flibs-0.9/flibs/doc/computing/select_precision.html
Normal file
60
flibs-0.9/flibs/doc/computing/select_precision.html
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
<! -- -*- flibs -*- doctools manpage
|
||||||
|
-->
|
||||||
|
<html><head>
|
||||||
|
<title>select_precision - flibs </title>
|
||||||
|
</head>
|
||||||
|
<! -- Generated from file 'select_precision.man' by tcllib/doctools with format 'html'
|
||||||
|
-->
|
||||||
|
<! -- Copyright © 2008 Arjen Markus <arjenmarkus@sourceforge.net>
|
||||||
|
-->
|
||||||
|
<! -- CVS: $Id: select_precision.html,v 1.1 2008/09/26 04:19:41 arjenmarkus Exp $ select_precision.n
|
||||||
|
-->
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1> select_precision(n) 1.0 "flibs"</h1>
|
||||||
|
<h2><a name="name">NAME</a></h2>
|
||||||
|
<p>
|
||||||
|
<p> select_precision - Select the precision for real variables
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h2><a name="table_of_contents">TABLE OF CONTENTS</a></h2>
|
||||||
|
<p> <a href="#table_of_contents">TABLE OF CONTENTS</a><br>
|
||||||
|
<a href="#description">DESCRIPTION</a><br>
|
||||||
|
<a href="#copyright">COPYRIGHT</a><br>
|
||||||
|
<h2><a name="description">DESCRIPTION</a></h2>
|
||||||
|
<p>
|
||||||
|
|
||||||
|
The auxiliary <em>select_precision</em> module defines three parameters
|
||||||
|
by which you can select the precision for real variables and constants:
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<em>sp</em> - Single precision
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
<em>dp</em> - Double precision (the real kind whose precision is larger
|
||||||
|
than that of single precision)
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
<em>wp</em> - Working precision. If you consistently use <em>wp</em> as the
|
||||||
|
kind for your real variables and constants, then switching between
|
||||||
|
single and double precision is merely a matter of setting <em>wp</em> to
|
||||||
|
either <em>sp</em> or <em>dp</em> in this module and recompiling.
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<em>Note:</em> One of the pitfalls in using double precision is that
|
||||||
|
literal constants, such as <em>1.2345678901234567890</em> are not
|
||||||
|
automatically interpreted as double precision. You need to specify the
|
||||||
|
kind explicitly: <em>1.2345678901234567890_wp</em> will define the
|
||||||
|
constant in the working precision.
|
||||||
|
|
||||||
|
<h2><a name="copyright">COPYRIGHT</a></h2>
|
||||||
|
<p>
|
||||||
|
Copyright © 2008 Arjen Markus <arjenmarkus@sourceforge.net><br>
|
||||||
|
</body></html>
|
||||||
|
|
||||||
34
flibs-0.9/flibs/doc/computing/select_precision.man
Normal file
34
flibs-0.9/flibs/doc/computing/select_precision.man
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
[comment {-*- flibs -*- doctools manpage}]
|
||||||
|
[manpage_begin select_precision n 1.0]
|
||||||
|
[copyright {2008 Arjen Markus <arjenmarkus@sourceforge.net>}]
|
||||||
|
[moddesc flibs]
|
||||||
|
[titledesc {Select the precision for real variables}]
|
||||||
|
|
||||||
|
[description]
|
||||||
|
|
||||||
|
The auxiliary [term select_precision] module defines three parameters
|
||||||
|
by which you can select the precision for real variables and constants:
|
||||||
|
|
||||||
|
[list_begin bullet]
|
||||||
|
[bullet]
|
||||||
|
[term sp] - Single precision
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
[term dp] - Double precision (the real kind whose precision is larger
|
||||||
|
than that of single precision)
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
[term wp] - Working precision. If you consistently use [term wp] as the
|
||||||
|
kind for your real variables and constants, then switching between
|
||||||
|
single and double precision is merely a matter of setting [term wp] to
|
||||||
|
either [term sp] or [term dp] in this module and recompiling.
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
[strong Note:] One of the pitfalls in using double precision is that
|
||||||
|
literal constants, such as [term 1.2345678901234567890] are not
|
||||||
|
automatically interpreted as double precision. You need to specify the
|
||||||
|
kind explicitly: [term 1.2345678901234567890_wp] will define the
|
||||||
|
constant in the working precision.
|
||||||
|
|
||||||
|
[manpage_end]
|
||||||
269
flibs-0.9/flibs/doc/controlstructures/finite_state.html
Normal file
269
flibs-0.9/flibs/doc/controlstructures/finite_state.html
Normal file
@@ -0,0 +1,269 @@
|
|||||||
|
|
||||||
|
<html><head>
|
||||||
|
<title>finite_state_machine - flibs </title>
|
||||||
|
</head>
|
||||||
|
<! -- Generated from file 'finite_state.man' by tcllib/doctools with format 'html'
|
||||||
|
-->
|
||||||
|
<! -- Copyright © 2006 Arjen Markus <arjenmarkus@sourceforge.net>
|
||||||
|
-->
|
||||||
|
<! -- CVS: $Id: finite_state.html,v 1.1 2008/06/13 10:31:48 relaxmike Exp $ finite_state_machine.n
|
||||||
|
-->
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1> finite_state_machine(n) 1.0 "flibs"</h1>
|
||||||
|
<h2><a name="name">NAME</a></h2>
|
||||||
|
<p>
|
||||||
|
<p> finite_state_machine - Support for building finite state machines
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h2><a name="table_of_contents">TABLE OF CONTENTS</a></h2>
|
||||||
|
<p> <a href="#table_of_contents">TABLE OF CONTENTS</a><br>
|
||||||
|
<a href="#synopsis">SYNOPSIS</a><br>
|
||||||
|
<a href="#description">DESCRIPTION</a><br>
|
||||||
|
<a href="#data_types_and_routines">DATA TYPES AND ROUTINES</a><br>
|
||||||
|
<a href="#example">EXAMPLE</a><br>
|
||||||
|
<a href="#copyright">COPYRIGHT</a><br>
|
||||||
|
<h2><a name="synopsis">SYNOPSIS</a></h2>
|
||||||
|
<p>
|
||||||
|
<table border=1 width=100% cellspacing=0 cellpadding=0><tr bgcolor=lightyellow><td bgcolor=lightyellow><table 0 width=100% cellspacing=0 cellpadding=0><tr valign=top ><td ><a href="#1"><b class='cmd'>call fsm_loop( data, machine )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#2"><b class='cmd'>call fsm_loop_int( data, machine )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#3"><b class='cmd'>call fsm_loop_print( data, machine, print_debug )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#4"><b class='cmd'>call fsm_loop_print_int( data, machine, print_debug )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#5"><b class='cmd'>call fsm_get_state( fsm, state )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#6"><b class='cmd'>call fsm_set_state( fsm, state )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#7"><b class='cmd'>call fsm_set_lurep( fsm, lurep )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#8"><b class='cmd'>lurep = fsm_get_lurep( fsm )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#9"><b class='cmd'>call fsm_finish( fsm )</b> </a></td></tr>
|
||||||
|
</table></td></tr></table>
|
||||||
|
<h2><a name="description">DESCRIPTION</a></h2>
|
||||||
|
<p>
|
||||||
|
|
||||||
|
The <em>finite_state.f90</em> source file defines a set of subroutines
|
||||||
|
that allow you to build a so-called finite state machine. This is
|
||||||
|
basically a way to structure a program or a part of a program that
|
||||||
|
takes input (from a file or from some other source) and reacts to
|
||||||
|
that input depending on the "state" it is in. A simple example could
|
||||||
|
be a heating device with a thermostat: if the ambient temperature is
|
||||||
|
high enough, there is no need to heat the room, so the system is in a
|
||||||
|
rest state. If the temperature is lower than the set temperature, the
|
||||||
|
heater should be turned on.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Finite state machines are encountered in many different areas in one
|
||||||
|
form or other. Lexical analysers are another, more complicated example.
|
||||||
|
When analysing an arithmetic expression like "1+2*3", the "+" that
|
||||||
|
follows the "1" will probably bring the analyser in a different state:
|
||||||
|
the literal number has terminated, it now needs to deal with an
|
||||||
|
operator. This type of programming is used in the test/demo program to
|
||||||
|
show how to use the finite_state.f90 source file to build a non-trivial
|
||||||
|
FSM.
|
||||||
|
|
||||||
|
<h2><a name="data_types_and_routines">DATA TYPES AND ROUTINES</a></h2>
|
||||||
|
<p>
|
||||||
|
The source code expects a data type, STATE_DATA, that contains all
|
||||||
|
information describing the finite state machine. The contents is
|
||||||
|
entirely up to the application though. The state data are passed to the
|
||||||
|
subroutine that implements the actual state machine, so that you can use
|
||||||
|
this argument to prepare the computation.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The type must be defined in a module called "fsm_data_definitions":
|
||||||
|
|
||||||
|
<p><table><tr><td bgcolor=black> </td><td><pre class='sample'>
|
||||||
|
module MYDATA_POOL
|
||||||
|
|
||||||
|
type POOLDATA
|
||||||
|
integer :: pool_index ! For private use by pool_acquire/pool_release
|
||||||
|
real, dimension(100) :: work ! The actual work space
|
||||||
|
end type
|
||||||
|
|
||||||
|
include "mem_pool.f90"
|
||||||
|
|
||||||
|
end module MYDATA_POOL
|
||||||
|
</pre></td></tr></table></p>
|
||||||
|
|
||||||
|
The code defines the following routines:
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt><a name="1"><b class='cmd'>call fsm_loop( data, machine )</b> </a><dd>
|
||||||
|
|
||||||
|
Run a finite state machine, implemented by the subroutine "machine" that
|
||||||
|
uses character strings to define the state. The first state is always
|
||||||
|
set to the parameter FSM_INIT_CHAR (="INIT"), the initial state, and should be
|
||||||
|
used to initialise the computation.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(STATE_DATA) <i class='arg'>data</i><dd>
|
||||||
|
The data defining the current state of the machine
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>subroutine <i class='arg'>machine</i><dd>
|
||||||
|
Subroutine that does the actual computation. Its interface is:
|
||||||
|
<p><table><tr><td bgcolor=black> </td><td><pre class='sample'>
|
||||||
|
subroutine machine( fsm, data, curstate )
|
||||||
|
use fsm_data_definitions
|
||||||
|
implicit none
|
||||||
|
type(FSM_STATE), intent(inout) :: fsm
|
||||||
|
type(STATE_DATA), intent(inout) :: data
|
||||||
|
character(len=*), intent(in) :: curstate
|
||||||
|
end subroutine</pre></td></tr></table></p>
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
<dt><a name="2"><b class='cmd'>call fsm_loop_int( data, machine )</b> </a><dd>
|
||||||
|
|
||||||
|
Similar to <em>fsm_loop</em> but the machine's state is an integer now.
|
||||||
|
The first state is represented by the parameter FSM_INIT (=0).
|
||||||
|
<br><br>
|
||||||
|
It has the same interface as <em>fsm_loop</em>
|
||||||
|
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt><a name="3"><b class='cmd'>call fsm_loop_print( data, machine, print_debug )</b> </a><dd>
|
||||||
|
|
||||||
|
Like <em>fsm_loop</em>, but the third argument is a routine that allows
|
||||||
|
you to print intermediate results. It's interface is:
|
||||||
|
<p><table><tr><td bgcolor=black> </td><td><pre class='sample'>
|
||||||
|
subroutine print_debug( lurep, data, oldstate, curstate )
|
||||||
|
use fsm_data_definitions
|
||||||
|
implicit none
|
||||||
|
integer, intent(in) :: lurep
|
||||||
|
type(STATE_DATA), intent(inout) :: data
|
||||||
|
character(len=*), intent(in) :: oldstate
|
||||||
|
character(len=*), intent(in) :: curstate
|
||||||
|
end subroutine</pre></td></tr></table></p>
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt><a name="4"><b class='cmd'>call fsm_loop_print_int( data, machine, print_debug )</b> </a><dd>
|
||||||
|
|
||||||
|
Like <em>fsm_loop_int</em>, but the third argument is a routine that
|
||||||
|
allows you to print intermediate results. It's interface is:
|
||||||
|
<p><table><tr><td bgcolor=black> </td><td><pre class='sample'>
|
||||||
|
subroutine print_debug( lurep, data, oldstate, curstate )
|
||||||
|
use fsm_data_definitions
|
||||||
|
implicit none
|
||||||
|
integer, intent(in) :: lurep
|
||||||
|
type(STATE_DATA), intent(inout) :: data
|
||||||
|
integer, intent(in) :: oldstate
|
||||||
|
integer, intent(in) :: curstate
|
||||||
|
end subroutine</pre></td></tr></table></p>
|
||||||
|
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt><a name="5"><b class='cmd'>call fsm_get_state( fsm, state )</b> </a><dd>
|
||||||
|
|
||||||
|
Get the current state from the FSM data structure
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(FSM_DATA) <i class='arg'>fsm</i><dd>
|
||||||
|
The data maintained by the FSM loop
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>integer/character(len=*), intent(out) <i class='arg'>state</i><dd>
|
||||||
|
Current state of the finite state machine - either as integer or as
|
||||||
|
character string.
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="6"><b class='cmd'>call fsm_set_state( fsm, state )</b> </a><dd>
|
||||||
|
|
||||||
|
Set the current state in the FSM data structure
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(FSM_DATA) <i class='arg'>fsm</i><dd>
|
||||||
|
The data maintained by the FSM loop
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>integer/character(len=*), intent(in) <i class='arg'>state</i><dd>
|
||||||
|
The new state of the finite state machine - either as integer or as
|
||||||
|
character string.
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="7"><b class='cmd'>call fsm_set_lurep( fsm, lurep )</b> </a><dd>
|
||||||
|
|
||||||
|
Set the LU-number for the print routine (by default: 0, to be
|
||||||
|
interpreted as output to screen).
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt><a name="8"><b class='cmd'>lurep = fsm_get_lurep( fsm )</b> </a><dd>
|
||||||
|
|
||||||
|
Return the LU-number for the print routine.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt><a name="9"><b class='cmd'>call fsm_finish( fsm )</b> </a><dd>
|
||||||
|
|
||||||
|
Instruct the FSM loop to stop.
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<h2><a name="example">EXAMPLE</a></h2>
|
||||||
|
<p>
|
||||||
|
The use of the source code in the two files "finite_state.f90"and
|
||||||
|
"fsm_state.f90" is illustrated by the following example:
|
||||||
|
|
||||||
|
<p><table><tr><td bgcolor=black> </td><td><pre class='sample'>
|
||||||
|
module fsm_data_definitions
|
||||||
|
implicit none
|
||||||
|
|
||||||
|
include 'fsm_state.f90'
|
||||||
|
|
||||||
|
type STATE_DATA
|
||||||
|
integer :: position ! Current position in the string
|
||||||
|
integer :: open_parens ! Number of open parentheses
|
||||||
|
character(len=80) :: string ! String holding the expression
|
||||||
|
end type STATE_DATA
|
||||||
|
|
||||||
|
end module fsm_data_definitions</pre></td></tr></table></p>
|
||||||
|
|
||||||
|
This module defines the STATE_DATA derived type and includes the file
|
||||||
|
with the (private) definitions.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The module that actually implements the finite state machine looks like
|
||||||
|
this (the included file "finite_state.f90"contains the <em>contains</em>
|
||||||
|
keyword):
|
||||||
|
|
||||||
|
<p><table><tr><td bgcolor=black> </td><td><pre class='sample'>
|
||||||
|
module analyse_string
|
||||||
|
use fsm_data_definitions
|
||||||
|
include 'finite_state.f90'
|
||||||
|
|
||||||
|
!
|
||||||
|
! Here is the actual routine that implements the finite state machine
|
||||||
|
!
|
||||||
|
! analyse_expression --
|
||||||
|
! Analyse an arithmetic expression
|
||||||
|
! Arguments:
|
||||||
|
! fsm Private data structure for the FSM machinery
|
||||||
|
! data Evaluation data structure
|
||||||
|
! state_name Current state of the machine
|
||||||
|
!
|
||||||
|
subroutine analyse_expression( fsm, data, state_name )
|
||||||
|
type(FSM_STATE), intent(inout) :: fsm
|
||||||
|
type(STATE_DATA), intent(inout) :: data
|
||||||
|
character(len=*), intent(in) :: state_name
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
end subroutine analyse_expression
|
||||||
|
|
||||||
|
end module</pre></td></tr></table></p>
|
||||||
|
|
||||||
|
(You can find the complete source code in the file
|
||||||
|
"tst_finite_state.f90" in the source distribution)
|
||||||
|
|
||||||
|
<h2><a name="copyright">COPYRIGHT</a></h2>
|
||||||
|
<p>
|
||||||
|
Copyright © 2006 Arjen Markus <arjenmarkus@sourceforge.net><br>
|
||||||
|
</body></html>
|
||||||
210
flibs-0.9/flibs/doc/controlstructures/finite_state.man
Normal file
210
flibs-0.9/flibs/doc/controlstructures/finite_state.man
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
[comment {-*- flibs -*- doctools manpage}]
|
||||||
|
[manpage_begin finite_state_machine n 1.0]
|
||||||
|
[copyright {2006 Arjen Markus <arjenmarkus@sourceforge.net>}]
|
||||||
|
[moddesc flibs]
|
||||||
|
[titledesc {Support for building finite state machines}]
|
||||||
|
|
||||||
|
[description]
|
||||||
|
|
||||||
|
The [strong finite_state.f90] source file defines a set of subroutines
|
||||||
|
that allow you to build a so-called finite state machine. This is
|
||||||
|
basically a way to structure a program or a part of a program that
|
||||||
|
takes input (from a file or from some other source) and reacts to
|
||||||
|
that input depending on the "state" it is in. A simple example could
|
||||||
|
be a heating device with a thermostat: if the ambient temperature is
|
||||||
|
high enough, there is no need to heat the room, so the system is in a
|
||||||
|
rest state. If the temperature is lower than the set temperature, the
|
||||||
|
heater should be turned on.
|
||||||
|
|
||||||
|
[para]
|
||||||
|
Finite state machines are encountered in many different areas in one
|
||||||
|
form or other. Lexical analysers are another, more complicated example.
|
||||||
|
When analysing an arithmetic expression like "1+2*3", the "+" that
|
||||||
|
follows the "1" will probably bring the analyser in a different state:
|
||||||
|
the literal number has terminated, it now needs to deal with an
|
||||||
|
operator. This type of programming is used in the test/demo program to
|
||||||
|
show how to use the finite_state.f90 source file to build a non-trivial
|
||||||
|
FSM.
|
||||||
|
|
||||||
|
[section "DATA TYPES AND ROUTINES"]
|
||||||
|
The source code expects a data type, STATE_DATA, that contains all
|
||||||
|
information describing the finite state machine. The contents is
|
||||||
|
entirely up to the application though. The state data are passed to the
|
||||||
|
subroutine that implements the actual state machine, so that you can use
|
||||||
|
this argument to prepare the computation.
|
||||||
|
|
||||||
|
[para]
|
||||||
|
The type must be defined in a module called "fsm_data_definitions":
|
||||||
|
|
||||||
|
[example {
|
||||||
|
module MYDATA_POOL
|
||||||
|
|
||||||
|
type POOLDATA
|
||||||
|
integer :: pool_index ! For private use by pool_acquire/pool_release
|
||||||
|
real, dimension(100) :: work ! The actual work space
|
||||||
|
end type
|
||||||
|
|
||||||
|
include "mem_pool.f90"
|
||||||
|
|
||||||
|
end module MYDATA_POOL
|
||||||
|
}]
|
||||||
|
|
||||||
|
The code defines the following routines:
|
||||||
|
|
||||||
|
[list_begin definitions]
|
||||||
|
|
||||||
|
[call [cmd "call fsm_loop( data, machine )"]]
|
||||||
|
Run a finite state machine, implemented by the subroutine "machine" that
|
||||||
|
uses character strings to define the state. The first state is always
|
||||||
|
set to the parameter FSM_INIT_CHAR (="INIT"), the initial state, and should be
|
||||||
|
used to initialise the computation.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(STATE_DATA)" data]
|
||||||
|
The data defining the current state of the machine
|
||||||
|
|
||||||
|
[arg_def "subroutine" machine]
|
||||||
|
Subroutine that does the actual computation. Its interface is:
|
||||||
|
[example {
|
||||||
|
subroutine machine( fsm, data, curstate )
|
||||||
|
use fsm_data_definitions
|
||||||
|
implicit none
|
||||||
|
type(FSM_STATE), intent(inout) :: fsm
|
||||||
|
type(STATE_DATA), intent(inout) :: data
|
||||||
|
character(len=*), intent(in) :: curstate
|
||||||
|
end subroutine}]
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
[call [cmd "call fsm_loop_int( data, machine )"]]
|
||||||
|
Similar to [emph fsm_loop] but the machine's state is an integer now.
|
||||||
|
The first state is represented by the parameter FSM_INIT (=0).
|
||||||
|
[nl]
|
||||||
|
It has the same interface as [emph fsm_loop]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call fsm_loop_print( data, machine, print_debug )"]]
|
||||||
|
Like [emph fsm_loop], but the third argument is a routine that allows
|
||||||
|
you to print intermediate results. It's interface is:
|
||||||
|
[example {
|
||||||
|
subroutine print_debug( lurep, data, oldstate, curstate )
|
||||||
|
use fsm_data_definitions
|
||||||
|
implicit none
|
||||||
|
integer, intent(in) :: lurep
|
||||||
|
type(STATE_DATA), intent(inout) :: data
|
||||||
|
character(len=*), intent(in) :: oldstate
|
||||||
|
character(len=*), intent(in) :: curstate
|
||||||
|
end subroutine}]
|
||||||
|
|
||||||
|
[call [cmd "call fsm_loop_print_int( data, machine, print_debug )"]]
|
||||||
|
Like [emph fsm_loop_int], but the third argument is a routine that
|
||||||
|
allows you to print intermediate results. It's interface is:
|
||||||
|
[example {
|
||||||
|
subroutine print_debug( lurep, data, oldstate, curstate )
|
||||||
|
use fsm_data_definitions
|
||||||
|
implicit none
|
||||||
|
integer, intent(in) :: lurep
|
||||||
|
type(STATE_DATA), intent(inout) :: data
|
||||||
|
integer, intent(in) :: oldstate
|
||||||
|
integer, intent(in) :: curstate
|
||||||
|
end subroutine}]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call fsm_get_state( fsm, state )"]]
|
||||||
|
Get the current state from the FSM data structure
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(FSM_DATA)" fsm]
|
||||||
|
The data maintained by the FSM loop
|
||||||
|
|
||||||
|
[arg_def "integer/character(len=*), intent(out)" state]
|
||||||
|
Current state of the finite state machine - either as integer or as
|
||||||
|
character string.
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call fsm_set_state( fsm, state )"]]
|
||||||
|
Set the current state in the FSM data structure
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(FSM_DATA)" fsm]
|
||||||
|
The data maintained by the FSM loop
|
||||||
|
|
||||||
|
[arg_def "integer/character(len=*), intent(in)" state]
|
||||||
|
The new state of the finite state machine - either as integer or as
|
||||||
|
character string.
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call fsm_set_lurep( fsm, lurep )"]]
|
||||||
|
Set the LU-number for the print routine (by default: 0, to be
|
||||||
|
interpreted as output to screen).
|
||||||
|
|
||||||
|
[call [cmd "lurep = fsm_get_lurep( fsm )"]]
|
||||||
|
Return the LU-number for the print routine.
|
||||||
|
|
||||||
|
[call [cmd "call fsm_finish( fsm )"]]
|
||||||
|
Instruct the FSM loop to stop.
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
[section "EXAMPLE"]
|
||||||
|
The use of the source code in the two files "finite_state.f90"and
|
||||||
|
"fsm_state.f90" is illustrated by the following example:
|
||||||
|
|
||||||
|
[example {
|
||||||
|
module fsm_data_definitions
|
||||||
|
implicit none
|
||||||
|
|
||||||
|
include 'fsm_state.f90'
|
||||||
|
|
||||||
|
type STATE_DATA
|
||||||
|
integer :: position ! Current position in the string
|
||||||
|
integer :: open_parens ! Number of open parentheses
|
||||||
|
character(len=80) :: string ! String holding the expression
|
||||||
|
end type STATE_DATA
|
||||||
|
|
||||||
|
end module fsm_data_definitions}]
|
||||||
|
|
||||||
|
This module defines the STATE_DATA derived type and includes the file
|
||||||
|
with the (private) definitions.
|
||||||
|
|
||||||
|
[para]
|
||||||
|
The module that actually implements the finite state machine looks like
|
||||||
|
this (the included file "finite_state.f90"contains the [emph contains]
|
||||||
|
keyword):
|
||||||
|
|
||||||
|
[example {
|
||||||
|
module analyse_string
|
||||||
|
use fsm_data_definitions
|
||||||
|
include 'finite_state.f90'
|
||||||
|
|
||||||
|
!
|
||||||
|
! Here is the actual routine that implements the finite state machine
|
||||||
|
!
|
||||||
|
! analyse_expression --
|
||||||
|
! Analyse an arithmetic expression
|
||||||
|
! Arguments:
|
||||||
|
! fsm Private data structure for the FSM machinery
|
||||||
|
! data Evaluation data structure
|
||||||
|
! state_name Current state of the machine
|
||||||
|
!
|
||||||
|
subroutine analyse_expression( fsm, data, state_name )
|
||||||
|
type(FSM_STATE), intent(inout) :: fsm
|
||||||
|
type(STATE_DATA), intent(inout) :: data
|
||||||
|
character(len=*), intent(in) :: state_name
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
end subroutine analyse_expression
|
||||||
|
|
||||||
|
end module}]
|
||||||
|
|
||||||
|
(You can find the complete source code in the file
|
||||||
|
"tst_finite_state.f90" in the source distribution)
|
||||||
|
|
||||||
|
[manpage_end]
|
||||||
185
flibs-0.9/flibs/doc/csv_file.html
Normal file
185
flibs-0.9/flibs/doc/csv_file.html
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
<! -- -*- flibs -*- doctools manpage
|
||||||
|
-->
|
||||||
|
<html><head>
|
||||||
|
<title>flibs/strings - flibs </title>
|
||||||
|
</head>
|
||||||
|
<! -- Generated from file 'csv_file.man' by tcllib/doctools with format 'html'
|
||||||
|
-->
|
||||||
|
<! -- Copyright © 2005 Arjen Markus <arjenmarkus@sourceforge.net>
|
||||||
|
-->
|
||||||
|
<! -- CVS: $Id$ flibs/strings.n
|
||||||
|
-->
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1> flibs/strings(n) 1.0 "flibs"</h1>
|
||||||
|
<h2><a name="name">NAME</a></h2>
|
||||||
|
<p>
|
||||||
|
<p> flibs/strings - Writing CSV files
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h2><a name="table_of_contents">TABLE OF CONTENTS</a></h2>
|
||||||
|
<p> <a href="#table_of_contents">TABLE OF CONTENTS</a><br>
|
||||||
|
<a href="#synopsis">SYNOPSIS</a><br>
|
||||||
|
<a href="#description">DESCRIPTION</a><br>
|
||||||
|
<a href="#routines">ROUTINES</a><br>
|
||||||
|
<a href="#copyright">COPYRIGHT</a><br>
|
||||||
|
<h2><a name="synopsis">SYNOPSIS</a></h2>
|
||||||
|
<p>
|
||||||
|
<table border=1 width=100% cellspacing=0 cellpadding=0><tr bgcolor=lightyellow><td bgcolor=lightyellow><table 0 width=100% cellspacing=0 cellpadding=0><tr valign=top ><td ><a href="#1"><b class='cmd'>use csv_file</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#2"><b class='cmd'>call csv_next_record( lun )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#3"><b class='cmd'>call csv_write( lun, data )</b> </a></td></tr>
|
||||||
|
</table></td></tr></table>
|
||||||
|
<h2><a name="description">DESCRIPTION</a></h2>
|
||||||
|
<p>
|
||||||
|
|
||||||
|
The <em>csv_file</em> module facilitates the writing of
|
||||||
|
CSV files. Whereas it is very easy to read CSV files with Fortran, using
|
||||||
|
list-directed read statements:
|
||||||
|
|
||||||
|
<p><table><tr><td bgcolor=black> </td><td><pre class='sample'>
|
||||||
|
integer :: i1, i2
|
||||||
|
character(len=20) :: string
|
||||||
|
real :: f3
|
||||||
|
read(10,*) i1, i2, string, f3
|
||||||
|
</pre></td></tr></table></p>
|
||||||
|
|
||||||
|
for instance, writing them is slightly more complicated. The module
|
||||||
|
helps with this by two routines, <em>csv_next_record</em> and
|
||||||
|
<em>csv_write</em>.
|
||||||
|
<p>
|
||||||
|
|
||||||
|
The module supports writing scalar variables, one- and two-dimensional
|
||||||
|
arrays according to a simple scheme. As CSV files are ordinary formatted
|
||||||
|
files where each field is separated by commas and strings are possibly
|
||||||
|
delimited by quotation marks ("), the procedure is this:
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
Open the file as a formatted file
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
Pass the LU-number for the file to the routines mentioned above,
|
||||||
|
using the second to write the data and the first to force a new record.
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
In more detail, the layout of the CSV-file can be described as follows:
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
Single items are written to the end of the current record
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
One-dimensional items are also written to the end of the current
|
||||||
|
record
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
Two-dimensional items are written to separate records, one for
|
||||||
|
each row
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
Except for the two-dimensional versions, all routines allow
|
||||||
|
you to suppress advancing to the next record:
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
for single items you must indicate whether to advance or not
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
for one-dimensional items, the argument is optional. Default
|
||||||
|
is to advance.
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<em>Note on the format:</em>
|
||||||
|
CSV-files apparently come in different guises (Kernighan and Pike,
|
||||||
|
The practice of Programming, Addison-Wesley, 1999). This module
|
||||||
|
uses the following rules:
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
items are always separated by a single comma (,)
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
string items are delimited by double quotes (")
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
embedded double quotes are treated by doubling the quote
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
trailing blanks are considered irrelevant
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
<h2><a name="routines">ROUTINES</a></h2>
|
||||||
|
<p>
|
||||||
|
The module contains two public subroutines:
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt><a name="1"><b class='cmd'>use csv_file</b> </a><dd>
|
||||||
|
|
||||||
|
To import the subroutines for writing a CSV file, use this module.
|
||||||
|
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt><a name="2"><b class='cmd'>call csv_next_record( lun )</b> </a><dd>
|
||||||
|
|
||||||
|
Writes a new line to the file.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>integer <i class='arg'>lun</i><dd>
|
||||||
|
The LU-number the file is connected to
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="3"><b class='cmd'>call csv_write( lun, data )</b> </a><dd>
|
||||||
|
|
||||||
|
Writes data to the file in the proper format.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>integer <i class='arg'>lun</i><dd>
|
||||||
|
The LU-number the file is connected to
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>(...) <i class='arg'>data</i><dd>
|
||||||
|
The data to be written to the file. The type can be:
|
||||||
|
<br><br>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
an integer or a real (single or double precision) number or a character
|
||||||
|
string
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
an integer or a real (single or double precision)one-dimensional array or a one-dimensional
|
||||||
|
array of character strings
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
an integer or a real (single or double precision)two-dimensional array or a two-dimensional
|
||||||
|
array of character strings
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<h2><a name="copyright">COPYRIGHT</a></h2>
|
||||||
|
<p>
|
||||||
|
Copyright © 2005 Arjen Markus <arjenmarkus@sourceforge.net><br>
|
||||||
|
</body></html>
|
||||||
|
|
||||||
133
flibs-0.9/flibs/doc/csv_file.man
Normal file
133
flibs-0.9/flibs/doc/csv_file.man
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
[comment {-*- flibs -*- doctools manpage}]
|
||||||
|
[manpage_begin flibs/strings n 1.0]
|
||||||
|
[copyright {2005 Arjen Markus <arjenmarkus@sourceforge.net>}]
|
||||||
|
[moddesc flibs]
|
||||||
|
[titledesc {Writing CSV files}]
|
||||||
|
|
||||||
|
[description]
|
||||||
|
|
||||||
|
The [strong csv_file] module facilitates the writing of
|
||||||
|
CSV files. Whereas it is very easy to read CSV files with Fortran, using
|
||||||
|
list-directed read statements:
|
||||||
|
|
||||||
|
[example {
|
||||||
|
integer :: i1, i2
|
||||||
|
character(len=20) :: string
|
||||||
|
real :: f3
|
||||||
|
read(10,*) i1, i2, string, f3
|
||||||
|
}]
|
||||||
|
|
||||||
|
for instance, writing them is slightly more complicated. The module
|
||||||
|
helps with this by two routines, [strong csv_next_record] and
|
||||||
|
[strong csv_write].
|
||||||
|
[para]
|
||||||
|
|
||||||
|
The module supports writing scalar variables, one- and two-dimensional
|
||||||
|
arrays according to a simple scheme. As CSV files are ordinary formatted
|
||||||
|
files where each field is separated by commas and strings are possibly
|
||||||
|
delimited by quotation marks ("), the procedure is this:
|
||||||
|
|
||||||
|
[list_begin bullet]
|
||||||
|
[bullet]
|
||||||
|
Open the file as a formatted file
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
Pass the LU-number for the file to the routines mentioned above,
|
||||||
|
using the second to write the data and the first to force a new record.
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
In more detail, the layout of the CSV-file can be described as follows:
|
||||||
|
|
||||||
|
[list_begin bullet]
|
||||||
|
[bullet]
|
||||||
|
Single items are written to the end of the current record
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
One-dimensional items are also written to the end of the current
|
||||||
|
record
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
Two-dimensional items are written to separate records, one for
|
||||||
|
each row
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
Except for the two-dimensional versions, all routines allow
|
||||||
|
you to suppress advancing to the next record:
|
||||||
|
|
||||||
|
[list_begin bullet]
|
||||||
|
[bullet]
|
||||||
|
for single items you must indicate whether to advance or not
|
||||||
|
[bullet]
|
||||||
|
for one-dimensional items, the argument is optional. Default
|
||||||
|
is to advance.
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
[strong "Note on the format:"]
|
||||||
|
CSV-files apparently come in different guises (Kernighan and Pike,
|
||||||
|
The practice of Programming, Addison-Wesley, 1999). This module
|
||||||
|
uses the following rules:
|
||||||
|
|
||||||
|
[list_begin bullet]
|
||||||
|
[bullet]
|
||||||
|
items are always separated by a single comma (,)
|
||||||
|
[bullet]
|
||||||
|
string items are delimited by double quotes (")
|
||||||
|
[bullet]
|
||||||
|
embedded double quotes are treated by doubling the quote
|
||||||
|
[bullet]
|
||||||
|
trailing blanks are considered irrelevant
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[section ROUTINES]
|
||||||
|
The module contains two public subroutines:
|
||||||
|
|
||||||
|
[list_begin definitions]
|
||||||
|
|
||||||
|
[call [cmd "use csv_file"]]
|
||||||
|
To import the subroutines for writing a CSV file, use this module.
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call csv_next_record( lun )"]]
|
||||||
|
Writes a new line to the file.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "integer" lun]
|
||||||
|
The LU-number the file is connected to
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call csv_write( lun, data )"]]
|
||||||
|
Writes data to the file in the proper format.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "integer" lun]
|
||||||
|
The LU-number the file is connected to
|
||||||
|
|
||||||
|
[arg_def "(...)" data]
|
||||||
|
The data to be written to the file. The type can be:
|
||||||
|
[list_begin bullet]
|
||||||
|
[bullet]
|
||||||
|
an integer or a real (single or double precision) number or a character
|
||||||
|
string
|
||||||
|
[bullet]
|
||||||
|
an integer or a real (single or double precision) one-dimensional array
|
||||||
|
or a one-dimensional array of character strings
|
||||||
|
[bullet]
|
||||||
|
an integer or a real (single or double precision) two-dimensional array
|
||||||
|
or a two-dimensional array of character strings
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
[manpage_end]
|
||||||
294
flibs-0.9/flibs/doc/datastructures/binarytree.html
Normal file
294
flibs-0.9/flibs/doc/datastructures/binarytree.html
Normal file
@@ -0,0 +1,294 @@
|
|||||||
|
|
||||||
|
<html><head>
|
||||||
|
<title>flibs/binarytree - flibs </title>
|
||||||
|
</head>
|
||||||
|
<! -- Generated from file 'binarytree.man' by tcllib/doctools with format 'html'
|
||||||
|
-->
|
||||||
|
<! -- Copyright © 2005 Arjen Markus <arjenmarkus@sourceforge.net>
|
||||||
|
-->
|
||||||
|
<! -- CVS: $Id: binarytree.html,v 1.1 2008/06/13 10:19:49 relaxmike Exp $ flibs/binarytree.n
|
||||||
|
-->
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1> flibs/binarytree(n) 1.0 "flibs"</h1>
|
||||||
|
<h2><a name="name">NAME</a></h2>
|
||||||
|
<p>
|
||||||
|
<p> flibs/binarytree - Linked lists
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h2><a name="table_of_contents">TABLE OF CONTENTS</a></h2>
|
||||||
|
<p> <a href="#table_of_contents">TABLE OF CONTENTS</a><br>
|
||||||
|
<a href="#synopsis">SYNOPSIS</a><br>
|
||||||
|
<a href="#description">DESCRIPTION</a><br>
|
||||||
|
<a href="#routines">ROUTINES</a><br>
|
||||||
|
<a href="#copyright">COPYRIGHT</a><br>
|
||||||
|
<h2><a name="synopsis">SYNOPSIS</a></h2>
|
||||||
|
<p>
|
||||||
|
<table border=1 width=100% cellspacing=0 cellpadding=0><tr bgcolor=lightyellow><td bgcolor=lightyellow><table 0 width=100% cellspacing=0 cellpadding=0><tr valign=top ><td ><a href="#1"><b class='cmd'>call btree_create( btree, data)</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#2"><b class='cmd'>call btree_destroy(btree )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#3"><b class='cmd'>count = btree_count( btree )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#4"><b class='cmd'>child => btree_child_node( node, right )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#5"><b class='cmd'>call btree_append_data( node, data, right )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#6"><b class='cmd'>call btree_append_subtree( node, subtree, right )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#7"><b class='cmd'>call btree_remove_subtree( node, subtree, right )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#8"><b class='cmd'>data = btree_get_data( node )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#9"><b class='cmd'>call btree_put_data( node, data )</b> </a></td></tr>
|
||||||
|
</table></td></tr></table>
|
||||||
|
<h2><a name="description">DESCRIPTION</a></h2>
|
||||||
|
<p>
|
||||||
|
|
||||||
|
The <em>binarytree.f90</em> source file allows you to implement
|
||||||
|
<em>binary trees</em> of any (derived) type without having to edit
|
||||||
|
the supplied source code. (The resulting binary tree is <em>not</em>
|
||||||
|
balanced, that would require a method of ordering the data.) To achieve
|
||||||
|
genericty, a simple technique is used, which is best illustrated by an
|
||||||
|
example:
|
||||||
|
|
||||||
|
<p><table><tr><td bgcolor=black> </td><td><pre class='sample'>
|
||||||
|
module MYDATA_MODULE
|
||||||
|
|
||||||
|
type MYDATA
|
||||||
|
character(len=20) :: string
|
||||||
|
end type MYDATA
|
||||||
|
|
||||||
|
end module
|
||||||
|
|
||||||
|
module MYDATA_BTREES
|
||||||
|
use MYDATA_MODULE, TREE_DATA => MYDATA
|
||||||
|
|
||||||
|
include "binarytree.f90"
|
||||||
|
end module MYDATA_BTREES
|
||||||
|
</pre></td></tr></table></p>
|
||||||
|
|
||||||
|
The above code defines a module <em>MYDATA_MODULE</em> with the derived
|
||||||
|
type that is to be stored in the binary trees. The name of that
|
||||||
|
derived type can be anything.
|
||||||
|
<p>
|
||||||
|
It also defines a module <em>MYDATA_BTREES</em> which will be the module
|
||||||
|
that holds the functionality to use binary trees:
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
The module <em>MYDATA_MODULE</em> is <em>used</em>, but the derived type
|
||||||
|
<em>MYDATA</em> is renamed to the (fixed) name <em>LIST_DATA</em>. (This
|
||||||
|
is the name used in the generic source file.)
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
The source code for the actual routines is simply included via the
|
||||||
|
INCLUDE statement.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
Nothing more is required, we can close the source text for the module.
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
To use a single type of binary trees in a program, we can just use the
|
||||||
|
MYDATA_BTREES module. If you need more than one type of data in binary
|
||||||
|
trees, then apply the same renaming trick on using the specific binary
|
||||||
|
trees modules.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
In fact the example in the source file "two_lists.f90" shows the general
|
||||||
|
technique of how to accomplish this for linked lists. The same applies
|
||||||
|
to binary trees.
|
||||||
|
|
||||||
|
<h2><a name="routines">ROUTINES</a></h2>
|
||||||
|
<p>
|
||||||
|
The source file <em>binarytree.f90</em> provides the following
|
||||||
|
routines:
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt><a name="1"><b class='cmd'>call btree_create( btree, data)</b> </a><dd>
|
||||||
|
|
||||||
|
Create a new tree with the given data associated to the root.
|
||||||
|
The data are copied and stored in that root.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(BINARY_TREE), pointer <i class='arg'>btree</i><dd>
|
||||||
|
The variable that will be used for accessing the tree's root
|
||||||
|
<br><br>
|
||||||
|
<dt>type(TREE_DATA), intent(in) <i class='arg'>data</i><dd>
|
||||||
|
The data to be stored in the root
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="2"><b class='cmd'>call btree_destroy(btree )</b> </a><dd>
|
||||||
|
|
||||||
|
Destroy the tree. All nodes contained in it will be destroyed as
|
||||||
|
well.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(BINARY_TREE), pointer <i class='arg'>btree</i><dd>
|
||||||
|
The list to be destroyed
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="3"><b class='cmd'>count = btree_count( btree )</b> </a><dd>
|
||||||
|
|
||||||
|
Function to return the number of nodes in the tree.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(BINARY_TREE), pointer <i class='arg'>btree</i><dd>
|
||||||
|
The tree in question
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="4"><b class='cmd'>child => btree_child_node( node, right )</b> </a><dd>
|
||||||
|
|
||||||
|
Function to return the left or right child node of a given node in the
|
||||||
|
tree. As each node is itself a tree, you can traverse the tree by
|
||||||
|
repeatedly using this function on the result.
|
||||||
|
<br><br>
|
||||||
|
Note: it returns a <em>pointer</em> to the child node,
|
||||||
|
so you must use <em>=></em>.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(BINARY_TREE), pointer <i class='arg'>node</i><dd>
|
||||||
|
The (parent) node in a tree or the root of a tree
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>logical <i class='arg'>right</i><dd>
|
||||||
|
Whether to return the right (.true.) or the left (.false.) child node.
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="5"><b class='cmd'>call btree_append_data( node, data, right )</b> </a><dd>
|
||||||
|
|
||||||
|
Append a new node to the left or right to the given node. (Note that no
|
||||||
|
balancing is taken care of). If the node already has a child node,
|
||||||
|
nothing is done.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(BINARY_TREE), pointer <i class='arg'>node</i><dd>
|
||||||
|
The node in the tree that should get a child node
|
||||||
|
<br><br>
|
||||||
|
<dt>type(TREE_DATA), intent(in) <i class='arg'>data</i><dd>
|
||||||
|
The data to be stored in the child node
|
||||||
|
<br><br>
|
||||||
|
<dt>logical <i class='arg'>right</i><dd>
|
||||||
|
Whether to append on the right (.true.) or the left (.false.) side.
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="6"><b class='cmd'>call btree_append_subtree( node, subtree, right )</b> </a><dd>
|
||||||
|
|
||||||
|
Append a subtree to the left or right to the given node.
|
||||||
|
If the node already has a child node, nothing is done. (Note: the
|
||||||
|
subtree is referred to, not copied!)
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(BINARY_TREE), pointer <i class='arg'>node</i><dd>
|
||||||
|
The node in the tree that should get a child node
|
||||||
|
<br><br>
|
||||||
|
<dt>type(BINARY_TREE), pointer <i class='arg'>subtree</i><dd>
|
||||||
|
The tree to be appended as the child node
|
||||||
|
<br><br>
|
||||||
|
<dt>logical <i class='arg'>right</i><dd>
|
||||||
|
Whether to append on the right (.true.) or the left (.false.) side.
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="7"><b class='cmd'>call btree_remove_subtree( node, subtree, right )</b> </a><dd>
|
||||||
|
|
||||||
|
Remove a subtree to the left or right to the given node.
|
||||||
|
A pointer to the subtree is returned in the "subtree" argument, so that
|
||||||
|
this can be destroyed or used independently of the original tree.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(BINARY_TREE), pointer <i class='arg'>node</i><dd>
|
||||||
|
The element in the list after which to insert a new one.
|
||||||
|
<br><br>
|
||||||
|
<dt>type(BINARY_TREE), pointer <i class='arg'>subtree</i><dd>
|
||||||
|
The subtree that was removeds the child node
|
||||||
|
<br><br>
|
||||||
|
<dt>logical <i class='arg'>right</i><dd>
|
||||||
|
Whether to remove on the right (.true.) or the left (.false.) side.
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="8"><b class='cmd'>data = btree_get_data( node )</b> </a><dd>
|
||||||
|
|
||||||
|
Return the data belonging to a node
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(BINARY_TREE), pointer <i class='arg'>node</i><dd>
|
||||||
|
The node of the tree in question
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="9"><b class='cmd'>call btree_put_data( node, data )</b> </a><dd>
|
||||||
|
|
||||||
|
Put new data at a given node
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(BINARY_TREE), pointer <i class='arg'>node</i><dd>
|
||||||
|
The node of the tree in question
|
||||||
|
<br><br>
|
||||||
|
<dt>type(TREE_DATA), intent(in) <i class='arg'>data</i><dd>
|
||||||
|
The data to be stored in the node
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
The binary trees can only store data of the same derived type. In
|
||||||
|
that sense the code is not generic.
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
Currently, the trees can only store derived types that do not require
|
||||||
|
an explicit destruction. If you want to store a derived type with
|
||||||
|
pointers to allocated memory, you can do that however, by supplying an
|
||||||
|
assignment operator. This would lead to a memory leak though. It is best
|
||||||
|
to wait for a next version that will allow such derived types to be
|
||||||
|
stored.
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2><a name="copyright">COPYRIGHT</a></h2>
|
||||||
|
<p>
|
||||||
|
Copyright © 2005 Arjen Markus <arjenmarkus@sourceforge.net><br>
|
||||||
|
</body></html>
|
||||||
227
flibs-0.9/flibs/doc/datastructures/binarytree.man
Normal file
227
flibs-0.9/flibs/doc/datastructures/binarytree.man
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
[comment {-*- flibs -*- doctools manpage}]
|
||||||
|
[manpage_begin flibs/binarytree n 1.0]
|
||||||
|
[copyright {2005 Arjen Markus <arjenmarkus@sourceforge.net>}]
|
||||||
|
[moddesc flibs]
|
||||||
|
[titledesc {Linked lists}]
|
||||||
|
|
||||||
|
[description]
|
||||||
|
|
||||||
|
The [strong binarytree.f90] source file allows you to implement
|
||||||
|
[strong "binary trees"] of any (derived) type without having to edit
|
||||||
|
the supplied source code. (The resulting binary tree is [strong not]
|
||||||
|
balanced, that would require a method of ordering the data.) To achieve
|
||||||
|
genericty, a simple technique is used, which is best illustrated by an
|
||||||
|
example:
|
||||||
|
|
||||||
|
[example {
|
||||||
|
module MYDATA_MODULE
|
||||||
|
|
||||||
|
type MYDATA
|
||||||
|
character(len=20) :: string
|
||||||
|
end type MYDATA
|
||||||
|
|
||||||
|
end module
|
||||||
|
|
||||||
|
module MYDATA_BTREES
|
||||||
|
use MYDATA_MODULE, TREE_DATA => MYDATA
|
||||||
|
|
||||||
|
include "binarytree.f90"
|
||||||
|
end module MYDATA_BTREES
|
||||||
|
}]
|
||||||
|
|
||||||
|
The above code defines a module [strong MYDATA_MODULE] with the derived
|
||||||
|
type that is to be stored in the binary trees. The name of that
|
||||||
|
derived type can be anything.
|
||||||
|
[para]
|
||||||
|
It also defines a module [strong MYDATA_BTREES] which will be the module
|
||||||
|
that holds the functionality to use binary trees:
|
||||||
|
|
||||||
|
[list_begin bullet]
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
The module [strong MYDATA_MODULE] is [strong used], but the derived type
|
||||||
|
[strong MYDATA] is renamed to the (fixed) name [strong LIST_DATA]. (This
|
||||||
|
is the name used in the generic source file.)
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
The source code for the actual routines is simply included via the
|
||||||
|
INCLUDE statement.
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
Nothing more is required, we can close the source text for the module.
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
To use a single type of binary trees in a program, we can just use the
|
||||||
|
MYDATA_BTREES module. If you need more than one type of data in binary
|
||||||
|
trees, then apply the same renaming trick on using the specific binary
|
||||||
|
trees modules.
|
||||||
|
|
||||||
|
[para]
|
||||||
|
In fact the example in the source file "two_lists.f90" shows the general
|
||||||
|
technique of how to accomplish this for linked lists. The same applies
|
||||||
|
to binary trees.
|
||||||
|
|
||||||
|
[section ROUTINES]
|
||||||
|
The source file [strong "binarytree.f90"] provides the following
|
||||||
|
routines:
|
||||||
|
|
||||||
|
[list_begin definitions]
|
||||||
|
|
||||||
|
[call [cmd "call btree_create( btree, data)"]]
|
||||||
|
Create a new tree with the given data associated to the root.
|
||||||
|
The data are copied and stored in that root.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(BINARY_TREE), pointer" btree]
|
||||||
|
The variable that will be used for accessing the tree's root
|
||||||
|
[arg_def "type(TREE_DATA), intent(in)" data]
|
||||||
|
The data to be stored in the root
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call btree_destroy(btree )"]]
|
||||||
|
Destroy the tree. All nodes contained in it will be destroyed as
|
||||||
|
well.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(BINARY_TREE), pointer" btree]
|
||||||
|
The list to be destroyed
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "count = btree_count( btree )"]]
|
||||||
|
Function to return the number of nodes in the tree.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(BINARY_TREE), pointer" btree]
|
||||||
|
The tree in question
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "child => btree_child_node( node, right )"]]
|
||||||
|
Function to return the left or right child node of a given node in the
|
||||||
|
tree. As each node is itself a tree, you can traverse the tree by
|
||||||
|
repeatedly using this function on the result.
|
||||||
|
[nl]
|
||||||
|
Note: it returns a [strong pointer] to the child node,
|
||||||
|
so you must use [strong =>].
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(BINARY_TREE), pointer" node]
|
||||||
|
The (parent) node in a tree or the root of a tree
|
||||||
|
|
||||||
|
[arg_def "logical" right]
|
||||||
|
Whether to return the right (.true.) or the left (.false.) child node.
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call btree_append_data( node, data, right )"]]
|
||||||
|
Append a new node to the left or right to the given node. (Note that no
|
||||||
|
balancing is taken care of). If the node already has a child node,
|
||||||
|
nothing is done.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(BINARY_TREE), pointer" node]
|
||||||
|
The node in the tree that should get a child node
|
||||||
|
[arg_def "type(TREE_DATA), intent(in)" data]
|
||||||
|
The data to be stored in the child node
|
||||||
|
[arg_def "logical" right]
|
||||||
|
Whether to append on the right (.true.) or the left (.false.) side.
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call btree_append_subtree( node, subtree, right )"]]
|
||||||
|
Append a subtree to the left or right to the given node.
|
||||||
|
If the node already has a child node, nothing is done. (Note: the
|
||||||
|
subtree is referred to, not copied!)
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(BINARY_TREE), pointer" node]
|
||||||
|
The node in the tree that should get a child node
|
||||||
|
[arg_def "type(BINARY_TREE), pointer" subtree]
|
||||||
|
The tree to be appended as the child node
|
||||||
|
[arg_def "logical" right]
|
||||||
|
Whether to append on the right (.true.) or the left (.false.) side.
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call btree_remove_subtree( node, subtree, right )"]]
|
||||||
|
Remove a subtree to the left or right to the given node.
|
||||||
|
A pointer to the subtree is returned in the "subtree" argument, so that
|
||||||
|
this can be destroyed or used independently of the original tree.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(BINARY_TREE), pointer" node]
|
||||||
|
The element in the list after which to insert a new one.
|
||||||
|
[arg_def "type(BINARY_TREE), pointer" subtree]
|
||||||
|
The subtree that was removeds the child node
|
||||||
|
[arg_def "logical" right]
|
||||||
|
Whether to remove on the right (.true.) or the left (.false.) side.
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "data = btree_get_data( node )"]]
|
||||||
|
Return the data belonging to a node
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(BINARY_TREE), pointer" node]
|
||||||
|
The node of the tree in question
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call btree_put_data( node, data )"]]
|
||||||
|
Put new data at a given node
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(BINARY_TREE), pointer" node]
|
||||||
|
The node of the tree in question
|
||||||
|
[arg_def "type(TREE_DATA), intent(in)" data]
|
||||||
|
The data to be stored in the node
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
[list_begin bullet]
|
||||||
|
[bullet]
|
||||||
|
The binary trees can only store data of the same derived type. In
|
||||||
|
that sense the code is not generic.
|
||||||
|
[bullet]
|
||||||
|
Currently, the trees can only store derived types that do not require
|
||||||
|
an explicit destruction. If you want to store a derived type with
|
||||||
|
pointers to allocated memory, you can do that however, by supplying an
|
||||||
|
assignment operator. This would lead to a memory leak though. It is best
|
||||||
|
to wait for a next version that will allow such derived types to be
|
||||||
|
stored.
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
[manpage_end]
|
||||||
275
flibs-0.9/flibs/doc/datastructures/linked_list.html
Normal file
275
flibs-0.9/flibs/doc/datastructures/linked_list.html
Normal file
@@ -0,0 +1,275 @@
|
|||||||
|
|
||||||
|
<html><head>
|
||||||
|
<title>flibs/datastructures - flibs </title>
|
||||||
|
</head>
|
||||||
|
<! -- Generated from file 'linked_list.man' by tcllib/doctools with format 'html'
|
||||||
|
-->
|
||||||
|
<! -- Copyright © 2005 Arjen Markus <arjenmarkus@sourceforge.net>
|
||||||
|
-->
|
||||||
|
<! -- CVS: $Id: linked_list.html,v 1.1 2008/06/13 10:27:02 relaxmike Exp $ flibs/datastructures.n
|
||||||
|
-->
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1> flibs/datastructures(n) 1.0 "flibs"</h1>
|
||||||
|
<h2><a name="name">NAME</a></h2>
|
||||||
|
<p>
|
||||||
|
<p> flibs/datastructures - Linked lists
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h2><a name="table_of_contents">TABLE OF CONTENTS</a></h2>
|
||||||
|
<p> <a href="#table_of_contents">TABLE OF CONTENTS</a><br>
|
||||||
|
<a href="#synopsis">SYNOPSIS</a><br>
|
||||||
|
<a href="#description">DESCRIPTION</a><br>
|
||||||
|
<a href="#routines">ROUTINES</a><br>
|
||||||
|
<a href="#copyright">COPYRIGHT</a><br>
|
||||||
|
<h2><a name="synopsis">SYNOPSIS</a></h2>
|
||||||
|
<p>
|
||||||
|
<table border=1 width=100% cellspacing=0 cellpadding=0><tr bgcolor=lightyellow><td bgcolor=lightyellow><table 0 width=100% cellspacing=0 cellpadding=0><tr valign=top ><td ><a href="#1"><b class='cmd'>call list_create( list, data)</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#2"><b class='cmd'>call list_destroy( list)</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#3"><b class='cmd'>count = list_count( list)</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#4"><b class='cmd'>next => list_next( elem )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#5"><b class='cmd'>call list_insert( elem, data )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#6"><b class='cmd'>call list_insert_head( list, data )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#7"><b class='cmd'>call list_delete_element( list, elem )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#8"><b class='cmd'>call list_get_data( elem, data )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#9"><b class='cmd'>call list_put_data( elem, data )</b> </a></td></tr>
|
||||||
|
</table></td></tr></table>
|
||||||
|
<h2><a name="description">DESCRIPTION</a></h2>
|
||||||
|
<p>
|
||||||
|
|
||||||
|
The <em>linkedlist.f90</em> source file allows you to implement
|
||||||
|
<em>linked lists</em> of any (derived) type without having to edit
|
||||||
|
the supplied source code. To this end a simple technique is used,
|
||||||
|
which is best illustrated by an example:
|
||||||
|
|
||||||
|
<p><table><tr><td bgcolor=black> </td><td><pre class='sample'>
|
||||||
|
module MYDATA_MODULE
|
||||||
|
|
||||||
|
type MYDATA
|
||||||
|
character(len=20) :: string
|
||||||
|
end type MYDATA
|
||||||
|
|
||||||
|
end module
|
||||||
|
|
||||||
|
module MYDATA_LISTS
|
||||||
|
use MYDATA_MODULE, LIST_DATA => MYDATA
|
||||||
|
|
||||||
|
include "linkedlist.f90"
|
||||||
|
end module MYDATA_LISTS
|
||||||
|
</pre></td></tr></table></p>
|
||||||
|
|
||||||
|
The above code defines a module <em>MYDATA_MODULE</em> with the derived
|
||||||
|
type that is to be stored in the linked lists. The name of that derived
|
||||||
|
type can be anything.
|
||||||
|
<p>
|
||||||
|
It also defines a module <em>MYDATA_LISTS</em> which will be the module
|
||||||
|
that holds the functionality to use linked lists:
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
The module <em>MYDATA_MODULE</em> is <em>used</em>, but the derived type
|
||||||
|
<em>MYDATA</em> is renamed to the (fixed) name <em>LIST_DATA</em>. (This
|
||||||
|
is the name used in the generic source file.)
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
The source code for the actual routines is simply included via the
|
||||||
|
INCLUDE statement.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
Nothing more is required, we can close the source text for the module.
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
To use a single type of linked lists in a program, we can just use the
|
||||||
|
MYDATA_LISTS module. If you need more than one type of data in linked
|
||||||
|
lists, then apply the same renaming trick on using the specific linked
|
||||||
|
lists modules.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
In fact the example in the source file "two_lists.f90" shows the general
|
||||||
|
technique of how to accomplish this.
|
||||||
|
|
||||||
|
<h2><a name="routines">ROUTINES</a></h2>
|
||||||
|
<p>
|
||||||
|
The source file <em>linkedlist.f90</em> provides the following
|
||||||
|
routines:
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt><a name="1"><b class='cmd'>call list_create( list, data)</b> </a><dd>
|
||||||
|
|
||||||
|
Create a new list with one element. The given data are copied and stored
|
||||||
|
in that element.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(LINKED_LIST), pointer <i class='arg'>list</i><dd>
|
||||||
|
The variable that will be used for accessing the list
|
||||||
|
<br><br>
|
||||||
|
<dt>type(LIST_DATA), intent(in) <i class='arg'>data</i><dd>
|
||||||
|
The data to be stored in the first element
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="2"><b class='cmd'>call list_destroy( list)</b> </a><dd>
|
||||||
|
|
||||||
|
Destroy the list. All elements contained in it will be destroyed as
|
||||||
|
well.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(LINKED_LIST), pointer <i class='arg'>list</i><dd>
|
||||||
|
The list to be destroyed
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="3"><b class='cmd'>count = list_count( list)</b> </a><dd>
|
||||||
|
|
||||||
|
Function to return the number of elements in the list.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(LINKED_LIST), pointer <i class='arg'>list</i><dd>
|
||||||
|
The list in question
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="4"><b class='cmd'>next => list_next( elem )</b> </a><dd>
|
||||||
|
|
||||||
|
Function to return the next element in the list. Note: it returns a
|
||||||
|
<em>pointer</em> to the next element, so you must use <em>=></em>.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(LINKED_LIST), pointer <i class='arg'>elem</i><dd>
|
||||||
|
The element in the list
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="5"><b class='cmd'>call list_insert( elem, data )</b> </a><dd>
|
||||||
|
|
||||||
|
Insert a new element (with the given data) into the list, <em>after</em>
|
||||||
|
the given element.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(LINKED_LIST), pointer <i class='arg'>elem</i><dd>
|
||||||
|
The element in the list after which to insert a new one.
|
||||||
|
<br><br>
|
||||||
|
<dt>type(LIST_DATA), intent(in) <i class='arg'>data</i><dd>
|
||||||
|
The data to be stored in the new element
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="6"><b class='cmd'>call list_insert_head( list, data )</b> </a><dd>
|
||||||
|
|
||||||
|
Insert a new element (with the given data) before the head of list.
|
||||||
|
The argument "list" will point to the new head.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(LINKED_LIST), pointer <i class='arg'>list</i><dd>
|
||||||
|
The list in question
|
||||||
|
<br><br>
|
||||||
|
<dt>type(LIST_DATA), intent(in) <i class='arg'>data</i><dd>
|
||||||
|
The data to be stored at the new head
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="7"><b class='cmd'>call list_delete_element( list, elem )</b> </a><dd>
|
||||||
|
|
||||||
|
Delete the given element from the list. The associated data
|
||||||
|
will disappear.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(LINKED_LIST), pointer <i class='arg'>list</i><dd>
|
||||||
|
The list in question
|
||||||
|
<br><br>
|
||||||
|
<dt>type(LINKED_LIST), pointer <i class='arg'>elem</i><dd>
|
||||||
|
The element to be deleted
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="8"><b class='cmd'>call list_get_data( elem, data )</b> </a><dd>
|
||||||
|
|
||||||
|
Copy the data belonging to the given element into the argument "data".
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(LINKED_LIST), pointer <i class='arg'>list</i><dd>
|
||||||
|
The element in question
|
||||||
|
<br><br>
|
||||||
|
<dt>type(LIST_DATA), intent(out) <i class='arg'>data</i><dd>
|
||||||
|
The variable to hold the data
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="9"><b class='cmd'>call list_put_data( elem, data )</b> </a><dd>
|
||||||
|
|
||||||
|
Copy the given data into the given element (overwriting the previous)
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(LINKED_LIST), pointer <i class='arg'>list</i><dd>
|
||||||
|
The element in question
|
||||||
|
<br><br>
|
||||||
|
<br><br>
|
||||||
|
<dt>type(LIST_DATA), intent(in) <i class='arg'>data</i><dd>
|
||||||
|
The new data
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
The lists can only store data of the same derived type. In that sense
|
||||||
|
the code is not generic.
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
Currently, the lists can only store derived types that do not require
|
||||||
|
an explicit destruction. If you want to store a derived type with
|
||||||
|
pointers to allocated memory, you can do that however, by supplying an
|
||||||
|
assignment operator. This would lead to a memory leak though. It is best
|
||||||
|
to wait for the next version which will allow such derived types to be
|
||||||
|
stored.
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2><a name="copyright">COPYRIGHT</a></h2>
|
||||||
|
<p>
|
||||||
|
Copyright © 2005 Arjen Markus <arjenmarkus@sourceforge.net><br>
|
||||||
|
</body></html>
|
||||||
211
flibs-0.9/flibs/doc/datastructures/linked_list.man
Normal file
211
flibs-0.9/flibs/doc/datastructures/linked_list.man
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
[comment {-*- flibs -*- doctools manpage}]
|
||||||
|
[manpage_begin flibs/datastructures n 1.0]
|
||||||
|
[copyright {2005 Arjen Markus <arjenmarkus@sourceforge.net>}]
|
||||||
|
[moddesc flibs]
|
||||||
|
[titledesc {Linked lists}]
|
||||||
|
|
||||||
|
[description]
|
||||||
|
|
||||||
|
The [strong linkedlist.f90] source file allows you to implement
|
||||||
|
[strong "linked lists"] of any (derived) type without having to edit
|
||||||
|
the supplied source code. To this end a simple technique is used,
|
||||||
|
which is best illustrated by an example:
|
||||||
|
|
||||||
|
[example {
|
||||||
|
module MYDATA_MODULE
|
||||||
|
|
||||||
|
type MYDATA
|
||||||
|
character(len=20) :: string
|
||||||
|
end type MYDATA
|
||||||
|
|
||||||
|
end module
|
||||||
|
|
||||||
|
module MYDATA_LISTS
|
||||||
|
use MYDATA_MODULE, LIST_DATA => MYDATA
|
||||||
|
|
||||||
|
include "linkedlist.f90"
|
||||||
|
end module MYDATA_LISTS
|
||||||
|
}]
|
||||||
|
|
||||||
|
The above code defines a module [strong MYDATA_MODULE] with the derived
|
||||||
|
type that is to be stored in the linked lists. The name of that derived
|
||||||
|
type can be anything.
|
||||||
|
[para]
|
||||||
|
It also defines a module [strong MYDATA_LISTS] which will be the module
|
||||||
|
that holds the functionality to use linked lists:
|
||||||
|
|
||||||
|
[list_begin bullet]
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
The module [strong MYDATA_MODULE] is [strong used], but the derived type
|
||||||
|
[strong MYDATA] is renamed to the (fixed) name [strong LIST_DATA]. (This
|
||||||
|
is the name used in the generic source file.)
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
The source code for the actual routines is simply included via the
|
||||||
|
INCLUDE statement.
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
Nothing more is required, we can close the source text for the module.
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
To use a single type of linked lists in a program, we can just use the
|
||||||
|
MYDATA_LISTS module. If you need more than one type of data in linked
|
||||||
|
lists, then apply the same renaming trick on using the specific linked
|
||||||
|
lists modules.
|
||||||
|
|
||||||
|
[para]
|
||||||
|
In fact the example in the source file "two_lists.f90" shows the general
|
||||||
|
technique of how to accomplish this.
|
||||||
|
|
||||||
|
[section ROUTINES]
|
||||||
|
The source file [strong "linkedlist.f90"] provides the following
|
||||||
|
routines:
|
||||||
|
|
||||||
|
[list_begin definitions]
|
||||||
|
|
||||||
|
[call [cmd "call list_create( list, data)"]]
|
||||||
|
Create a new list with one element. The given data are copied and stored
|
||||||
|
in that element.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(LINKED_LIST), pointer" list]
|
||||||
|
The variable that will be used for accessing the list
|
||||||
|
[arg_def "type(LIST_DATA), intent(in)" data]
|
||||||
|
The data to be stored in the first element
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call list_destroy( list)"]]
|
||||||
|
Destroy the list. All elements contained in it will be destroyed as
|
||||||
|
well.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(LINKED_LIST), pointer" list]
|
||||||
|
The list to be destroyed
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "count = list_count( list)"]]
|
||||||
|
Function to return the number of elements in the list.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(LINKED_LIST), pointer" list]
|
||||||
|
The list in question
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "next => list_next( elem )"]]
|
||||||
|
Function to return the next element in the list. Note: it returns a
|
||||||
|
[strong pointer] to the next element, so you must use [strong =>].
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(LINKED_LIST), pointer" elem]
|
||||||
|
The element in the list
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call list_insert( elem, data )"]]
|
||||||
|
Insert a new element (with the given data) into the list, [strong after]
|
||||||
|
the given element.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(LINKED_LIST), pointer" elem]
|
||||||
|
The element in the list after which to insert a new one.
|
||||||
|
[arg_def "type(LIST_DATA), intent(in)" data]
|
||||||
|
The data to be stored in the new element
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call list_insert_head( list, data )"]]
|
||||||
|
Insert a new element (with the given data) before the head of list.
|
||||||
|
The argument "list" will point to the new head.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(LINKED_LIST), pointer" list]
|
||||||
|
The list in question
|
||||||
|
[arg_def "type(LIST_DATA), intent(in)" data]
|
||||||
|
The data to be stored at the new head
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call list_delete_element( list, elem )"]]
|
||||||
|
Delete the given element from the list. The associated data
|
||||||
|
will disappear.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(LINKED_LIST), pointer" list]
|
||||||
|
The list in question
|
||||||
|
[arg_def "type(LINKED_LIST), pointer" elem]
|
||||||
|
The element to be deleted
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call list_get_data( elem, data )"]]
|
||||||
|
Copy the data belonging to the given element into the argument "data".
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(LINKED_LIST), pointer" list]
|
||||||
|
The element in question
|
||||||
|
[arg_def "type(LIST_DATA), intent(out)" data]
|
||||||
|
The variable to hold the data
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call list_put_data( elem, data )"]]
|
||||||
|
Copy the given data into the given element (overwriting the previous)
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(LINKED_LIST), pointer" list]
|
||||||
|
The element in question
|
||||||
|
[nl]
|
||||||
|
[arg_def "type(LIST_DATA), intent(in)" data]
|
||||||
|
The new data
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
[list_begin bullet]
|
||||||
|
[bullet]
|
||||||
|
The lists can only store data of the same derived type. In that sense
|
||||||
|
the code is not generic.
|
||||||
|
[bullet]
|
||||||
|
Currently, the lists can only store derived types that do not require
|
||||||
|
an explicit destruction. If you want to store a derived type with
|
||||||
|
pointers to allocated memory, you can do that however, by supplying an
|
||||||
|
assignment operator. This would lead to a memory leak though. It is best
|
||||||
|
to wait for the next version which will allow such derived types to be
|
||||||
|
stored.
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
[manpage_end]
|
||||||
111
flibs-0.9/flibs/doc/datastructures/mem_pool.html
Normal file
111
flibs-0.9/flibs/doc/datastructures/mem_pool.html
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
|
||||||
|
<html><head>
|
||||||
|
<title>mem_pool - flibs </title>
|
||||||
|
</head>
|
||||||
|
<! -- Generated from file 'mem_pool.man' by tcllib/doctools with format 'html'
|
||||||
|
-->
|
||||||
|
<! -- Copyright © 2006 Arjen Markus <arjenmarkus@sourceforge.net>
|
||||||
|
-->
|
||||||
|
<! -- CVS: $Id: mem_pool.html,v 1.1 2008/06/13 10:33:28 relaxmike Exp $ mem_pool.n
|
||||||
|
-->
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1> mem_pool(n) 1.0 "flibs"</h1>
|
||||||
|
<h2><a name="name">NAME</a></h2>
|
||||||
|
<p>
|
||||||
|
<p> mem_pool - Implement a straightforward memory pool
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h2><a name="table_of_contents">TABLE OF CONTENTS</a></h2>
|
||||||
|
<p> <a href="#table_of_contents">TABLE OF CONTENTS</a><br>
|
||||||
|
<a href="#synopsis">SYNOPSIS</a><br>
|
||||||
|
<a href="#description">DESCRIPTION</a><br>
|
||||||
|
<a href="#data_types_and_routines">DATA TYPES AND ROUTINES</a><br>
|
||||||
|
<a href="#implementation_notes">IMPLEMENTATION NOTES</a><br>
|
||||||
|
<a href="#copyright">COPYRIGHT</a><br>
|
||||||
|
<h2><a name="synopsis">SYNOPSIS</a></h2>
|
||||||
|
<p>
|
||||||
|
<table border=1 width=100% cellspacing=0 cellpadding=0><tr bgcolor=lightyellow><td bgcolor=lightyellow><table 0 width=100% cellspacing=0 cellpadding=0><tr valign=top ><td ><a href="#1"><b class='cmd'>call pool_acquire( pdata )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#2"><b class='cmd'>call pool_release( pdata )</b> </a></td></tr>
|
||||||
|
</table></td></tr></table>
|
||||||
|
<h2><a name="description">DESCRIPTION</a></h2>
|
||||||
|
<p>
|
||||||
|
|
||||||
|
The <em>mem_pool.f90</em> source file defines a set of subroutines
|
||||||
|
that allow you to acquire and release memory of a particular derived
|
||||||
|
type, thereby reducing the number of allocations and deallocations.
|
||||||
|
Such a memory pool is useful for instance when you need temporary memory
|
||||||
|
of fixed size.
|
||||||
|
|
||||||
|
<h2><a name="data_types_and_routines">DATA TYPES AND ROUTINES</a></h2>
|
||||||
|
<p>
|
||||||
|
The source code expects a data type, POOL_DATA, that contains an integer
|
||||||
|
field "pool_index" for private use by the subroutines. All other fields
|
||||||
|
can be used by the application itself:
|
||||||
|
|
||||||
|
<p><table><tr><td bgcolor=black> </td><td><pre class='sample'>
|
||||||
|
module MYDATA_POOL
|
||||||
|
|
||||||
|
type POOLDATA
|
||||||
|
integer :: pool_index ! For private use by pool_acquire/pool_release
|
||||||
|
real, dimension(100) :: work ! The actual work space
|
||||||
|
end type
|
||||||
|
|
||||||
|
include "mem_pool.f90"
|
||||||
|
|
||||||
|
end module MYDATA_POOL
|
||||||
|
</pre></td></tr></table></p>
|
||||||
|
|
||||||
|
The code defines the following routines:
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt><a name="1"><b class='cmd'>call pool_acquire( pdata )</b> </a><dd>
|
||||||
|
|
||||||
|
Get a pointer to available data in the memory pool. The memory pool is
|
||||||
|
expanded automatically, by allocating an array of 100 items. If there
|
||||||
|
is an error (no more memory can be allocated), the pointer will not be
|
||||||
|
associated.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(pool_data), pointer <i class='arg'>pdata</i><dd>
|
||||||
|
The pointer variable that will be associated with valid memory
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
<dt><a name="2"><b class='cmd'>call pool_release( pdata )</b> </a><dd>
|
||||||
|
|
||||||
|
Release the data pointed to by pdata to the memory pool. This data will
|
||||||
|
become available again for further acquiring.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(pool_data), pointer <i class='arg'>pdata</i><dd>
|
||||||
|
The pointer variable pointing to data to be released into the pool
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
(Note: two more subroutines are envisioned: setting two parameters that
|
||||||
|
control the allocation and deallocation of memory, and a routine to
|
||||||
|
print statistical information. These have not been implemented yet.)
|
||||||
|
|
||||||
|
<h2><a name="implementation_notes">IMPLEMENTATION NOTES</a></h2>
|
||||||
|
<p>
|
||||||
|
The subroutines do not change the fields of the POOL_DATA structure
|
||||||
|
(except for pool_index). This means that allocatable (pointer)
|
||||||
|
components in this structure are not influenced. You could use this to
|
||||||
|
store dynamically sized arrays in the memory pool. It is especially
|
||||||
|
useful if all such arrays have the same size.
|
||||||
|
|
||||||
|
<h2><a name="copyright">COPYRIGHT</a></h2>
|
||||||
|
<p>
|
||||||
|
Copyright © 2006 Arjen Markus <arjenmarkus@sourceforge.net><br>
|
||||||
|
</body></html>
|
||||||
75
flibs-0.9/flibs/doc/datastructures/mem_pool.man
Normal file
75
flibs-0.9/flibs/doc/datastructures/mem_pool.man
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
[comment {-*- flibs -*- doctools manpage}]
|
||||||
|
[manpage_begin mem_pool n 1.0]
|
||||||
|
[copyright {2006 Arjen Markus <arjenmarkus@sourceforge.net>}]
|
||||||
|
[moddesc flibs]
|
||||||
|
[titledesc {Implement a straightforward memory pool}]
|
||||||
|
|
||||||
|
[description]
|
||||||
|
|
||||||
|
The [strong mem_pool.f90] source file defines a set of subroutines
|
||||||
|
that allow you to acquire and release memory of a particular derived
|
||||||
|
type, thereby reducing the number of allocations and deallocations.
|
||||||
|
Such a memory pool is useful for instance when you need temporary memory
|
||||||
|
of fixed size.
|
||||||
|
|
||||||
|
[section "DATA TYPES AND ROUTINES"]
|
||||||
|
The source code expects a data type, POOL_DATA, that contains an integer
|
||||||
|
field "pool_index" for private use by the subroutines. All other fields
|
||||||
|
can be used by the application itself:
|
||||||
|
|
||||||
|
[example {
|
||||||
|
module MYDATA_POOL
|
||||||
|
|
||||||
|
type POOLDATA
|
||||||
|
integer :: pool_index ! For private use by pool_acquire/pool_release
|
||||||
|
real, dimension(100) :: work ! The actual work space
|
||||||
|
end type
|
||||||
|
|
||||||
|
include "mem_pool.f90"
|
||||||
|
|
||||||
|
end module MYDATA_POOL
|
||||||
|
}]
|
||||||
|
|
||||||
|
The code defines the following routines:
|
||||||
|
|
||||||
|
[list_begin definitions]
|
||||||
|
|
||||||
|
[call [cmd "call pool_acquire( pdata )"]]
|
||||||
|
Get a pointer to available data in the memory pool. The memory pool is
|
||||||
|
expanded automatically, by allocating an array of 100 items. If there
|
||||||
|
is an error (no more memory can be allocated), the pointer will not be
|
||||||
|
associated.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(pool_data), pointer" pdata]
|
||||||
|
The pointer variable that will be associated with valid memory
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
[call [cmd "call pool_release( pdata )"]]
|
||||||
|
Release the data pointed to by pdata to the memory pool. This data will
|
||||||
|
become available again for further acquiring.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(pool_data), pointer" pdata]
|
||||||
|
The pointer variable pointing to data to be released into the pool
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
(Note: two more subroutines are envisioned: setting two parameters that
|
||||||
|
control the allocation and deallocation of memory, and a routine to
|
||||||
|
print statistical information. These have not been implemented yet.)
|
||||||
|
|
||||||
|
[section "IMPLEMENTATION NOTES"]
|
||||||
|
The subroutines do not change the fields of the POOL_DATA structure
|
||||||
|
(except for pool_index). This means that allocatable (pointer)
|
||||||
|
components in this structure are not influenced. You could use this to
|
||||||
|
store dynamically sized arrays in the memory pool. It is especially
|
||||||
|
useful if all such arrays have the same size.
|
||||||
|
|
||||||
|
[manpage_end]
|
||||||
430
flibs-0.9/flibs/doc/datastructures/sets.html
Normal file
430
flibs-0.9/flibs/doc/datastructures/sets.html
Normal file
@@ -0,0 +1,430 @@
|
|||||||
|
|
||||||
|
<html><head>
|
||||||
|
<title>flibs/datastructures - flibs </title>
|
||||||
|
</head>
|
||||||
|
<! -- Generated from file 'sets.man' by tcllib/doctools with format 'html'
|
||||||
|
-->
|
||||||
|
<! -- Copyright © 2006 Arjen Markus <arjenmarkus@sourceforge.net>
|
||||||
|
-->
|
||||||
|
<! -- CVS: $Id: sets.html,v 1.1 2008/06/13 10:25:55 relaxmike Exp $ flibs/datastructures.n
|
||||||
|
-->
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1> flibs/datastructures(n) 1.0 "flibs"</h1>
|
||||||
|
<h2><a name="name">NAME</a></h2>
|
||||||
|
<p>
|
||||||
|
<p> flibs/datastructures - Unordered sets
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h2><a name="table_of_contents">TABLE OF CONTENTS</a></h2>
|
||||||
|
<p> <a href="#table_of_contents">TABLE OF CONTENTS</a><br>
|
||||||
|
<a href="#synopsis">SYNOPSIS</a><br>
|
||||||
|
<a href="#description">DESCRIPTION</a><br>
|
||||||
|
<a href="#routines">ROUTINES</a><br>
|
||||||
|
<a href="#copyright">COPYRIGHT</a><br>
|
||||||
|
<h2><a name="synopsis">SYNOPSIS</a></h2>
|
||||||
|
<p>
|
||||||
|
<table border=1 width=100% cellspacing=0 cellpadding=0><tr bgcolor=lightyellow><td bgcolor=lightyellow><table 0 width=100% cellspacing=0 cellpadding=0><tr valign=top ><td ><a href="#1"><b class='cmd'>call set_create( dataset )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#2"><b class='cmd'>call set_destroy( dataset )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#3"><b class='cmd'>size = set_size( dataset )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#4"><b class='cmd'>call set_add( dataset, elem )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#5"><b class='cmd'>call set_delete_element( dataset, elem )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#6"><b class='cmd'>has = set_haselement( dataset, elem )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#7"><b class='cmd'>has = elem .elementof. dataset</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#8"><b class='cmd'>equal = set_equal( set1, set2 )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#9"><b class='cmd'>equal = set1 .eq. set2</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#10"><b class='cmd'>notequal = set_notequal( set1, set2 )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#11"><b class='cmd'>notequal = set1 .ne. set2</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#12"><b class='cmd'>has = set_hassubset( dataset, subset )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#13"><b class='cmd'>has = subset .subsetof. dataset</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#14"><b class='cmd'>newset = set_union( set1, set2 )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#15"><b class='cmd'>newset = set1 .union. set2</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#16"><b class='cmd'>newset = set_intersection( set1, set2 )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#17"><b class='cmd'>newset = set1 .intersect. set2</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#18"><b class='cmd'>newset = set_exclusion( set1, set2 )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#19"><b class='cmd'>newset = set1 .intersect. set2</b> </a></td></tr>
|
||||||
|
</table></td></tr></table>
|
||||||
|
<h2><a name="description">DESCRIPTION</a></h2>
|
||||||
|
<p>
|
||||||
|
|
||||||
|
The <em>sets.f90</em> source file allows you to implement
|
||||||
|
<em>unordered sets</em> of any (derived) type without having to
|
||||||
|
edit the supplied source code. To this end a simple technique is used,
|
||||||
|
which is best illustrated by an example:
|
||||||
|
|
||||||
|
<p><table><tr><td bgcolor=black> </td><td><pre class='sample'>
|
||||||
|
!
|
||||||
|
! The data that will be stored in the sets
|
||||||
|
!
|
||||||
|
type MYDATA
|
||||||
|
integer :: value
|
||||||
|
end type MYDATA
|
||||||
|
|
||||||
|
!
|
||||||
|
! As derived types are compared, we need to define
|
||||||
|
! how to compare them
|
||||||
|
!
|
||||||
|
interface operator(.eq.)
|
||||||
|
module procedure mydata_isequal
|
||||||
|
end interface
|
||||||
|
|
||||||
|
contains
|
||||||
|
logical function mydata_isequal( v1, v2 )
|
||||||
|
type(MYDATA), intent(in) :: v1
|
||||||
|
type(MYDATA), intent(in) :: v2
|
||||||
|
|
||||||
|
mydata_isequal = v1%value .eq. v2%value
|
||||||
|
end function mydata_isequal
|
||||||
|
|
||||||
|
end module MYDATA_MODULE
|
||||||
|
|
||||||
|
module MYDATA_SET_STRUCTS
|
||||||
|
use MYDATA_MODULE, SET_DATA => MYDATA
|
||||||
|
|
||||||
|
include "data_for_sets.f90"
|
||||||
|
end module MYDATA_SET_STRUCTS
|
||||||
|
|
||||||
|
module MYDATA_SETS
|
||||||
|
use MYDATA_SET_STRUCTS
|
||||||
|
|
||||||
|
include "sets.f90"
|
||||||
|
end module MYDATA_SETS
|
||||||
|
</pre></td></tr></table></p>
|
||||||
|
|
||||||
|
The above code defines a module <em>MYDATA_MODULE</em> with the derived
|
||||||
|
type that is to be stored in the sets. The name of that derived
|
||||||
|
type can be anything.
|
||||||
|
<p>
|
||||||
|
It also defines a module <em>MYDATA_SET_STRUCTS</em> which prepares the
|
||||||
|
underlying data structure. The reason for this two-layer process is that
|
||||||
|
you need to be able to define the name of the modules that are involved
|
||||||
|
yourself. (Otherwise it would be impossible to use two or more
|
||||||
|
<em>sets</em> holding different types of data in one program.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
It finally defines a module <em>MYDATA_SETS</em> which will be the
|
||||||
|
module that holds the functionality to use unordered sets:
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
The module <em>MYDATA_MODULE</em> is <em>used</em>, but the derived type
|
||||||
|
<em>MYDATA</em> is renamed to the (fixed) name <em>SET_DATA</em>. (This
|
||||||
|
is the name used in the generic source file.)
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
The source code for the actual routines is simply included via the
|
||||||
|
INCLUDE statement.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
Nothing more is required, we can close the source text for the module.
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
To use a single type of sets in a program, we can just use the
|
||||||
|
MYDATA_SETS module. If you need more than one type of data in sets,
|
||||||
|
then apply the same renaming trick on using the specific set
|
||||||
|
modules.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
In fact the example in the source file "two_lists.f90" shows the general
|
||||||
|
technique of how to accomplish this.
|
||||||
|
|
||||||
|
<h2><a name="routines">ROUTINES</a></h2>
|
||||||
|
<p>
|
||||||
|
The source file <em>sets.f90</em> provides the following
|
||||||
|
routines:
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt><a name="1"><b class='cmd'>call set_create( dataset )</b> </a><dd>
|
||||||
|
|
||||||
|
Create a new empty set.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(SET) <i class='arg'>dataset</i><dd>
|
||||||
|
The variable that will be used for accessing the set
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="2"><b class='cmd'>call set_destroy( dataset )</b> </a><dd>
|
||||||
|
|
||||||
|
Destroy the set. All elements contained in it will be destroyed as
|
||||||
|
well.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(SET) <i class='arg'>dataset</i><dd>
|
||||||
|
The set to be destroyed
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="3"><b class='cmd'>size = set_size( dataset )</b> </a><dd>
|
||||||
|
|
||||||
|
Function to return the number of elements in the set.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(SET) <i class='arg'>dataset</i><dd>
|
||||||
|
The set in question
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="4"><b class='cmd'>call set_add( dataset, elem )</b> </a><dd>
|
||||||
|
|
||||||
|
Insert a new element in the set. If the element is already present,
|
||||||
|
nothing is done.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(SET) <i class='arg'>dataset</i><dd>
|
||||||
|
The dataset to add the element to.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>type(SET_DATA), intent(in) <i class='arg'>elem</i><dd>
|
||||||
|
The element to be stored
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="5"><b class='cmd'>call set_delete_element( dataset, elem )</b> </a><dd>
|
||||||
|
|
||||||
|
Delete the given element from the set.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(SET) <i class='arg'>dataset</i><dd>
|
||||||
|
The list in question
|
||||||
|
<br><br>
|
||||||
|
<dt>type(SET_DATA) <i class='arg'>elem</i><dd>
|
||||||
|
The element to be deleted
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="6"><b class='cmd'>has = set_haselement( dataset, elem )</b> </a><dd>
|
||||||
|
|
||||||
|
Returns whether or not the given element is in the set.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(SET) <i class='arg'>dataset</i><dd>
|
||||||
|
The set in question
|
||||||
|
<br><br>
|
||||||
|
<dt>type(SET_DATA) <i class='arg'>elem</i><dd>
|
||||||
|
The element to be checked
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="7"><b class='cmd'>has = elem .elementof. dataset</b> </a><dd>
|
||||||
|
|
||||||
|
Returns whether or not the given element is in the set.
|
||||||
|
(The operator version)
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(SET) <i class='arg'>dataset</i><dd>
|
||||||
|
The set in question
|
||||||
|
<br><br>
|
||||||
|
<dt>type(SET_DATA) <i class='arg'>elem</i><dd>
|
||||||
|
The element to be checked
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="8"><b class='cmd'>equal = set_equal( set1, set2 )</b> </a><dd>
|
||||||
|
|
||||||
|
Returns whether or not the two sets contain the same elements.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(SET) <i class='arg'>set1</i><dd>
|
||||||
|
The first set
|
||||||
|
<br><br>
|
||||||
|
<dt>type(SET) <i class='arg'>set2</i><dd>
|
||||||
|
The second set
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="9"><b class='cmd'>equal = set1 .eq. set2</b> </a><dd>
|
||||||
|
|
||||||
|
Returns whether or not the two sets contain the same elements.
|
||||||
|
(The operator version)
|
||||||
|
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt><a name="10"><b class='cmd'>notequal = set_notequal( set1, set2 )</b> </a><dd>
|
||||||
|
|
||||||
|
Returns whether or not the two sets do not contain the same elements.
|
||||||
|
(The operator version)
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(SET) <i class='arg'>set1</i><dd>
|
||||||
|
The first set
|
||||||
|
<br><br>
|
||||||
|
<dt>type(SET) <i class='arg'>set2</i><dd>
|
||||||
|
The second set
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="11"><b class='cmd'>notequal = set1 .ne. set2</b> </a><dd>
|
||||||
|
|
||||||
|
Returns whether or not the two sets do not contain the same elements.
|
||||||
|
(The operator version)
|
||||||
|
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt><a name="12"><b class='cmd'>has = set_hassubset( dataset, subset )</b> </a><dd>
|
||||||
|
|
||||||
|
Returns whether or not one set is contained in the other set.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(SET) <i class='arg'>dataset</i><dd>
|
||||||
|
The set that may hold the second one
|
||||||
|
<br><br>
|
||||||
|
<dt>type(SET) <i class='arg'>subset</i><dd>
|
||||||
|
The set that may be a subset of the fist
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="13"><b class='cmd'>has = subset .subsetof. dataset</b> </a><dd>
|
||||||
|
|
||||||
|
Returns whether or not one set is contained in the other set.
|
||||||
|
(The operator version)
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(SET) <i class='arg'>subset</i><dd>
|
||||||
|
The set that may be a subset of the other
|
||||||
|
<br><br>
|
||||||
|
<dt>type(SET) <i class='arg'>dataset</i><dd>
|
||||||
|
The set that may hold the first one
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="14"><b class='cmd'>newset = set_union( set1, set2 )</b> </a><dd>
|
||||||
|
|
||||||
|
Returns the union of two sets.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(SET) <i class='arg'>set1</i><dd>
|
||||||
|
The first set
|
||||||
|
<br><br>
|
||||||
|
<dt>type(SET) <i class='arg'>set2</i><dd>
|
||||||
|
The second set
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
<dt><a name="15"><b class='cmd'>newset = set1 .union. set2</b> </a><dd>
|
||||||
|
|
||||||
|
Returns the union of two sets - operator version.
|
||||||
|
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt><a name="16"><b class='cmd'>newset = set_intersection( set1, set2 )</b> </a><dd>
|
||||||
|
|
||||||
|
Returns the intersection of two sets.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(SET) <i class='arg'>set1</i><dd>
|
||||||
|
The first set
|
||||||
|
<br><br>
|
||||||
|
<dt>type(SET) <i class='arg'>set2</i><dd>
|
||||||
|
The second set
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
<dt><a name="17"><b class='cmd'>newset = set1 .intersect. set2</b> </a><dd>
|
||||||
|
|
||||||
|
Returns the intersection of two sets - operator version.
|
||||||
|
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt><a name="18"><b class='cmd'>newset = set_exclusion( set1, set2 )</b> </a><dd>
|
||||||
|
|
||||||
|
Returns a copy of the first set with the elements of the second set
|
||||||
|
excluded.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>type(SET) <i class='arg'>set1</i><dd>
|
||||||
|
The first set
|
||||||
|
<br><br>
|
||||||
|
<dt>type(SET) <i class='arg'>set2</i><dd>
|
||||||
|
The second set
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
<dt><a name="19"><b class='cmd'>newset = set1 .intersect. set2</b> </a><dd>
|
||||||
|
|
||||||
|
Returns a copy of the first set with the elements of the second set
|
||||||
|
excluded - operator version.
|
||||||
|
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
The sets can only store data of the same derived type. In that sense
|
||||||
|
the code is not generic.
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
Currently, the sets can only store derived types that do not require
|
||||||
|
an explicit destruction. If you want to store a derived type with
|
||||||
|
pointers to allocated memory, you can do that however, by supplying an
|
||||||
|
assignment operator. This would lead to a memory leak though. It is best
|
||||||
|
to wait for the next version which will allow such derived types to be
|
||||||
|
stored.
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2><a name="copyright">COPYRIGHT</a></h2>
|
||||||
|
<p>
|
||||||
|
Copyright © 2006 Arjen Markus <arjenmarkus@sourceforge.net><br>
|
||||||
|
</body></html>
|
||||||
332
flibs-0.9/flibs/doc/datastructures/sets.man
Normal file
332
flibs-0.9/flibs/doc/datastructures/sets.man
Normal file
@@ -0,0 +1,332 @@
|
|||||||
|
[comment {-*- flibs -*- doctools manpage}]
|
||||||
|
[manpage_begin flibs/datastructures n 1.0]
|
||||||
|
[copyright {2006 Arjen Markus <arjenmarkus@sourceforge.net>}]
|
||||||
|
[moddesc flibs]
|
||||||
|
[titledesc {Unordered sets}]
|
||||||
|
|
||||||
|
[description]
|
||||||
|
|
||||||
|
The [strong sets.f90] source file allows you to implement
|
||||||
|
[strong "unordered sets"] of any (derived) type without having to
|
||||||
|
edit the supplied source code. To this end a simple technique is used,
|
||||||
|
which is best illustrated by an example:
|
||||||
|
|
||||||
|
[example {
|
||||||
|
!
|
||||||
|
! The data that will be stored in the sets
|
||||||
|
!
|
||||||
|
type MYDATA
|
||||||
|
integer :: value
|
||||||
|
end type MYDATA
|
||||||
|
|
||||||
|
!
|
||||||
|
! As derived types are compared, we need to define
|
||||||
|
! how to compare them
|
||||||
|
!
|
||||||
|
interface operator(.eq.)
|
||||||
|
module procedure mydata_isequal
|
||||||
|
end interface
|
||||||
|
|
||||||
|
contains
|
||||||
|
logical function mydata_isequal( v1, v2 )
|
||||||
|
type(MYDATA), intent(in) :: v1
|
||||||
|
type(MYDATA), intent(in) :: v2
|
||||||
|
|
||||||
|
mydata_isequal = v1%value .eq. v2%value
|
||||||
|
end function mydata_isequal
|
||||||
|
|
||||||
|
end module MYDATA_MODULE
|
||||||
|
|
||||||
|
module MYDATA_SET_STRUCTS
|
||||||
|
use MYDATA_MODULE, SET_DATA => MYDATA
|
||||||
|
|
||||||
|
include "data_for_sets.f90"
|
||||||
|
end module MYDATA_SET_STRUCTS
|
||||||
|
|
||||||
|
module MYDATA_SETS
|
||||||
|
use MYDATA_SET_STRUCTS
|
||||||
|
|
||||||
|
include "sets.f90"
|
||||||
|
end module MYDATA_SETS
|
||||||
|
}]
|
||||||
|
|
||||||
|
The above code defines a module [strong MYDATA_MODULE] with the derived
|
||||||
|
type that is to be stored in the sets. The name of that derived
|
||||||
|
type can be anything.
|
||||||
|
[para]
|
||||||
|
It also defines a module [strong MYDATA_SET_STRUCTS] which prepares the
|
||||||
|
underlying data structure. The reason for this two-layer process is that
|
||||||
|
you need to be able to define the name of the modules that are involved
|
||||||
|
yourself. (Otherwise it would be impossible to use two or more
|
||||||
|
[strong sets] holding different types of data in one program.
|
||||||
|
|
||||||
|
[para]
|
||||||
|
It finally defines a module [strong MYDATA_SETS] which will be the
|
||||||
|
module that holds the functionality to use unordered sets:
|
||||||
|
|
||||||
|
[list_begin bullet]
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
The module [strong MYDATA_MODULE] is [strong used], but the derived type
|
||||||
|
[strong MYDATA] is renamed to the (fixed) name [strong SET_DATA]. (This
|
||||||
|
is the name used in the generic source file.)
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
The source code for the actual routines is simply included via the
|
||||||
|
INCLUDE statement.
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
Nothing more is required, we can close the source text for the module.
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
To use a single type of sets in a program, we can just use the
|
||||||
|
MYDATA_SETS module. If you need more than one type of data in sets,
|
||||||
|
then apply the same renaming trick on using the specific set
|
||||||
|
modules.
|
||||||
|
|
||||||
|
[para]
|
||||||
|
In fact the example in the source file "two_lists.f90" shows the general
|
||||||
|
technique of how to accomplish this.
|
||||||
|
|
||||||
|
[section ROUTINES]
|
||||||
|
The source file [strong "sets.f90"] provides the following
|
||||||
|
routines:
|
||||||
|
|
||||||
|
[list_begin definitions]
|
||||||
|
|
||||||
|
[call [cmd "call set_create( dataset )"]]
|
||||||
|
Create a new empty set.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(SET)" dataset]
|
||||||
|
The variable that will be used for accessing the set
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call set_destroy( dataset )"]]
|
||||||
|
Destroy the set. All elements contained in it will be destroyed as
|
||||||
|
well.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(SET)" dataset]
|
||||||
|
The set to be destroyed
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "size = set_size( dataset )"]]
|
||||||
|
Function to return the number of elements in the set.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(SET)" dataset]
|
||||||
|
The set in question
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call set_add( dataset, elem )"]]
|
||||||
|
Insert a new element in the set. If the element is already present,
|
||||||
|
nothing is done.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(SET)" dataset]
|
||||||
|
The dataset to add the element to.
|
||||||
|
|
||||||
|
[arg_def "type(SET_DATA), intent(in)" elem]
|
||||||
|
The element to be stored
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call set_delete_element( dataset, elem )"]]
|
||||||
|
Delete the given element from the set.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(SET)" dataset]
|
||||||
|
The list in question
|
||||||
|
[arg_def "type(SET_DATA)" elem]
|
||||||
|
The element to be deleted
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "has = set_haselement( dataset, elem )"]]
|
||||||
|
Returns whether or not the given element is in the set.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(SET)" dataset]
|
||||||
|
The set in question
|
||||||
|
[arg_def "type(SET_DATA)" elem]
|
||||||
|
The element to be checked
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "has = elem .elementof. dataset"]]
|
||||||
|
Returns whether or not the given element is in the set.
|
||||||
|
(The operator version)
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(SET)" dataset]
|
||||||
|
The set in question
|
||||||
|
[arg_def "type(SET_DATA)" elem]
|
||||||
|
The element to be checked
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "equal = set_equal( set1, set2 )"]]
|
||||||
|
Returns whether or not the two sets contain the same elements.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(SET)" set1]
|
||||||
|
The first set
|
||||||
|
[arg_def "type(SET)" set2]
|
||||||
|
The second set
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "equal = set1 .eq. set2"]]
|
||||||
|
Returns whether or not the two sets contain the same elements.
|
||||||
|
(The operator version)
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "notequal = set_notequal( set1, set2 )"]]
|
||||||
|
Returns whether or not the two sets do not contain the same elements.
|
||||||
|
(The operator version)
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(SET)" set1]
|
||||||
|
The first set
|
||||||
|
[arg_def "type(SET)" set2]
|
||||||
|
The second set
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "notequal = set1 .ne. set2"]]
|
||||||
|
Returns whether or not the two sets do not contain the same elements.
|
||||||
|
(The operator version)
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "has = set_hassubset( dataset, subset )"]]
|
||||||
|
Returns whether or not one set is contained in the other set.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(SET)" dataset]
|
||||||
|
The set that may hold the second one
|
||||||
|
[arg_def "type(SET)" subset]
|
||||||
|
The set that may be a subset of the fist
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "has = subset .subsetof. dataset"]]
|
||||||
|
Returns whether or not one set is contained in the other set.
|
||||||
|
(The operator version)
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(SET)" subset]
|
||||||
|
The set that may be a subset of the other
|
||||||
|
[arg_def "type(SET)" dataset]
|
||||||
|
The set that may hold the first one
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "newset = set_union( set1, set2 )"]]
|
||||||
|
Returns the union of two sets.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(SET)" set1]
|
||||||
|
The first set
|
||||||
|
[arg_def "type(SET)" set2]
|
||||||
|
The second set
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
[call [cmd "newset = set1 .union. set2"]]
|
||||||
|
Returns the union of two sets - operator version.
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "newset = set_intersection( set1, set2 )"]]
|
||||||
|
Returns the intersection of two sets.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(SET)" set1]
|
||||||
|
The first set
|
||||||
|
[arg_def "type(SET)" set2]
|
||||||
|
The second set
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
[call [cmd "newset = set1 .intersect. set2"]]
|
||||||
|
Returns the intersection of two sets - operator version.
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "newset = set_exclusion( set1, set2 )"]]
|
||||||
|
Returns a copy of the first set with the elements of the second set
|
||||||
|
excluded.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "type(SET)" set1]
|
||||||
|
The first set
|
||||||
|
[arg_def "type(SET)" set2]
|
||||||
|
The second set
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
[call [cmd "newset = set1 .intersect. set2"]]
|
||||||
|
Returns a copy of the first set with the elements of the second set
|
||||||
|
excluded - operator version.
|
||||||
|
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
[list_begin bullet]
|
||||||
|
[bullet]
|
||||||
|
The sets can only store data of the same derived type. In that sense
|
||||||
|
the code is not generic.
|
||||||
|
[bullet]
|
||||||
|
Currently, the sets can only store derived types that do not require
|
||||||
|
an explicit destruction. If you want to store a derived type with
|
||||||
|
pointers to allocated memory, you can do that however, by supplying an
|
||||||
|
assignment operator. This would lead to a memory leak though. It is best
|
||||||
|
to wait for the next version which will allow such derived types to be
|
||||||
|
stored.
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
[manpage_end]
|
||||||
BIN
flibs-0.9/flibs/doc/design_patterns_f90.doc
Normal file
BIN
flibs-0.9/flibs/doc/design_patterns_f90.doc
Normal file
Binary file not shown.
5319
flibs-0.9/flibs/doc/design_patterns_f90.pdf
Normal file
5319
flibs-0.9/flibs/doc/design_patterns_f90.pdf
Normal file
File diff suppressed because it is too large
Load Diff
BIN
flibs-0.9/flibs/doc/design_patterns_in_f2003.doc
Normal file
BIN
flibs-0.9/flibs/doc/design_patterns_in_f2003.doc
Normal file
Binary file not shown.
187
flibs-0.9/flibs/doc/filedir/filedir.html
Normal file
187
flibs-0.9/flibs/doc/filedir/filedir.html
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
|
||||||
|
<html><head>
|
||||||
|
<title>flibs/strings - flibs </title>
|
||||||
|
</head>
|
||||||
|
<! -- Generated from file 'filedir.man' by tcllib/doctools with format 'html'
|
||||||
|
-->
|
||||||
|
<! -- Copyright © 2005 Arjen Markus <arjenmarkus@sourceforge.net>
|
||||||
|
-->
|
||||||
|
<! -- CVS: $Id: filedir.html,v 1.1 2008/06/13 10:22:48 relaxmike Exp $ flibs/strings.n
|
||||||
|
-->
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1> flibs/strings(n) 1.0 "flibs"</h1>
|
||||||
|
<h2><a name="name">NAME</a></h2>
|
||||||
|
<p>
|
||||||
|
<p> flibs/strings - Manipulate file and directory names
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h2><a name="table_of_contents">TABLE OF CONTENTS</a></h2>
|
||||||
|
<p> <a href="#table_of_contents">TABLE OF CONTENTS</a><br>
|
||||||
|
<a href="#synopsis">SYNOPSIS</a><br>
|
||||||
|
<a href="#description">DESCRIPTION</a><br>
|
||||||
|
<a href="#routines">ROUTINES</a><br>
|
||||||
|
<a href="#copyright">COPYRIGHT</a><br>
|
||||||
|
<h2><a name="synopsis">SYNOPSIS</a></h2>
|
||||||
|
<p>
|
||||||
|
<table border=1 width=100% cellspacing=0 cellpadding=0><tr bgcolor=lightyellow><td bgcolor=lightyellow><table 0 width=100% cellspacing=0 cellpadding=0><tr valign=top ><td ><a href="#1"><b class='cmd'>use filedir</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#2"><b class='cmd'>rootname = filedir_rootname( filename )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#3"><b class='cmd'>extension = filedir_extension( filename )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#4"><b class='cmd'>basename = filedir_basename( filename )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#5"><b class='cmd'>dirname = filedir_dirname( filename )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#6"><b class='cmd'>dirname = filedir_concat( directory, filename )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#7"><b class='cmd'>newname = filedir_add_extension( filename, extension )</b> </a></td></tr>
|
||||||
|
</table></td></tr></table>
|
||||||
|
<h2><a name="description">DESCRIPTION</a></h2>
|
||||||
|
<p>
|
||||||
|
|
||||||
|
The <em>filedir</em> contains a number of routines to manipulate file
|
||||||
|
and directory names:
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
Strip the extension from a file name and return the "root name".
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
Determine instead the extension from a file name and return that.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
Strip the directory name from the path to the file and return the "base
|
||||||
|
name".
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
Strip the file name from the path to the file and return the
|
||||||
|
directory.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
Concatenate file and directory names.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
Add an extension to a file name.
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
These are all relatively simple routines, but they are fairly common,
|
||||||
|
hence the module.
|
||||||
|
|
||||||
|
|
||||||
|
<h2><a name="routines">ROUTINES</a></h2>
|
||||||
|
<p>
|
||||||
|
The module contains the following routines:
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt><a name="1"><b class='cmd'>use filedir</b> </a><dd>
|
||||||
|
|
||||||
|
To import the subroutines, use this module.
|
||||||
|
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt><a name="2"><b class='cmd'>rootname = filedir_rootname( filename )</b> </a><dd>
|
||||||
|
|
||||||
|
Strips the extension if any off the file name and returns the result.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>character(len=*) <i class='arg'>filename</i><dd>
|
||||||
|
Name of the file
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="3"><b class='cmd'>extension = filedir_extension( filename )</b> </a><dd>
|
||||||
|
|
||||||
|
Returns the extension if any found in a file name
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>character(len=*) <i class='arg'>filename</i><dd>
|
||||||
|
Name of the file
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="4"><b class='cmd'>basename = filedir_basename( filename )</b> </a><dd>
|
||||||
|
|
||||||
|
Returns the base name of a file (so, without the directory part)
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>character(len=*) <i class='arg'>filename</i><dd>
|
||||||
|
Name of the file
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="5"><b class='cmd'>dirname = filedir_dirname( filename )</b> </a><dd>
|
||||||
|
|
||||||
|
Returns the directory part of a file name
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>character(len=*) <i class='arg'>filename</i><dd>
|
||||||
|
Name of the file
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="6"><b class='cmd'>dirname = filedir_concat( directory, filename )</b> </a><dd>
|
||||||
|
|
||||||
|
Prepend the directory to the file name
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>character(len=*) <i class='arg'>directory</i><dd>
|
||||||
|
Directory to prepend
|
||||||
|
<br><br>
|
||||||
|
<dt>character(len=*) <i class='arg'>filename</i><dd>
|
||||||
|
Name of the file
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="7"><b class='cmd'>newname = filedir_add_extension( filename, extension )</b> </a><dd>
|
||||||
|
|
||||||
|
Append an extension to the file name
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt>character(len=*) <i class='arg'>directory</i><dd>
|
||||||
|
Directory to prepend
|
||||||
|
<br><br>
|
||||||
|
<dt>character(len=*) <i class='arg'>filename</i><dd>
|
||||||
|
Name of the file
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<em>Note:</em>
|
||||||
|
The functions all return strings that are large enough to guarantee
|
||||||
|
that the entire result can be hold. In many cases, the length is the
|
||||||
|
same as that of the input argument, but for instance with
|
||||||
|
<em>file_add_extension</em> it is the sum of the lengths of the
|
||||||
|
two arguments plus 1 (for the dot).
|
||||||
|
|
||||||
|
<h2><a name="copyright">COPYRIGHT</a></h2>
|
||||||
|
<p>
|
||||||
|
Copyright © 2005 Arjen Markus <arjenmarkus@sourceforge.net><br>
|
||||||
|
</body></html>
|
||||||
131
flibs-0.9/flibs/doc/filedir/filedir.man
Normal file
131
flibs-0.9/flibs/doc/filedir/filedir.man
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
[comment {-*- flibs -*- doctools manpage}]
|
||||||
|
[manpage_begin flibs/strings n 1.0]
|
||||||
|
[copyright {2005 Arjen Markus <arjenmarkus@sourceforge.net>}]
|
||||||
|
[moddesc flibs]
|
||||||
|
[titledesc {Manipulate file and directory names}]
|
||||||
|
|
||||||
|
[description]
|
||||||
|
|
||||||
|
The [strong filedir] contains a number of routines to manipulate file
|
||||||
|
and directory names:
|
||||||
|
|
||||||
|
[list_begin bullet]
|
||||||
|
[bullet]
|
||||||
|
Strip the extension from a file name and return the "root name".
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
Determine instead the extension from a file name and return that.
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
Strip the directory name from the path to the file and return the "base
|
||||||
|
name".
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
Strip the file name from the path to the file and return the
|
||||||
|
directory.
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
Concatenate file and directory names.
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
Add an extension to a file name.
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
These are all relatively simple routines, but they are fairly common,
|
||||||
|
hence the module.
|
||||||
|
|
||||||
|
|
||||||
|
[section ROUTINES]
|
||||||
|
The module contains the following routines:
|
||||||
|
|
||||||
|
[list_begin definitions]
|
||||||
|
|
||||||
|
[call [cmd "use filedir"]]
|
||||||
|
To import the subroutines, use this module.
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "rootname = filedir_rootname( filename )"]]
|
||||||
|
Strips the extension if any off the file name and returns the result.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "character(len=*)" filename]
|
||||||
|
Name of the file
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "extension = filedir_extension( filename )"]]
|
||||||
|
Returns the extension if any found in a file name
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "character(len=*)" filename]
|
||||||
|
Name of the file
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "basename = filedir_basename( filename )"]]
|
||||||
|
Returns the base name of a file (so, without the directory part)
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "character(len=*)" filename]
|
||||||
|
Name of the file
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "dirname = filedir_dirname( filename )"]]
|
||||||
|
Returns the directory part of a file name
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "character(len=*)" filename]
|
||||||
|
Name of the file
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "dirname = filedir_concat( directory, filename )"]]
|
||||||
|
Prepend the directory to the file name
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "character(len=*)" directory]
|
||||||
|
Directory to prepend
|
||||||
|
[arg_def "character(len=*)" filename]
|
||||||
|
Name of the file
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
[nl]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "newname = filedir_add_extension( filename, extension )"]]
|
||||||
|
Append an extension to the file name
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def "character(len=*)" directory]
|
||||||
|
Directory to prepend
|
||||||
|
[arg_def "character(len=*)" filename]
|
||||||
|
Name of the file
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
[strong Note:]
|
||||||
|
The functions all return strings that are large enough to guarantee
|
||||||
|
that the entire result can be hold. In many cases, the length is the
|
||||||
|
same as that of the input argument, but for instance with
|
||||||
|
[strong file_add_extension] it is the sum of the lengths of the
|
||||||
|
two arguments plus 1 (for the dot).
|
||||||
|
|
||||||
|
[manpage_end]
|
||||||
179
flibs-0.9/flibs/doc/filedir/m_fileunit.html
Normal file
179
flibs-0.9/flibs/doc/filedir/m_fileunit.html
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
|
||||||
|
<html><head>
|
||||||
|
<title>flibs/m_fileunit - flibs </title>
|
||||||
|
</head>
|
||||||
|
<! -- Generated from file 'filedir/m_fileunit.man' by tcllib/doctools with format 'html'
|
||||||
|
-->
|
||||||
|
<! -- Copyright © 2008 Michael Baudin michael.baudin@gmail.com
|
||||||
|
-->
|
||||||
|
<! -- CVS: $Id: m_fileunit.html,v 1.2 2008/06/17 12:44:21 relaxmike Exp $ flibs/m_fileunit.n
|
||||||
|
-->
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1> flibs/m_fileunit(n) 1.0 "flibs"</h1>
|
||||||
|
<h2><a name="name">NAME</a></h2>
|
||||||
|
<p>
|
||||||
|
<p> flibs/m_fileunit - Manage file units
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h2><a name="table_of_contents">TABLE OF CONTENTS</a></h2>
|
||||||
|
<p> <a href="#table_of_contents">TABLE OF CONTENTS</a><br>
|
||||||
|
<a href="#synopsis">SYNOPSIS</a><br>
|
||||||
|
<a href="#description">DESCRIPTION</a><br>
|
||||||
|
<a href="#overview">OVERVIEW</a><br>
|
||||||
|
<a href="#routines">ROUTINES</a><br>
|
||||||
|
<a href="#todo">TODO</a><br>
|
||||||
|
<a href="#copyright">COPYRIGHT</a><br>
|
||||||
|
<h2><a name="synopsis">SYNOPSIS</a></h2>
|
||||||
|
<p>
|
||||||
|
<table border=1 width=100% cellspacing=0 cellpadding=0><tr bgcolor=lightyellow><td bgcolor=lightyellow><table 0 width=100% cellspacing=0 cellpadding=0><tr valign=top ><td ><a href="#1"><strong>fileunit_getallopen</strong> ( <i class='arg'>nbunits</i> <i class='arg'>, units</i> )</a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#2"><strong>fileunit_displayopen</strong> ( <i class='arg'>reportunitnumber</i> )</a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#3"><strong>fileunit_report</strong> ( <i class='arg'>reportunitnumber</i> <i class='arg'>iunit</i>)</a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#4"><strong>fileunit_closeallopen</strong> ( )</a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#5"><strong>fileunit_getfreeunit</strong> ( ) result ( freeunit )</a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#6"><strong>fileunit_set_stoponerror</strong> ( <i class='arg'>stoponerror</i>)</a></td></tr>
|
||||||
|
</table></td></tr></table>
|
||||||
|
<h2><a name="description">DESCRIPTION</a></h2>
|
||||||
|
<p>
|
||||||
|
|
||||||
|
The component <em>m_fileunit</em> provides services to manage fortran file units.
|
||||||
|
|
||||||
|
<h2><a name="overview">OVERVIEW</a></h2>
|
||||||
|
<p>
|
||||||
|
|
||||||
|
The function fileunit_getfreeunit returns an integer representing
|
||||||
|
a fortran unit which is available for opening a file.
|
||||||
|
The typical use of this function is to manage the files dynamically,
|
||||||
|
without any database of file units in the library/software.
|
||||||
|
In the following example, one opens a file with a dynamical
|
||||||
|
file unit.
|
||||||
|
|
||||||
|
<p><table><tr><td bgcolor=black> </td><td><pre class='sample'>
|
||||||
|
integer :: fileunit
|
||||||
|
fileunit = fileunit_getfreeunit ()
|
||||||
|
open ( unit = fileunit , file = "data.txt" )
|
||||||
|
[lb]etc...[rb]
|
||||||
|
</pre></td></tr></table></p>
|
||||||
|
|
||||||
|
If several files are to be opened, the "fileunit_getfreeunit"
|
||||||
|
method has to be inserted between the "open" statements.
|
||||||
|
This is because two consecutive calls to "fileunit_getfreeunit"
|
||||||
|
will return the same integer, as expected : if a unit is available
|
||||||
|
the first time, it will also be available the second time.
|
||||||
|
In the following example, several files are opened and connected
|
||||||
|
to several files.
|
||||||
|
|
||||||
|
<p><table><tr><td bgcolor=black> </td><td><pre class='sample'>
|
||||||
|
integer :: fileunit1
|
||||||
|
integer :: fileunit2
|
||||||
|
fileunit1 = fileunit_getfreeunit ()
|
||||||
|
open ( unit = fileunit1 , file = "data.txt" )
|
||||||
|
fileunit2 = fileunit_getfreeunit ()
|
||||||
|
open ( unit = fileunit2 , file = "data2.txt" )
|
||||||
|
[lb]etc...[rb]
|
||||||
|
</pre></td></tr></table></p>
|
||||||
|
|
||||||
|
In a large fortran software, it may be difficult to see if some
|
||||||
|
bug has been introduced in the file management, especially
|
||||||
|
when the software is the composition of several libraries.
|
||||||
|
The subroutines fileunit_getallopen , fileunit_closeallopen ,
|
||||||
|
fileunit_report , fileunit_displayopen allow to manage for
|
||||||
|
the units currently used in the software.
|
||||||
|
The fileunit_getallopen returns an array of integers which
|
||||||
|
contains all the currently opened units. The fileunit_closeallopen
|
||||||
|
subroutine close all currently opened units. The fileunit_report
|
||||||
|
displays a full report about a given unit number by using the
|
||||||
|
"inquire" fortran intrinsic statement.
|
||||||
|
|
||||||
|
<h2><a name="routines">ROUTINES</a></h2>
|
||||||
|
<p>
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt><a name="1"><strong>fileunit_getallopen</strong> ( <i class='arg'>nbunits</i> <i class='arg'>, units</i> )</a><dd>
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
<dt><strong>integer, intent ( out ) ::</strong> <i class='arg'>nbunits</i><dd>
|
||||||
|
<dt><strong>integer , dimension(:) , pointer ::</strong> <i class='arg'>units</i><dd>
|
||||||
|
</dl>
|
||||||
|
Computes an array of integers made of all currently opened units.
|
||||||
|
On output, <i class='arg'>nbunits</i> is the number of opened units and
|
||||||
|
<i class='arg'>units ( iunit )</i> is the unit number for the opened unit #iunit
|
||||||
|
with 1<= iunit <= nbunits.
|
||||||
|
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt><a name="2"><strong>fileunit_displayopen</strong> ( <i class='arg'>reportunitnumber</i> )</a><dd>
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
<dt><strong>integer, intent ( in ) ::</strong> <i class='arg'>reportunitnumber</i><dd>
|
||||||
|
</dl>
|
||||||
|
Writes on unit <i class='arg'>unitnumber</i> the full list of opened units and their associated
|
||||||
|
filenames.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt><a name="3"><strong>fileunit_report</strong> ( <i class='arg'>reportunitnumber</i> <i class='arg'>iunit</i>)</a><dd>
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
<dt><strong>integer, intent ( in ) ::</strong> <i class='arg'>reportunitnumber</i><dd>
|
||||||
|
<dt><strong>integer, intent ( in ) ::</strong> <i class='arg'>iunit</i><dd>
|
||||||
|
</dl>
|
||||||
|
Compute report about logical unit <i class='arg'>iunit</i> and write it on
|
||||||
|
unit <i class='arg'>unitnumber</i>. Note : All possible features of the "inquire" intrinsic are used.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt><a name="4"><strong>fileunit_closeallopen</strong> ( )</a><dd>
|
||||||
|
|
||||||
|
Close all currently opened units.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt><a name="5"><strong>fileunit_getfreeunit</strong> ( ) result ( freeunit )</a><dd>
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
<dt><strong>integer ::</strong> <i class='arg'>freeunit</i><dd>
|
||||||
|
</dl>
|
||||||
|
Returns a free fortran unit <i class='arg'>freeunit</i> as an integer between 1 and FILEUNIT_MAX_UNIT_NUMBER,
|
||||||
|
representing a free FORTRAN logical unit.
|
||||||
|
If no free unit can be found, generates an error.
|
||||||
|
Note that fileunit_getfreeunit assumes that units 5 and 6
|
||||||
|
are special, and will never return those values.
|
||||||
|
Original Author : John Burkardt
|
||||||
|
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt><a name="6"><strong>fileunit_set_stoponerror</strong> ( <i class='arg'>stoponerror</i>)</a><dd>
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
<dt><strong>integer ::</strong> <i class='arg'>freeunit</i><dd>
|
||||||
|
</dl>
|
||||||
|
Configure the behaviour of the component whenever an
|
||||||
|
error is met.
|
||||||
|
If <i class='arg'>stoponerror</i> is true, then the execution stops if an error is encountered.
|
||||||
|
If <i class='arg'>stoponerror</i> is false, then the execution continues if an error is encountered.
|
||||||
|
In both cases, a message is displayed on standard output.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<h2><a name="todo">TODO</a></h2>
|
||||||
|
<p>
|
||||||
|
<ul>
|
||||||
|
<li> allow to "lock" a collection of logical units, so that an
|
||||||
|
external library which may use constant units can be linked.
|
||||||
|
<br><br>
|
||||||
|
<li> allow to "unlock" one unit, or all units at once.
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2><a name="copyright">COPYRIGHT</a></h2>
|
||||||
|
<p>
|
||||||
|
Copyright © 2008 Michael Baudin michael.baudin@gmail.com<br>
|
||||||
|
</body></html>
|
||||||
129
flibs-0.9/flibs/doc/filedir/m_fileunit.man
Normal file
129
flibs-0.9/flibs/doc/filedir/m_fileunit.man
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
[comment {-*- flibs -*- doctools manpage}]
|
||||||
|
[manpage_begin flibs/m_fileunit n 1.0]
|
||||||
|
[copyright {2008 Michael Baudin michael.baudin@gmail.com}]
|
||||||
|
[moddesc flibs]
|
||||||
|
[titledesc {Manage file units}]
|
||||||
|
|
||||||
|
[description]
|
||||||
|
|
||||||
|
The component [strong m_fileunit] provides services to manage fortran file units.
|
||||||
|
|
||||||
|
[section OVERVIEW]
|
||||||
|
|
||||||
|
The function fileunit_getfreeunit returns an integer representing
|
||||||
|
a fortran unit which is available for opening a file.
|
||||||
|
The typical use of this function is to manage the files dynamically,
|
||||||
|
without any database of file units in the library/software.
|
||||||
|
In the following example, one opens a file with a dynamical
|
||||||
|
file unit.
|
||||||
|
|
||||||
|
[example {
|
||||||
|
integer :: fileunit
|
||||||
|
fileunit = fileunit_getfreeunit ()
|
||||||
|
open ( unit = fileunit , file = "data.txt" )
|
||||||
|
[lb]etc...[rb]
|
||||||
|
}]
|
||||||
|
|
||||||
|
If several files are to be opened, the "fileunit_getfreeunit"
|
||||||
|
method has to be inserted between the "open" statements.
|
||||||
|
This is because two consecutive calls to "fileunit_getfreeunit"
|
||||||
|
will return the same integer, as expected : if a unit is available
|
||||||
|
the first time, it will also be available the second time.
|
||||||
|
In the following example, several files are opened and connected
|
||||||
|
to several files.
|
||||||
|
|
||||||
|
[example {
|
||||||
|
integer :: fileunit1
|
||||||
|
integer :: fileunit2
|
||||||
|
fileunit1 = fileunit_getfreeunit ()
|
||||||
|
open ( unit = fileunit1 , file = "data.txt" )
|
||||||
|
fileunit2 = fileunit_getfreeunit ()
|
||||||
|
open ( unit = fileunit2 , file = "data2.txt" )
|
||||||
|
[lb]etc...[rb]
|
||||||
|
}]
|
||||||
|
|
||||||
|
In a large fortran software, it may be difficult to see if some
|
||||||
|
bug has been introduced in the file management, especially
|
||||||
|
when the software is the composition of several libraries.
|
||||||
|
The subroutines fileunit_getallopen , fileunit_closeallopen ,
|
||||||
|
fileunit_report , fileunit_displayopen allow to manage for
|
||||||
|
the units currently used in the software.
|
||||||
|
The fileunit_getallopen returns an array of integers which
|
||||||
|
contains all the currently opened units. The fileunit_closeallopen
|
||||||
|
subroutine close all currently opened units. The fileunit_report
|
||||||
|
displays a full report about a given unit number by using the
|
||||||
|
"inquire" fortran intrinsic statement.
|
||||||
|
|
||||||
|
[section ROUTINES]
|
||||||
|
|
||||||
|
[list_begin definitions]
|
||||||
|
|
||||||
|
[call [method "fileunit_getallopen"] ( [arg nbunits] [arg ", units"] )]
|
||||||
|
[list_begin arg]
|
||||||
|
[arg_def [type "integer, intent ( out ) ::"] nbunits]
|
||||||
|
[arg_def [type "integer , dimension(:) , pointer ::"] units]
|
||||||
|
[list_end]
|
||||||
|
Computes an array of integers made of all currently opened units.
|
||||||
|
On output, [arg nbunits] is the number of opened units and
|
||||||
|
[arg "units ( iunit )"] is the unit number for the opened unit #iunit
|
||||||
|
with 1<= iunit <= nbunits.
|
||||||
|
|
||||||
|
|
||||||
|
[call [method "fileunit_displayopen"] ( [arg reportunitnumber] )]
|
||||||
|
[list_begin arg]
|
||||||
|
[arg_def [type "integer, intent ( in ) ::"] reportunitnumber]
|
||||||
|
[list_end]
|
||||||
|
Writes on unit [arg unitnumber] the full list of opened units and their associated
|
||||||
|
filenames.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[call [method "fileunit_report"] ( [arg reportunitnumber] [arg iunit])]
|
||||||
|
[list_begin arg]
|
||||||
|
[arg_def [type "integer, intent ( in ) ::"] reportunitnumber]
|
||||||
|
[arg_def [type "integer, intent ( in ) ::"] iunit]
|
||||||
|
[list_end]
|
||||||
|
Compute report about logical unit [arg iunit] and write it on
|
||||||
|
unit [arg unitnumber]. Note : All possible features of the "inquire" intrinsic are used.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[call [method "fileunit_closeallopen"] ( )]
|
||||||
|
Close all currently opened units.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[call [method "fileunit_getfreeunit"] ( ) result ( freeunit )]
|
||||||
|
[list_begin arg]
|
||||||
|
[arg_def [type "integer ::"] freeunit]
|
||||||
|
[list_end]
|
||||||
|
Returns a free fortran unit [arg freeunit] as an integer between 1 and FILEUNIT_MAX_UNIT_NUMBER,
|
||||||
|
representing a free FORTRAN logical unit.
|
||||||
|
If no free unit can be found, generates an error.
|
||||||
|
Note that fileunit_getfreeunit assumes that units 5 and 6
|
||||||
|
are special, and will never return those values.
|
||||||
|
Original Author : John Burkardt
|
||||||
|
|
||||||
|
|
||||||
|
[call [method "fileunit_set_stoponerror"] ( [arg stoponerror])]
|
||||||
|
[list_begin arg]
|
||||||
|
[arg_def [type "integer ::"] freeunit]
|
||||||
|
[list_end]
|
||||||
|
Configure the behaviour of the component whenever an
|
||||||
|
error is met.
|
||||||
|
If [arg stoponerror] is true, then the execution stops if an error is encountered.
|
||||||
|
If [arg stoponerror] is false, then the execution continues if an error is encountered.
|
||||||
|
In both cases, a message is displayed on standard output.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
[section TODO]
|
||||||
|
[list_begin bullet]
|
||||||
|
[bullet] allow to "lock" a collection of logical units, so that an
|
||||||
|
external library which may use constant units can be linked.
|
||||||
|
[bullet] allow to "unlock" one unit, or all units at once.
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
[manpage_end]
|
||||||
1381
flibs-0.9/flibs/doc/filedir/m_vfile.html
Normal file
1381
flibs-0.9/flibs/doc/filedir/m_vfile.html
Normal file
File diff suppressed because it is too large
Load Diff
1109
flibs-0.9/flibs/doc/filedir/m_vfile.man
Normal file
1109
flibs-0.9/flibs/doc/filedir/m_vfile.man
Normal file
File diff suppressed because it is too large
Load Diff
586
flibs-0.9/flibs/doc/funit/ftnunit.html
Normal file
586
flibs-0.9/flibs/doc/funit/ftnunit.html
Normal file
@@ -0,0 +1,586 @@
|
|||||||
|
|
||||||
|
<html><head>
|
||||||
|
<title>flibs/ftnunit - flibs </title>
|
||||||
|
</head>
|
||||||
|
<! -- Generated from file 'ftnunit.man' by tcllib/doctools with format 'html'
|
||||||
|
-->
|
||||||
|
<! -- Copyright © 2006 Arjen Markus <arjenmarkus@sourceforge.net>
|
||||||
|
-->
|
||||||
|
<! -- CVS: $Id: ftnunit.html,v 1.1 2008/06/13 10:30:53 relaxmike Exp $ flibs/ftnunit.n
|
||||||
|
-->
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1> flibs/ftnunit(n) 1.1 "flibs"</h1>
|
||||||
|
<h2><a name="name">NAME</a></h2>
|
||||||
|
<p>
|
||||||
|
<p> flibs/ftnunit - Unit testing
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h2><a name="table_of_contents">TABLE OF CONTENTS</a></h2>
|
||||||
|
<p> <a href="#table_of_contents">TABLE OF CONTENTS</a><br>
|
||||||
|
<a href="#synopsis">SYNOPSIS</a><br>
|
||||||
|
<a href="#description">DESCRIPTION</a><br>
|
||||||
|
<a href="#routines">ROUTINES</a><br>
|
||||||
|
<a href="#generating_tests_from_a_table">GENERATING TESTS FROM A TABLE</a><br>
|
||||||
|
<a href="#todo">TODO</a><br>
|
||||||
|
<a href="#related_work">RELATED WORK</a><br>
|
||||||
|
<a href="#copyright">COPYRIGHT</a><br>
|
||||||
|
<h2><a name="synopsis">SYNOPSIS</a></h2>
|
||||||
|
<p>
|
||||||
|
<table border=1 width=100% cellspacing=0 cellpadding=0><tr bgcolor=lightyellow><td bgcolor=lightyellow><table 0 width=100% cellspacing=0 cellpadding=0><tr valign=top ><td ><a href="#1">runtests.bat </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#2">runtests.sh </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#3">runtests.tcl </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#4"><b class='cmd'>call runtests( testproc )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#5"><b class='cmd'>call runtests_init</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#6"><b class='cmd'>call runtests_final</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#7"><b class='cmd'>call test( proc, text )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#8"><b class='cmd'>call assert_true( cond, text )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#9"><b class='cmd'>call assert_false( cond, text )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#10"><b class='cmd'>call assert_equal( value1, value2, text )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#11"><b class='cmd'>call assert_comparable( value1, value2, margin, text )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#12"><b class='cmd'>exists = ftnunit_file_exists( filename )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#13"><b class='cmd'>call ftnunit_get_lun( lun )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#14"><b class='cmd'>call ftnunit_remove_file( filename )</b> </a></td></tr>
|
||||||
|
<tr valign=top ><td ><a href="#15"><b class='cmd'>call ftnunit_make_empty_file( filename )</b> </a></td></tr>
|
||||||
|
</table></td></tr></table>
|
||||||
|
<h2><a name="description">DESCRIPTION</a></h2>
|
||||||
|
<p>
|
||||||
|
|
||||||
|
<em>JUnit</em> is a well-known facility for defining and running unit
|
||||||
|
tests in Java programs. The <em>ftnunit</em> framework was inspired by
|
||||||
|
that facility. It is not as good-looking as JUnit, by no means:
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
It has no graphical user-interface
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
As Fortran does not allow introspection, the test routines can not
|
||||||
|
be detected automatically, instead as a programmer you need to set up a
|
||||||
|
high-level routine yourself that collects all the unit tests.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
A runtime error, like division by zero, may lead to a termination of
|
||||||
|
the program. There is no (portable) way to catch these. Instead, the
|
||||||
|
framework relies on a batch file or shell script to repeatedly start the
|
||||||
|
program until all tests are run.
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
Despite these limitations, <em>ftnunit</em> can be a great help:
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
The Tcl program <em>gentabletest.tcl</em> generates a complete test program based
|
||||||
|
on a simple input file (see <a href="#generating_tests_from_a_table">GENERATING TESTS FROM A TABLE</a>).
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
The code to test the various components (subroutines, functions, tasks
|
||||||
|
consisting of several program units) can be combined with the program
|
||||||
|
itself, without interfering with the ordinary code.
|
||||||
|
<br><br>
|
||||||
|
This is achieved by defining a single routine (test_all, say) that runs
|
||||||
|
all the unit tests and that is called via the provided routine
|
||||||
|
<em>runtests</em>:
|
||||||
|
|
||||||
|
<p><table><tr><td bgcolor=black> </td><td><pre class='sample'>
|
||||||
|
program myprog
|
||||||
|
...
|
||||||
|
!
|
||||||
|
! The routine runtests will check if unit tests are requested
|
||||||
|
! If not, it will return immediately. This way we make sure
|
||||||
|
! the unit tests remain part of the program.
|
||||||
|
!
|
||||||
|
! The routine test_all runs all unit tests
|
||||||
|
! (see the dataproc_testing module)
|
||||||
|
!
|
||||||
|
call runtests( test_all )
|
||||||
|
!
|
||||||
|
! Ordinary processing
|
||||||
|
!
|
||||||
|
...
|
||||||
|
|
||||||
|
end program
|
||||||
|
</pre></td></tr></table></p>
|
||||||
|
|
||||||
|
The routine runtests checks if there is a file "ftnunit.run". If there is
|
||||||
|
such a file, it will run the given subroutine. Otherwise it will return
|
||||||
|
and the rest of the program is executed.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
Because the test code is incorporated in the program itself, it is less
|
||||||
|
likely that they evolve independently: changes in the argument lists of
|
||||||
|
the subroutines and functions may lead to compile errors in the test
|
||||||
|
code.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
There is no need to set up a whole new program for testing portions of
|
||||||
|
the program.
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
The source file "test_ftnunit.f90" illustrates how to use the ftnunit
|
||||||
|
framework:
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
The main program calls the routine "runtests" and passes it the argument
|
||||||
|
"test_all", a routine defined in a module called "dataproc_testing".
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
The routine "test_all" consists of nothing but calls to the generic
|
||||||
|
routine "test":
|
||||||
|
|
||||||
|
<p><table><tr><td bgcolor=black> </td><td><pre class='sample'>
|
||||||
|
subroutine test_all
|
||||||
|
|
||||||
|
call test( test_no_file, "Read non-existent file" )
|
||||||
|
call test( test_empty_file, "Read an empty file" )
|
||||||
|
call test( test_invalid_file, "Read an invalid file" )
|
||||||
|
call test( test_ordinary_file, "Read an ordinary file" )
|
||||||
|
|
||||||
|
end subroutine test_all
|
||||||
|
</pre></td></tr></table></p>
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
The module includes a source file "ftnunit_test.f90". This is a remnant
|
||||||
|
of a previous version. Please ignore this.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
The generic routine "test" checks whether a particular unit
|
||||||
|
test needs to be run (via the test number) and then runs the subroutine
|
||||||
|
that was passed as one of its arguments. One such routine looks like
|
||||||
|
this:
|
||||||
|
|
||||||
|
<p><table><tr><td bgcolor=black> </td><td><pre class='sample'>
|
||||||
|
subroutine test_no_file
|
||||||
|
|
||||||
|
integer :: nodata
|
||||||
|
real :: vmean, vmin, vmax
|
||||||
|
|
||||||
|
call ftnunit_remove_file( 'no_such_file' )
|
||||||
|
call write_name( 'no_such_file' )
|
||||||
|
|
||||||
|
call open_files
|
||||||
|
call process_data( nodata, vmean, vmax, vmin )
|
||||||
|
|
||||||
|
call assert_true( nodata == 0, "No data read" )
|
||||||
|
|
||||||
|
end subroutine test_no_file
|
||||||
|
</pre></td></tr></table></p>
|
||||||
|
|
||||||
|
The assertion is used to check that the result is as expected.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
The program contains some deliberate errors and the resulting
|
||||||
|
log file looks like this":
|
||||||
|
|
||||||
|
<p><table><tr><td bgcolor=black> </td><td><pre class='sample'>
|
||||||
|
Test: Read non-existent file
|
||||||
|
Test: Read an empty file
|
||||||
|
Test: Read an invalid file
|
||||||
|
forrtl: severe (59): list-directed I/O syntax error, unit 11, file c:\arjen\flibs\tests\ftnunit\invalid_file
|
||||||
|
|
||||||
|
Image PC Routine Line Source
|
||||||
|
test_ftnunit.exe 004151B9 Unknown Unknown Unknown
|
||||||
|
test_ftnunit.exe 00415017 Unknown Unknown Unknown
|
||||||
|
test_ftnunit.exe 004141F4 Unknown Unknown Unknown
|
||||||
|
test_ftnunit.exe 00414629 Unknown Unknown Unknown
|
||||||
|
test_ftnunit.exe 00409C05 Unknown Unknown Unknown
|
||||||
|
test_ftnunit.exe 004095FB Unknown Unknown Unknown
|
||||||
|
test_ftnunit.exe 0040144B Unknown Unknown Unknown
|
||||||
|
test_ftnunit.exe 00401FE9 Unknown Unknown Unknown
|
||||||
|
test_ftnunit.exe 00401A2C Unknown Unknown Unknown
|
||||||
|
test_ftnunit.exe 00401BB3 Unknown Unknown Unknown
|
||||||
|
test_ftnunit.exe 0040294A Unknown Unknown Unknown
|
||||||
|
test_ftnunit.exe 0040232E Unknown Unknown Unknown
|
||||||
|
test_ftnunit.exe 0044A1E9 Unknown Unknown Unknown
|
||||||
|
test_ftnunit.exe 00433519 Unknown Unknown Unknown
|
||||||
|
kernel32.dll 7C816D4F Unknown Unknown Unknown
|
||||||
|
|
||||||
|
Incrementally linked image--PC correlation disabled.
|
||||||
|
Test: Read an ordinary file
|
||||||
|
Number of failed assertions: 0
|
||||||
|
Number of runs needed to complete the tests: 3
|
||||||
|
</pre></td></tr></table></p>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
The program is run via one of the following files:
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt><a name="1">runtests.bat </a><dd>
|
||||||
|
|
||||||
|
A batch file for use under MS Windows
|
||||||
|
<br><br>
|
||||||
|
<dt><a name="2">runtests.sh </a><dd>
|
||||||
|
|
||||||
|
A Bourne shell script for use under UNIX/Linux or similar systems, like
|
||||||
|
Cygwin or Mingw.
|
||||||
|
<br><br>
|
||||||
|
<dt><a name="3">runtests.tcl </a><dd>
|
||||||
|
|
||||||
|
A Tcl program that presents a simple graphical user-interface
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<h2><a name="routines">ROUTINES</a></h2>
|
||||||
|
<p>
|
||||||
|
The module ftnunit contains the following subroutines and functions:
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
|
||||||
|
<dt><a name="4"><b class='cmd'>call runtests( testproc )</b> </a><dd>
|
||||||
|
|
||||||
|
Routine to start the unit tests. It checks if the file "ftnunit.run"
|
||||||
|
exists. If so, it will call the subroutine <em>testproc</em> that was
|
||||||
|
passed. Otherwise it will simply return, so that the ordinary program
|
||||||
|
execution may continue.
|
||||||
|
<br><br>
|
||||||
|
If the subroutine testproc returns, the program stops, unless you have
|
||||||
|
called the subroutine <em>runtests_init</em> before <em>runtests</em>.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt><a name="5"><b class='cmd'>call runtests_init</b> </a><dd>
|
||||||
|
|
||||||
|
Routine to initialise the ftnunit system, so that you call <em>runtests</em>
|
||||||
|
more than once. To complete the tests, call <em>runtests_final</em>, as
|
||||||
|
this will print the final statistics and stop the program.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt><a name="6"><b class='cmd'>call runtests_final</b> </a><dd>
|
||||||
|
|
||||||
|
Routine to finalise the ftnunit system: it will print the final statistics
|
||||||
|
and stop the program, but only if the file "ftnunit.run" is present.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
<dt>subroutine <i class='arg'>testproc</i><dd>
|
||||||
|
Subroutine that calls the individual test routines. It takes no
|
||||||
|
arguments. It wil generally exist of a series of calls to the
|
||||||
|
routine <em>test</em> - see below.
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="7"><b class='cmd'>call test( proc, text )</b> </a><dd>
|
||||||
|
|
||||||
|
Routine to run the individual unit test routine (emph proc). It decides
|
||||||
|
if the test has not run yet and if so, the test routine is called.
|
||||||
|
Otherwise it is skipped.
|
||||||
|
<br><br>
|
||||||
|
<em>test</em> takes care of all administrative details.
|
||||||
|
<br><br>
|
||||||
|
Note: to make it possible to use <em>private</em> unit test routines,
|
||||||
|
the source code of this subroutine is kept in a separate file,
|
||||||
|
<em>ftnunit_test.f90</em> that should be included in an appropriate
|
||||||
|
place in the program's sources. This way, you can make it a private
|
||||||
|
routine in each module. The only public access to the unit testing
|
||||||
|
routines is then via the subroutine <em>testproc</em> that is passed to
|
||||||
|
<em>runtests</em>.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
<dt>subroutine <i class='arg'>proc</i><dd>
|
||||||
|
Subroutine that implements an individual unit test. It takes no
|
||||||
|
arguments. Within each such subroutine the complete unit test is run.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>character(len=*), intent(in) <i class='arg'>text</i><dd>
|
||||||
|
Text describing the particular unit test. It is printed in the log
|
||||||
|
file.
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="8"><b class='cmd'>call assert_true( cond, text )</b> </a><dd>
|
||||||
|
|
||||||
|
Routine to check that a condition is true. If not, a message is printed
|
||||||
|
in the log file and the number of failures is increased.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
<dt>logical <i class='arg'>cond</i><dd>
|
||||||
|
The condition to be checked
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>character(len=*), intent(in) <i class='arg'>text</i><dd>
|
||||||
|
Text describing the condition
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="9"><b class='cmd'>call assert_false( cond, text )</b> </a><dd>
|
||||||
|
|
||||||
|
Routine to check that a condition is false. If not, a message is
|
||||||
|
printed in the log file and the number of failures is increased.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
<dt>logical <i class='arg'>cond</i><dd>
|
||||||
|
The condition to be checked
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>character(len=*), intent(in) <i class='arg'>text</i><dd>
|
||||||
|
Text describing the condition
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="10"><b class='cmd'>call assert_equal( value1, value2, text )</b> </a><dd>
|
||||||
|
|
||||||
|
Routine to check that two integers are equal or if two one-dimensional
|
||||||
|
integer arrays are equal. If not, a message is printed, along with the
|
||||||
|
values that were different.
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
<dt>integer [, dimension(:)] <i class='arg'>value1</i><dd>
|
||||||
|
The first integer value or array
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>integer [, dimension(:)] <i class='arg'>value2</i><dd>
|
||||||
|
The second integer value or array
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>character(len=*), intent(in) <i class='arg'>text</i><dd>
|
||||||
|
Text describing the condition
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="11"><b class='cmd'>call assert_comparable( value1, value2, margin, text )</b> </a><dd>
|
||||||
|
|
||||||
|
Routine to check that two reals are almost equal or if two one-dimensional
|
||||||
|
real arrays are almost equal. If not, a message is printed, along with
|
||||||
|
the values that were different.
|
||||||
|
<br><br>
|
||||||
|
The margin is taken as a relative tolerance. Two values are
|
||||||
|
considered almost equal if:
|
||||||
|
<p><table><tr><td bgcolor=black> </td><td><pre class='sample'>
|
||||||
|
abs( v1 - v2 ) < margin * (abs(v1)+abs(v2)) / 2
|
||||||
|
</pre></td></tr></table></p>
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
<dt>real [, dimension(:)] <i class='arg'>value1</i><dd>
|
||||||
|
The first real value or array
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>real [, dimension(:)] <i class='arg'>value2</i><dd>
|
||||||
|
The second real value or array
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dt>character(len=*), intent(in) <i class='arg'>text</i><dd>
|
||||||
|
Text describing the condition
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="12"><b class='cmd'>exists = ftnunit_file_exists( filename )</b> </a><dd>
|
||||||
|
|
||||||
|
Logical function to check that a particular file exists
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
<dt>character(len=*), intent(in) <i class='arg'>filename</i><dd>
|
||||||
|
Name of the file to be checked
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="13"><b class='cmd'>call ftnunit_get_lun( lun )</b> </a><dd>
|
||||||
|
|
||||||
|
Subroutine to get a free LU-number
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
<dt>integer, intent(out) <i class='arg'>lun</i><dd>
|
||||||
|
Next free LU-number
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="14"><b class='cmd'>call ftnunit_remove_file( filename )</b> </a><dd>
|
||||||
|
|
||||||
|
Subroutine to remove (delete) a file
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
<dt>character(len=*), intent(in) <i class='arg'>filename</i><dd>
|
||||||
|
Name of the file to be removed
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
<dt><a name="15"><b class='cmd'>call ftnunit_make_empty_file( filename )</b> </a><dd>
|
||||||
|
|
||||||
|
Subroutine to make a new, empty file
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<dl>
|
||||||
|
<dt>character(len=*), intent(in) <i class='arg'>filename</i><dd>
|
||||||
|
Name of the file to be created
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
<h2><a name="generating_tests_from_a_table">GENERATING TESTS FROM A TABLE</a></h2>
|
||||||
|
<p>
|
||||||
|
The Tcl program "gentabletest.tcl" reads the test specifications from an
|
||||||
|
input file and generates a complete Fortran program. The ideas from
|
||||||
|
Bil Kleb's "Toward Scientific Numerical Modeling"
|
||||||
|
<a href="ftp://ftp.rta.nato.int/PubFullText/RTO/MP/RTO-MP-AVT-147/RTO-MP-AVT-147-P-17-Kleb.pdf">ftp://ftp.rta.nato.int/PubFullText/RTO/MP/RTO-MP-AVT-147/RTO-MP-AVT-147-P-17-Kleb.pdf</a>
|
||||||
|
were used for the set-up.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
To do: provide a detailed description. For the moment: see <em>example.tbl</em>, including below.
|
||||||
|
|
||||||
|
<p><table><tr><td bgcolor=black> </td><td><pre class='sample'>
|
||||||
|
! Example of generating test code via a table
|
||||||
|
! -------------------------------------------
|
||||||
|
! The routine to be tested determines the minimum oxygen concentration
|
||||||
|
! in a river, based on the Streeter-Phelps model:
|
||||||
|
!
|
||||||
|
! dBOD/dt = -k * BOD
|
||||||
|
!
|
||||||
|
! dO2/dt = -k * BOD + ka * (O2sat-O2) / H
|
||||||
|
!
|
||||||
|
! where
|
||||||
|
! BOD - biological oxygen demand (mg O2/l)
|
||||||
|
! O2 - oxygen concentration (mg O2/l)
|
||||||
|
! O2sat - saturation concentration of oxygen (mg O2/l)
|
||||||
|
! k - decay rate of BOD (1/day)
|
||||||
|
! ka - reareation rate of oxygen (m/day)
|
||||||
|
! H - depth of the river
|
||||||
|
!
|
||||||
|
! We need boundary (initial) conditions for BOD and oxygen and
|
||||||
|
! the equations describe the concentrations of BOD and oxygen in a
|
||||||
|
! packet of water as it flows along the river.
|
||||||
|
!
|
||||||
|
! Note:
|
||||||
|
! It is a very simple model, it is not meant as a realistic
|
||||||
|
! representation.
|
||||||
|
!
|
||||||
|
! The routine simply continues the solution until a minimum is found.
|
||||||
|
! The results are: oxymin and time
|
||||||
|
!
|
||||||
|
!
|
||||||
|
! The keyword DECLARATIONS introduces the declarations we need for the
|
||||||
|
! complete generated code
|
||||||
|
!
|
||||||
|
DECLARATIONS
|
||||||
|
use streeter_phelps
|
||||||
|
real :: bod, oxy
|
||||||
|
real :: k, ka, h, oxysat, dt, oxymin, time
|
||||||
|
!
|
||||||
|
! The keyword CODE introduces the code fragment required to run the
|
||||||
|
! routine or routines. The results and possible checking of error
|
||||||
|
! conditions are separated.
|
||||||
|
!
|
||||||
|
CODE
|
||||||
|
call compute_min_oxygen( bod, oxy, k, ka, h, oxysat, dt, oxymin, time )
|
||||||
|
!
|
||||||
|
! The keyword RESULT indicates which arguments/variables hold the
|
||||||
|
! interesting results. Specify one name per line (you can not currently
|
||||||
|
! use array elements) and the allowed margin (taken as absolute, if
|
||||||
|
! followed by "%" as a percentage)
|
||||||
|
!
|
||||||
|
RESULT
|
||||||
|
oxymin 0.001 ! Minimum oxygen concentration
|
||||||
|
time 0.01% ! Time the minimum is reached
|
||||||
|
|
||||||
|
!
|
||||||
|
! The keyword ERROR is used for a code fragment that checks if the
|
||||||
|
! routine has correctly found an error in the input (that is, some
|
||||||
|
! parameter value is out of range). The code is invoked when any of
|
||||||
|
! result variables in a table entry has the keyword ERROR instead of
|
||||||
|
! a proper value.
|
||||||
|
! Use the subroutine "error" to indicate the correctly reported error
|
||||||
|
! condition.
|
||||||
|
!
|
||||||
|
ERROR
|
||||||
|
if ( time == -999.0 ) then
|
||||||
|
call error
|
||||||
|
endif
|
||||||
|
!
|
||||||
|
! The keyword RANGES specifies that the variables are to be taken
|
||||||
|
! from a uniform or a normal distribution. The generated program will
|
||||||
|
! simply select values at random and run the code with them. The report
|
||||||
|
! consists of the detailed output as well as a summary.
|
||||||
|
!
|
||||||
|
RANGES
|
||||||
|
oxy 10.0 2.0 Uniform ! Name of the variable, the mean and the margin (uniform)
|
||||||
|
! Normal: mean and standard deviation followed by Normal
|
||||||
|
! Note: all parameters must be given!
|
||||||
|
!
|
||||||
|
! The keyword TABLE indicates the beginning of a table of input data and
|
||||||
|
! expected values. The first (non-comment) line contains the names of
|
||||||
|
! the variables as used in the code fragments and all others are the
|
||||||
|
! values expected.
|
||||||
|
!
|
||||||
|
! There are two special values:
|
||||||
|
! ? - indicating an unknown value for result variables and a "do not
|
||||||
|
! care" value for input variables
|
||||||
|
! It is useful to generate a table that does contain the (computed)
|
||||||
|
! results (see the file table.out) or to indicate situations
|
||||||
|
! where one or more input variables are out of range and this
|
||||||
|
! should lead to an error
|
||||||
|
! ERROR - indicating that the entry should cause the routine to be
|
||||||
|
! tested to flag an error condition.
|
||||||
|
!
|
||||||
|
TABLE
|
||||||
|
dt oxy bod oxysat h k ka oxymin time
|
||||||
|
0.1 10 1 10 10 0.1 1.0 10.0 2.0
|
||||||
|
1.0 10 1 10 10 0.1 1.0 ? ?
|
||||||
|
!
|
||||||
|
! This case is unacceptable: time step must be positive
|
||||||
|
0.0 ? ? ? ? ? ? ? ERROR
|
||||||
|
1.0 0. 10 10 10 0.1 1.0 ? ?
|
||||||
|
</pre></td></tr></table></p>
|
||||||
|
|
||||||
|
<h2><a name="todo">TODO</a></h2>
|
||||||
|
<p>
|
||||||
|
The following things are still left to do:
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
Proper inclusion of the routine <em>prolog</em> and <em>epilog</em>
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
Extension of the set of assertion routines
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2><a name="related_work">RELATED WORK</a></h2>
|
||||||
|
<p>
|
||||||
|
There are at least two similar initiatives with regard to a unit testing
|
||||||
|
framework for Fortran:
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="http://nasarb.rubyforge.org">Funit (implemented in Fortran and
|
||||||
|
Ruby)</a> by Bil Kleb and others
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
<a href="http://www.sourceforge.net/projects/pfunit">A framework
|
||||||
|
implemented in Fortran</a> by Brice Womack and Tom Clune
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
<li>
|
||||||
|
<a href="http://www.sourceforge.net/projects/fortranxunit">FRUIT
|
||||||
|
(implemented in Fortran and Ruby)</a> by Andrew Chen
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
(Note: To avoid confusion, I have renamed my original module "funit" to
|
||||||
|
<em>ftnunit</em>)
|
||||||
|
|
||||||
|
<h2><a name="copyright">COPYRIGHT</a></h2>
|
||||||
|
<p>
|
||||||
|
Copyright © 2006 Arjen Markus <arjenmarkus@sourceforge.net><br>
|
||||||
|
</body></html>
|
||||||
489
flibs-0.9/flibs/doc/funit/ftnunit.man
Normal file
489
flibs-0.9/flibs/doc/funit/ftnunit.man
Normal file
@@ -0,0 +1,489 @@
|
|||||||
|
[comment {-*- flibs -*- doctools manpage}]
|
||||||
|
[manpage_begin flibs/ftnunit n 1.1]
|
||||||
|
[copyright {2006 Arjen Markus <arjenmarkus@sourceforge.net>}]
|
||||||
|
[moddesc flibs]
|
||||||
|
[titledesc {Unit testing}]
|
||||||
|
|
||||||
|
[description]
|
||||||
|
|
||||||
|
[emph JUnit] is a well-known facility for defining and running unit
|
||||||
|
tests in Java programs. The [emph ftnunit] framework was inspired by
|
||||||
|
that facility. It is not as good-looking as JUnit, by no means:
|
||||||
|
[list_begin bullet]
|
||||||
|
[bullet]
|
||||||
|
It has no graphical user-interface
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
As Fortran does not allow introspection, the test routines can not
|
||||||
|
be detected automatically, instead as a programmer you need to set up a
|
||||||
|
high-level routine yourself that collects all the unit tests.
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
A runtime error, like division by zero, may lead to a termination of
|
||||||
|
the program. There is no (portable) way to catch these. Instead, the
|
||||||
|
framework relies on a batch file or shell script to repeatedly start the
|
||||||
|
program until all tests are run.
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
Despite these limitations, [emph ftnunit] can be a great help:
|
||||||
|
|
||||||
|
[list_begin bullet]
|
||||||
|
[bullet]
|
||||||
|
The Tcl program [emph gentabletest.tcl] generates a complete test program based
|
||||||
|
on a simple input file (see [sectref "GENERATING TESTS FROM A TABLE"]).
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
The code to test the various components (subroutines, functions, tasks
|
||||||
|
consisting of several program units) can be combined with the program
|
||||||
|
itself, without interfering with the ordinary code.
|
||||||
|
[nl]
|
||||||
|
This is achieved by defining a single routine (test_all, say) that runs
|
||||||
|
all the unit tests and that is called via the provided routine
|
||||||
|
[emph runtests]:
|
||||||
|
|
||||||
|
[example {
|
||||||
|
program myprog
|
||||||
|
...
|
||||||
|
!
|
||||||
|
! The routine runtests will check if unit tests are requested
|
||||||
|
! If not, it will return immediately. This way we make sure
|
||||||
|
! the unit tests remain part of the program.
|
||||||
|
!
|
||||||
|
! The routine test_all runs all unit tests
|
||||||
|
! (see the dataproc_testing module)
|
||||||
|
!
|
||||||
|
call runtests( test_all )
|
||||||
|
!
|
||||||
|
! Ordinary processing
|
||||||
|
!
|
||||||
|
...
|
||||||
|
|
||||||
|
end program
|
||||||
|
}]
|
||||||
|
|
||||||
|
The routine runtests checks if there is a file "ftnunit.run". If there is
|
||||||
|
such a file, it will run the given subroutine. Otherwise it will return
|
||||||
|
and the rest of the program is executed.
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
Because the test code is incorporated in the program itself, it is less
|
||||||
|
likely that they evolve independently: changes in the argument lists of
|
||||||
|
the subroutines and functions may lead to compile errors in the test
|
||||||
|
code.
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
There is no need to set up a whole new program for testing portions of
|
||||||
|
the program.
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
The source file "test_ftnunit.f90" illustrates how to use the ftnunit
|
||||||
|
framework:
|
||||||
|
|
||||||
|
[list_begin bullet]
|
||||||
|
[bullet]
|
||||||
|
The main program calls the routine "runtests" and passes it the argument
|
||||||
|
"test_all", a routine defined in a module called "dataproc_testing".
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
The routine "test_all" consists of nothing but calls to the generic
|
||||||
|
routine "test":
|
||||||
|
|
||||||
|
[example {
|
||||||
|
subroutine test_all
|
||||||
|
|
||||||
|
call test( test_no_file, "Read non-existent file" )
|
||||||
|
call test( test_empty_file, "Read an empty file" )
|
||||||
|
call test( test_invalid_file, "Read an invalid file" )
|
||||||
|
call test( test_ordinary_file, "Read an ordinary file" )
|
||||||
|
|
||||||
|
end subroutine test_all
|
||||||
|
}]
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
The module includes a source file "ftnunit_test.f90". This is a remnant
|
||||||
|
of a previous version. Please ignore this.
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
The generic routine "test" checks whether a particular unit
|
||||||
|
test needs to be run (via the test number) and then runs the subroutine
|
||||||
|
that was passed as one of its arguments. One such routine looks like
|
||||||
|
this:
|
||||||
|
|
||||||
|
[example {
|
||||||
|
subroutine test_no_file
|
||||||
|
|
||||||
|
integer :: nodata
|
||||||
|
real :: vmean, vmin, vmax
|
||||||
|
|
||||||
|
call ftnunit_remove_file( 'no_such_file' )
|
||||||
|
call write_name( 'no_such_file' )
|
||||||
|
|
||||||
|
call open_files
|
||||||
|
call process_data( nodata, vmean, vmax, vmin )
|
||||||
|
|
||||||
|
call assert_true( nodata == 0, "No data read" )
|
||||||
|
|
||||||
|
end subroutine test_no_file
|
||||||
|
}]
|
||||||
|
|
||||||
|
The assertion is used to check that the result is as expected.
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
The program contains some deliberate errors and the resulting
|
||||||
|
log file looks like this":
|
||||||
|
|
||||||
|
[example {
|
||||||
|
Test: Read non-existent file
|
||||||
|
Test: Read an empty file
|
||||||
|
Test: Read an invalid file
|
||||||
|
forrtl: severe (59): list-directed I/O syntax error, unit 11, file c:\arjen\flibs\tests\ftnunit\invalid_file
|
||||||
|
|
||||||
|
Image PC Routine Line Source
|
||||||
|
test_ftnunit.exe 004151B9 Unknown Unknown Unknown
|
||||||
|
test_ftnunit.exe 00415017 Unknown Unknown Unknown
|
||||||
|
test_ftnunit.exe 004141F4 Unknown Unknown Unknown
|
||||||
|
test_ftnunit.exe 00414629 Unknown Unknown Unknown
|
||||||
|
test_ftnunit.exe 00409C05 Unknown Unknown Unknown
|
||||||
|
test_ftnunit.exe 004095FB Unknown Unknown Unknown
|
||||||
|
test_ftnunit.exe 0040144B Unknown Unknown Unknown
|
||||||
|
test_ftnunit.exe 00401FE9 Unknown Unknown Unknown
|
||||||
|
test_ftnunit.exe 00401A2C Unknown Unknown Unknown
|
||||||
|
test_ftnunit.exe 00401BB3 Unknown Unknown Unknown
|
||||||
|
test_ftnunit.exe 0040294A Unknown Unknown Unknown
|
||||||
|
test_ftnunit.exe 0040232E Unknown Unknown Unknown
|
||||||
|
test_ftnunit.exe 0044A1E9 Unknown Unknown Unknown
|
||||||
|
test_ftnunit.exe 00433519 Unknown Unknown Unknown
|
||||||
|
kernel32.dll 7C816D4F Unknown Unknown Unknown
|
||||||
|
|
||||||
|
Incrementally linked image--PC correlation disabled.
|
||||||
|
Test: Read an ordinary file
|
||||||
|
Number of failed assertions: 0
|
||||||
|
Number of runs needed to complete the tests: 3
|
||||||
|
}]
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
The program is run via one of the following files:
|
||||||
|
|
||||||
|
[list_begin definitions]
|
||||||
|
|
||||||
|
[call runtests.bat]
|
||||||
|
A batch file for use under MS Windows
|
||||||
|
[call runtests.sh]
|
||||||
|
A Bourne shell script for use under UNIX/Linux or similar systems, like
|
||||||
|
Cygwin or Mingw.
|
||||||
|
[call runtests.tcl]
|
||||||
|
A Tcl program that presents a simple graphical user-interface
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
[section ROUTINES]
|
||||||
|
The module ftnunit contains the following subroutines and functions:
|
||||||
|
|
||||||
|
[list_begin definitions]
|
||||||
|
|
||||||
|
[call [cmd "call runtests( testproc )"]]
|
||||||
|
Routine to start the unit tests. It checks if the file "ftnunit.run"
|
||||||
|
exists. If so, it will call the subroutine [emph testproc] that was
|
||||||
|
passed. Otherwise it will simply return, so that the ordinary program
|
||||||
|
execution may continue.
|
||||||
|
[nl]
|
||||||
|
If the subroutine testproc returns, the program stops, unless you have
|
||||||
|
called the subroutine [emph runtests_init] before [emph runtests].
|
||||||
|
|
||||||
|
[call [cmd "call runtests_init"]]
|
||||||
|
Routine to initialise the ftnunit system, so that you call [emph runtests]
|
||||||
|
more than once. To complete the tests, call [emph runtests_final], as
|
||||||
|
this will print the final statistics and stop the program.
|
||||||
|
|
||||||
|
[call [cmd "call runtests_final"]]
|
||||||
|
Routine to finalise the ftnunit system: it will print the final statistics
|
||||||
|
and stop the program, but only if the file "ftnunit.run" is present.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
[arg_def "subroutine" testproc]
|
||||||
|
Subroutine that calls the individual test routines. It takes no
|
||||||
|
arguments. It wil generally exist of a series of calls to the
|
||||||
|
routine [emph test] - see below.
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call test( proc, text )"]]
|
||||||
|
Routine to run the individual unit test routine (emph proc). It decides
|
||||||
|
if the test has not run yet and if so, the test routine is called.
|
||||||
|
Otherwise it is skipped.
|
||||||
|
[nl]
|
||||||
|
[emph test] takes care of all administrative details.
|
||||||
|
[nl]
|
||||||
|
Note: to make it possible to use [emph private] unit test routines,
|
||||||
|
the source code of this subroutine is kept in a separate file,
|
||||||
|
[emph ftnunit_test.f90] that should be included in an appropriate
|
||||||
|
place in the program's sources. This way, you can make it a private
|
||||||
|
routine in each module. The only public access to the unit testing
|
||||||
|
routines is then via the subroutine [emph testproc] that is passed to
|
||||||
|
[emph runtests].
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
[arg_def "subroutine" proc]
|
||||||
|
Subroutine that implements an individual unit test. It takes no
|
||||||
|
arguments. Within each such subroutine the complete unit test is run.
|
||||||
|
|
||||||
|
[arg_def "character(len=*), intent(in)" text]
|
||||||
|
Text describing the particular unit test. It is printed in the log
|
||||||
|
file.
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call assert_true( cond, text )"]]
|
||||||
|
Routine to check that a condition is true. If not, a message is printed
|
||||||
|
in the log file and the number of failures is increased.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
[arg_def "logical" cond]
|
||||||
|
The condition to be checked
|
||||||
|
|
||||||
|
[arg_def "character(len=*), intent(in)" text]
|
||||||
|
Text describing the condition
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call assert_false( cond, text )"]]
|
||||||
|
Routine to check that a condition is false. If not, a message is
|
||||||
|
printed in the log file and the number of failures is increased.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
[arg_def "logical" cond]
|
||||||
|
The condition to be checked
|
||||||
|
|
||||||
|
[arg_def "character(len=*), intent(in)" text]
|
||||||
|
Text describing the condition
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call assert_equal( value1, value2, text )"]]
|
||||||
|
Routine to check that two integers are equal or if two one-dimensional
|
||||||
|
integer arrays are equal. If not, a message is printed, along with the
|
||||||
|
values that were different.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
[arg_def "integer \[, dimension(:)\]" value1]
|
||||||
|
The first integer value or array
|
||||||
|
|
||||||
|
[arg_def "integer \[, dimension(:)\]" value2]
|
||||||
|
The second integer value or array
|
||||||
|
|
||||||
|
[arg_def "character(len=*), intent(in)" text]
|
||||||
|
Text describing the condition
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call assert_comparable( value1, value2, margin, text )"]]
|
||||||
|
Routine to check that two reals are almost equal or if two one-dimensional
|
||||||
|
real arrays are almost equal. If not, a message is printed, along with
|
||||||
|
the values that were different.
|
||||||
|
[nl]
|
||||||
|
The margin is taken as a relative tolerance. Two values are
|
||||||
|
considered almost equal if:
|
||||||
|
[example {
|
||||||
|
abs( v1 - v2 ) < margin * (abs(v1)+abs(v2)) / 2
|
||||||
|
}]
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
[arg_def "real \[, dimension(:)\]" value1]
|
||||||
|
The first real value or array
|
||||||
|
|
||||||
|
[arg_def "real \[, dimension(:)\]" value2]
|
||||||
|
The second real value or array
|
||||||
|
|
||||||
|
[arg_def "character(len=*), intent(in)" text]
|
||||||
|
Text describing the condition
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "exists = ftnunit_file_exists( filename )"]]
|
||||||
|
Logical function to check that a particular file exists
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
[arg_def "character(len=*), intent(in)" filename]
|
||||||
|
Name of the file to be checked
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call ftnunit_get_lun( lun )"]]
|
||||||
|
Subroutine to get a free LU-number
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
[arg_def "integer, intent(out)" lun]
|
||||||
|
Next free LU-number
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call ftnunit_remove_file( filename )"]]
|
||||||
|
Subroutine to remove (delete) a file
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
[arg_def "character(len=*), intent(in)" filename]
|
||||||
|
Name of the file to be removed
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call ftnunit_make_empty_file( filename )"]]
|
||||||
|
Subroutine to make a new, empty file
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
[arg_def "character(len=*), intent(in)" filename]
|
||||||
|
Name of the file to be created
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
|
||||||
|
[section "GENERATING TESTS FROM A TABLE"]
|
||||||
|
The Tcl program "gentabletest.tcl" reads the test specifications from an
|
||||||
|
input file and generates a complete Fortran program. The ideas from
|
||||||
|
Bil Kleb's "Toward Scientific Numerical Modeling"
|
||||||
|
[uri ftp://ftp.rta.nato.int/PubFullText/RTO/MP/RTO-MP-AVT-147/RTO-MP-AVT-147-P-17-Kleb.pdf]
|
||||||
|
were used for the set-up.
|
||||||
|
|
||||||
|
[para]
|
||||||
|
To do: provide a detailed description. For the moment: see [emph example.tbl], including below.
|
||||||
|
|
||||||
|
[example {
|
||||||
|
! Example of generating test code via a table
|
||||||
|
! -------------------------------------------
|
||||||
|
! The routine to be tested determines the minimum oxygen concentration
|
||||||
|
! in a river, based on the Streeter-Phelps model:
|
||||||
|
!
|
||||||
|
! dBOD/dt = -k * BOD
|
||||||
|
!
|
||||||
|
! dO2/dt = -k * BOD + ka * (O2sat-O2) / H
|
||||||
|
!
|
||||||
|
! where
|
||||||
|
! BOD - biological oxygen demand (mg O2/l)
|
||||||
|
! O2 - oxygen concentration (mg O2/l)
|
||||||
|
! O2sat - saturation concentration of oxygen (mg O2/l)
|
||||||
|
! k - decay rate of BOD (1/day)
|
||||||
|
! ka - reareation rate of oxygen (m/day)
|
||||||
|
! H - depth of the river
|
||||||
|
!
|
||||||
|
! We need boundary (initial) conditions for BOD and oxygen and
|
||||||
|
! the equations describe the concentrations of BOD and oxygen in a
|
||||||
|
! packet of water as it flows along the river.
|
||||||
|
!
|
||||||
|
! Note:
|
||||||
|
! It is a very simple model, it is not meant as a realistic
|
||||||
|
! representation.
|
||||||
|
!
|
||||||
|
! The routine simply continues the solution until a minimum is found.
|
||||||
|
! The results are: oxymin and time
|
||||||
|
!
|
||||||
|
!
|
||||||
|
! The keyword DECLARATIONS introduces the declarations we need for the
|
||||||
|
! complete generated code
|
||||||
|
!
|
||||||
|
DECLARATIONS
|
||||||
|
use streeter_phelps
|
||||||
|
real :: bod, oxy
|
||||||
|
real :: k, ka, h, oxysat, dt, oxymin, time
|
||||||
|
!
|
||||||
|
! The keyword CODE introduces the code fragment required to run the
|
||||||
|
! routine or routines. The results and possible checking of error
|
||||||
|
! conditions are separated.
|
||||||
|
!
|
||||||
|
CODE
|
||||||
|
call compute_min_oxygen( bod, oxy, k, ka, h, oxysat, dt, oxymin, time )
|
||||||
|
!
|
||||||
|
! The keyword RESULT indicates which arguments/variables hold the
|
||||||
|
! interesting results. Specify one name per line (you can not currently
|
||||||
|
! use array elements) and the allowed margin (taken as absolute, if
|
||||||
|
! followed by "%" as a percentage)
|
||||||
|
!
|
||||||
|
RESULT
|
||||||
|
oxymin 0.001 ! Minimum oxygen concentration
|
||||||
|
time 0.01% ! Time the minimum is reached
|
||||||
|
|
||||||
|
!
|
||||||
|
! The keyword ERROR is used for a code fragment that checks if the
|
||||||
|
! routine has correctly found an error in the input (that is, some
|
||||||
|
! parameter value is out of range). The code is invoked when any of
|
||||||
|
! result variables in a table entry has the keyword ERROR instead of
|
||||||
|
! a proper value.
|
||||||
|
! Use the subroutine "error" to indicate the correctly reported error
|
||||||
|
! condition.
|
||||||
|
!
|
||||||
|
ERROR
|
||||||
|
if ( time == -999.0 ) then
|
||||||
|
call error
|
||||||
|
endif
|
||||||
|
!
|
||||||
|
! The keyword RANGES specifies that the variables are to be taken
|
||||||
|
! from a uniform or a normal distribution. The generated program will
|
||||||
|
! simply select values at random and run the code with them. The report
|
||||||
|
! consists of the detailed output as well as a summary.
|
||||||
|
!
|
||||||
|
RANGES
|
||||||
|
oxy 10.0 2.0 Uniform ! Name of the variable, the mean and the margin (uniform)
|
||||||
|
! Normal: mean and standard deviation followed by Normal
|
||||||
|
! Note: all parameters must be given!
|
||||||
|
!
|
||||||
|
! The keyword TABLE indicates the beginning of a table of input data and
|
||||||
|
! expected values. The first (non-comment) line contains the names of
|
||||||
|
! the variables as used in the code fragments and all others are the
|
||||||
|
! values expected.
|
||||||
|
!
|
||||||
|
! There are two special values:
|
||||||
|
! ? - indicating an unknown value for result variables and a "do not
|
||||||
|
! care" value for input variables
|
||||||
|
! It is useful to generate a table that does contain the (computed)
|
||||||
|
! results (see the file table.out) or to indicate situations
|
||||||
|
! where one or more input variables are out of range and this
|
||||||
|
! should lead to an error
|
||||||
|
! ERROR - indicating that the entry should cause the routine to be
|
||||||
|
! tested to flag an error condition.
|
||||||
|
!
|
||||||
|
TABLE
|
||||||
|
dt oxy bod oxysat h k ka oxymin time
|
||||||
|
0.1 10 1 10 10 0.1 1.0 10.0 2.0
|
||||||
|
1.0 10 1 10 10 0.1 1.0 ? ?
|
||||||
|
!
|
||||||
|
! This case is unacceptable: time step must be positive
|
||||||
|
0.0 ? ? ? ? ? ? ? ERROR
|
||||||
|
1.0 0. 10 10 10 0.1 1.0 ? ?
|
||||||
|
}]
|
||||||
|
|
||||||
|
[section TODO]
|
||||||
|
The following things are still left to do:
|
||||||
|
[list_begin bullet]
|
||||||
|
[bullet]
|
||||||
|
Proper inclusion of the routine [emph prolog] and [emph epilog]
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
Extension of the set of assertion routines
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
[section "RELATED WORK"]
|
||||||
|
There are at least two similar initiatives with regard to a unit testing
|
||||||
|
framework for Fortran:
|
||||||
|
|
||||||
|
[list_begin bullet]
|
||||||
|
[bullet]
|
||||||
|
[uri {http://nasarb.rubyforge.org} {Funit (implemented in Fortran and
|
||||||
|
Ruby)}] by Bil Kleb and others
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
[uri {http://www.sourceforge.net/projects/pfunit} {A framework
|
||||||
|
implemented in Fortran}] by Brice Womack and Tom Clune
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
[uri {http://www.sourceforge.net/projects/fortranxunit} {FRUIT
|
||||||
|
(implemented in Fortran and Ruby)}] by Andrew Chen
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
(Note: To avoid confusion, I have renamed my original module "funit" to
|
||||||
|
[emph ftnunit])
|
||||||
|
|
||||||
|
[manpage_end]
|
||||||
129
flibs-0.9/flibs/doc/ipc.man
Normal file
129
flibs-0.9/flibs/doc/ipc.man
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
[comment {-*- flibs -*- doctools manpage}]
|
||||||
|
[manpage_begin flibs/ipc n 0.1]
|
||||||
|
[copyright {2006 Arjen Markus <arjenmarkus@sourceforge.net>}]
|
||||||
|
[moddesc flibs]
|
||||||
|
[titledesc {Inter-process communication}]
|
||||||
|
|
||||||
|
[description]
|
||||||
|
|
||||||
|
[emph IPC] or inter-process communication is the name for various
|
||||||
|
mechanisms by which programs (either multiple instances of the same
|
||||||
|
program or different programs) can exchange information. There are
|
||||||
|
numerous mechanisms available, each with its own pros and cons.
|
||||||
|
|
||||||
|
[para]
|
||||||
|
The modules in the [emph ipc] directory are intended to make
|
||||||
|
inter-process communication possible with a minimum of OS requirements:
|
||||||
|
|
||||||
|
[list_begin bullet]
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
The module [emph ipc_file] uses plain files for this communication and
|
||||||
|
can therefore only be used if the processes have access to the same
|
||||||
|
disks.
|
||||||
|
[nl]
|
||||||
|
The advantage however is that it can be in standard Fortran, without any
|
||||||
|
reliance on special system libraries. The sole exception is the use of a
|
||||||
|
sleep routine, to make sure the program can pause without consuming too
|
||||||
|
much CPU (like in a long computation).
|
||||||
|
|
||||||
|
[bullet]
|
||||||
|
The module [emph ipc_mmap] uses so-called memory-mapped files. This is
|
||||||
|
a more sophisticated method that does rely on system libraries
|
||||||
|
(currently Windows and Linux, including Cygwin, are supported).
|
||||||
|
[nl]
|
||||||
|
The advantage is mostly in better performance - data are communicated
|
||||||
|
via memory and not via the hard disk. The disadvantages are that a C
|
||||||
|
compiler is required, as part of the code is in C and it is limited to
|
||||||
|
shared-memory systems.
|
||||||
|
|
||||||
|
[list_end]
|
||||||
|
|
||||||
|
Both modules use the [emph same] set of routines and the [emph same]
|
||||||
|
programming methods can be used. In fact, you select either one by
|
||||||
|
changing the module [emph ipc], not by using [emph ipc_file] or
|
||||||
|
[emph ipc_mmap] directly.
|
||||||
|
|
||||||
|
|
||||||
|
[section "PROGRAMMING PHILOSOPHY"]
|
||||||
|
|
||||||
|
[section ROUTINES]
|
||||||
|
|
||||||
|
The set of routines offered by the [emph IPC] modules consists of
|
||||||
|
the following:
|
||||||
|
|
||||||
|
[list_begin definitions]
|
||||||
|
|
||||||
|
[call [cmd "call ipc_open( comm, src, dest, dir, maxsize )"]]
|
||||||
|
Open the connection between sender (src) and receiver (dest). The
|
||||||
|
connection parameters are stored in the argument [emph comm], which is
|
||||||
|
then used for all other routines to identify the connection.
|
||||||
|
|
||||||
|
[list_begin arg]
|
||||||
|
|
||||||
|
[arg_def type(ipc_comm) comm]
|
||||||
|
Variable of derived type "ipc_comm" which will hold all information.
|
||||||
|
|
||||||
|
[arg_def character(len=*) src]
|
||||||
|
String identifying the sender process. This should be unique among all
|
||||||
|
the processes involved. (Maximum significant length: 20 characters)
|
||||||
|
|
||||||
|
[arg_def character(len=*) dest]
|
||||||
|
String identifying the receiver process. This should be unique
|
||||||
|
among all the processes involved. (Maximum significant length: 20
|
||||||
|
characters)
|
||||||
|
|
||||||
|
[arg_def character(len=*) dir]
|
||||||
|
Directory to be used for the files. This directory must be accessible to
|
||||||
|
all processes. An empty string signifies a default directory, which
|
||||||
|
depends on the platform, such as /tmp or c:\temp - but it is not
|
||||||
|
recommended. (Maximum significant length: 256 characters)
|
||||||
|
|
||||||
|
[arg_def integer maxsize]
|
||||||
|
The maximum size for all the data sent in one message. It is measured in
|
||||||
|
bytes. (Note: you should not take it too tight, as per call to
|
||||||
|
ipc_send there will be a small overhead, some 40 bytes, to identify the
|
||||||
|
type and dimension of the data. It is ignored, however, when using the
|
||||||
|
[emph ipc_file] module).
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call ipc_send_start( comm, tag, id )"]]
|
||||||
|
Start the sending of the data. The message as a whole is identified by a
|
||||||
|
short string and an ID number, so that the receiver can check (if
|
||||||
|
needed) that the right message is received.
|
||||||
|
|
||||||
|
[arg_def type(ipc_comm) comm]
|
||||||
|
Variable of derived type "ipc_comm" which holds the connection information.
|
||||||
|
|
||||||
|
[arg_def character(len=*) tag]
|
||||||
|
String identifying the type of message (maximum length: 20)
|
||||||
|
|
||||||
|
[arg_def integer id]
|
||||||
|
ID number of the message
|
||||||
|
|
||||||
|
|
||||||
|
[call [cmd "call ipc_send_stop( comm )"]]
|
||||||
|
Signals that all data have been sent.
|
||||||
|
|
||||||
|
[arg_def type(ipc_comm) comm]
|
||||||
|
Variable of derived type "ipc_comm" which holds the connection information.
|
||||||
|
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
[call [cmd "call ipc_receive_start( comm, tag, id )"]]
|
||||||
|
Start receiving of the data. The message as a whole is identified by the
|
||||||
|
short string and an ID number. so that the receiver can check (if
|
||||||
|
needed) that the right message is received.
|
||||||
|
|
||||||
|
[arg_def type(ipc_comm) comm]
|
||||||
|
Variable of derived type "ipc_comm" which holds the connection information.
|
||||||
|
|
||||||
|
[arg_def character(len=*) tag]
|
||||||
|
String identifying the type of message (maximum length: 20)
|
||||||
|
|
||||||
|
[arg_def integer id]
|
||||||
|
ID number of the message
|
||||||
|
|
||||||
|
|
||||||
|
[manpage_end]
|
||||||
19
flibs-0.9/flibs/doc/makedoc
Normal file
19
flibs-0.9/flibs/doc/makedoc
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
OVERVIEW
|
||||||
|
--------
|
||||||
|
|
||||||
|
src/strings:
|
||||||
|
------------
|
||||||
|
The source files in this directory manipulate character strings in some
|
||||||
|
way or another:
|
||||||
|
|
||||||
|
- filedir.f90
|
||||||
|
Module to manipulate the parts of a file name (directory, name, extension)
|
||||||
|
|
||||||
|
- textstr.f90
|
||||||
|
Small collection of modules that can help to store strings of arbitrary length.
|
||||||
|
It is not meant to implement a general arbitrary-length module: there are only a few
|
||||||
|
intrinsic functions emulated.
|
||||||
|
|
||||||
|
- csv_file.f90
|
||||||
|
Module to help _write_ CSV files
|
||||||
|
|
||||||
6
flibs-0.9/flibs/doc/makedoc.bat
Normal file
6
flibs-0.9/flibs/doc/makedoc.bat
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
@echo off
|
||||||
|
rem makedoc.tcl --
|
||||||
|
rem Script for creating HTML-files from the raw documentation files
|
||||||
|
rem
|
||||||
|
c:\tcl\bin\tclsh.exe c:\tcl\demos\TclApps\apps\dtp\main.tcl doc -out %1.html html %1.man
|
||||||
|
copy /n /y %1.html ..\..\site
|
||||||
79
flibs-0.9/flibs/doc/makedoc.tcl
Normal file
79
flibs-0.9/flibs/doc/makedoc.tcl
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
#
|
||||||
|
# A script to generate the html documentation from the
|
||||||
|
# doctools man files.
|
||||||
|
#
|
||||||
|
|
||||||
|
package require doctools
|
||||||
|
|
||||||
|
#
|
||||||
|
# formatfile --
|
||||||
|
# Process the given manfile and generate the associated
|
||||||
|
# html file.
|
||||||
|
#
|
||||||
|
proc formatfile {manfile} {
|
||||||
|
::doctools::new mdt
|
||||||
|
mdt configure -file $manfile
|
||||||
|
mdt configure -format html
|
||||||
|
set handle [open $manfile r]
|
||||||
|
set content [read -nonewline $handle]
|
||||||
|
close $handle
|
||||||
|
set htmlcontent [mdt format $content]
|
||||||
|
set htmlfile [computefilename $manfile .html]
|
||||||
|
set handle [open $htmlfile w]
|
||||||
|
puts -nonewline $handle $htmlcontent
|
||||||
|
close $handle
|
||||||
|
mdt destroy
|
||||||
|
return $htmlfile
|
||||||
|
}
|
||||||
|
#
|
||||||
|
# computefilename --
|
||||||
|
# Replace the extension in the given filename
|
||||||
|
# with the given new extension.
|
||||||
|
#
|
||||||
|
proc computefilename {filename newextension} {
|
||||||
|
set lastdot [string last "." $filename]
|
||||||
|
incr lastdot -1
|
||||||
|
set newname [string range $filename 0 $lastdot]
|
||||||
|
append newname $newextension
|
||||||
|
return $newname
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# processall --
|
||||||
|
# Process all man files in the current directory.
|
||||||
|
#
|
||||||
|
proc processall {} {
|
||||||
|
set manfiles [glob "*/*.man"]
|
||||||
|
foreach filename $manfiles {
|
||||||
|
set isuptodate [isuptodate $filename]
|
||||||
|
if {$isuptodate==0} then {
|
||||||
|
puts "> Updating $filename..."
|
||||||
|
formatfile $filename
|
||||||
|
} else {
|
||||||
|
puts "> Up-to-date: $filename "
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
#
|
||||||
|
# isuptodate --
|
||||||
|
# Returns 1 if the given man file is up-to-date,
|
||||||
|
# with respect to the associated htmlfile.
|
||||||
|
#
|
||||||
|
proc isuptodate {manfile} {
|
||||||
|
set htmlfile [computefilename $manfile .html]
|
||||||
|
set fexists [file exists $htmlfile]
|
||||||
|
if {$fexists==0} then {
|
||||||
|
set result 0
|
||||||
|
} else {
|
||||||
|
set time1 [file mtime $manfile]
|
||||||
|
set time2 [file mtime $htmlfile]
|
||||||
|
set result [expr {$time1< $time2}]
|
||||||
|
}
|
||||||
|
return $result
|
||||||
|
}
|
||||||
|
#
|
||||||
|
# Executable part of the script.
|
||||||
|
#
|
||||||
|
processall
|
||||||
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user