Tcl/Tk

Tcl is a cross-platform bytecode-interpreted scripting language that was initially developed at the University of California, Berkeley, in 1988, and is famous for its graphical widget library Tk, that is also the default toolkit in Python (known as Tkinter). Tcl provides an API to embed scripts in programs written in C and other languages.

The Ftcl library contains non-standard interface bindings to Tcl/Tk for Fortran, to call Tcl from Fortran and vice versa. The library is not compatible to modern Fortran compilers. Instead, we may call Fortran from Tcl/Tk by just relying on standard input/output for inter-process communication on Unix.

Tcl/Tk application calling Fortran
Fig. 1: Tcl/Tk graphical user interface to Fortran program that converts temperature values (fonts, widget style, and window decorations depend on the window manager and the default Tk theme)

Installation

Tcl/Tk packages are available for most Unix-like operating systems. On FreeBSD, install the Tcl shell tclsh, the Tcl/Tk interpreter wish, and the Tk graphical user interface toolkit with:

# pkg install lang/tcl86 x11-toolkits/tk86

We can then invoke the Tcl command-line interpreter:

$ tclsh8.6
% puts "Hello, World!"
Hello, World!

Example

The example program in Fortran will convert temperature values from °Ré to °C. The historic Réaumur scale was common in Europe until the mid-19th century, and is still used in niche markets. In comparison to °C, the freezing and boiling points of water are defined as 0 and 80 degrees respectively instead. Today, references can be found in Russian literature:

Simply because a poor student, unhinged by poverty and hypochondria, on the eve of a severe delirious illness (note that), suspicious, vain, proud, who has not seen a soul to speak to for six months, in rags and in boots without soles, has to face some wretched policemen and put up with their insolence; and the unexpected debt thrust under his nose, the I.O.U. presented by Tchebarov, the new paint, thirty degrees Reaumur and a stifling atmosphere, a crowd of people, the talk about the murder of a person where he had been just before, and all that on an empty stomach--he might well have a fainting fit!

— Fyodor Dostoevsky: Crime and Punishment, Part III, Chapter IV, p. 276

The input value in °Ré is simply read-in from stdin, converted to °C, and written to stdout:

! re2c.f90
program main
    implicit none
    integer :: rc
    real    :: re

    do
        read (*, *, iostat=rc) re
        if (rc /= 0) exit
        print '(f0.2)', re * 5 / 4
    end do
end program main

We compile the source code to the executable re2c:

$ gfortran10 -o re2c re2c.f90

The binary re2c will later be executed by our Tcl/Tk script.

Graphical User Interface

The front-end script re2c.tcl in Tcl creates a Tk window with entry widgets, label widgets, and a single button widget. The callback routine callback will be invoked on button press events, and then opens an anonymous pipe to the Fortran program re2c.

The input value in °Re is passed through standard output to the Fortran program, and the result is read back through standard input. The converted temperature value in °C is then displayed in one of the entry widgets:

#!/usr/bin/env wish
# re2c.tcl

package require Tk

set input  "0.0"    ;# Default input value.
set output ""       ;# Default output value.

# Set window title.
wm title . "Réaumur to Celsius"

# Create grid for our widgets.
grid [ttk::frame .frame -padding "10 10 20 20"] -column 0 -row 0 -sticky nwes
grid columnconfigure . 0 -weight 1
grid rowconfigure    . 0 -weight 1

# Add widgets.
grid [ttk::label  .frame.text -text "Enter value in °Ré:"] -columnspan 5 -column 1 -row 1 -sticky we
grid [ttk::entry  .frame.input -width 7 -textvariable input] -column 1 -row 2 -sticky we
grid [ttk::label  .frame.deg_re -text "°Ré"] -column 2 -row 2 -sticky we
grid [ttk::button .frame.button -text ">" -command [list callback]] -column 3 -row 2 -sticky w
grid [ttk::entry  .frame.output -width 7 -textvariable output] -column 4 -row 2 -sticky we
grid [ttk::label  .frame.deg_c -text "°C"] -column 5 -row 2 -sticky we

# Add padding to widgets.
foreach w [winfo children .frame] {
    grid configure $w -padx 0 -pady 5
}

focus .frame.input                  ;# Set initial focus to input widget.
bind . <Return> {[list callback]}   ;# Add key binding.

# The callback routine.
proc callback {} {
    global output                   ;# Set output variable as global to change widget value.
    set input [.frame.input get]    ;# Get input value.
    if {$input eq ""} return

    set f [open "| ./re2c" r+]      ;# Open anonymous pipe to program.
    puts $f $input                  ;# Write to stdout.
    flush $f                        ;# Flush buffer.
    gets $f output                  ;# Read from stdin.
    close $f                        ;# Close file handle.
}

The Tcl/Tk script re2c.tcl has to be executed with wish, the Tcl interpreter for graphical Tk applications:

$ wish ./re2c.tcl

The script can be made executable:

$ chmod a+x re2c.tcl
$ ./re2c.tcl

Make sure the Fortran application re2c is located in the same directory as the Tcl/Tk script:

The graphical user interface will show the converted temperature returned from the Fortran program (fig. 1).

References