← 都来码 / Dolaima← 例程索引fortran/test/libs.f90原文

fortran/test/libs.f90 · 5798 字节 · 下载原文

! 共享库一览 —— 用 **Fortran** 把四个共享库各叫一遍
! Shared libraries tour -- calling all four shared libraries from **Fortran**
!
! ◆ 这份例程在练什么
! ◆ What this example exercises
!
! 共享库是**一次投入、22 门语言都受益**的那种东西:`regex`(正则)· `dbf`(dBASE 数据文件)
! · `sql`(跑在 .dbf 上的查询)· `turtle`(海龟作图)。它们**不是 Fortran 的库**,
! 而是每一门语言都能调的同一份实现 —— 这份例程就是"从 Fortran 这边调得动"的活证据。
! The shared libraries are one investment serving all 22 languages: `regex`, `dbf` (dBASE data
! files), `sql` (queries over .dbf) and `turtle`. They are not Fortran libraries -- they are one
! implementation every language can call. This example is the living proof that Fortran can.
!
!   regex  : 模式 `abc` 在 `xxabcyy` 里**找得到**吗(1 = 找得到)
!   dbf    : 现建一张两字段的表、塞两条记录,再看一眼记录数
!   sql    : 在刚建的那张表上跑一句 `SELECT ... WHERE`
!   turtle : 抬笔走 50 步,看它的坐标(不写屏幕,所以**不需要开窗口**)
!
! ◆ ⚠ 为什么输出走 `print_str` / `println_int`,而不是 `print *`
! ◆ (!) Why the output goes through `print_str` / `println_int` instead of `print *`
!
! Fortran 的 `print *, '名字=', 值` 会在两项之间**插一个空格**(列表式输出的规矩),
! 打出来是 `名字= 值`。而这两条辅助函数(每门语言都无条件链的 builtins)写出来
! **没有那个空格**,所以本文件用它们 —— 22 门语言的例程输出因此是同一个格式。
! Fortran's `print *, 'name=', value` **inserts a space** between the two items (list-directed
! output), so it prints `name= value`. The two helpers used here (from builtins, which every
! language links unconditionally) print with **no** such space, which keeps this example's output
! in the same shape as the other 21 languages'.
!
! ◆ 为什么全程只调"返回整数"的那些接口
! ◆ Why only the integer-returning calls
!
! Fortran 的字符串字面量**取不到可写地址**,而 `dbf_get` / `sql_cell` 这类要调用方给 dst。
! 所以这里走另一条路:**要缓冲区的地方用 `alloc` 自己拿一块**(见下面 `rec` 那几行),
! 取值一律用"只问长度"的形态(`dbf_fname(h, 0, 0)`)。
! Fortran string literals give no writable address, and `dbf_get`/`sql_cell` need a caller-supplied
! dst. So: take a buffer yourself with `alloc` (see the `rec` lines below), and use the
! "length only" form of the accessors (`dbf_fname(h, 0, 0)`).
!
! ◆ 写法与 `demo_std.f90` 同源:`program` / `implicit none` / 变量先声明 / `call` 调子程序。
! ◆ The shape follows `demo_std.f90`: `program` / `implicit none` / declarations first / `call`.
!
! ⚠ 跑一次会在**本文件所在目录**建一个 `libdemo.dbf`(这就是 dbf 那一半在演示的事)。
! ⚠ Running this creates a small `libdemo.dbf` **next to this file** -- that is the point of it.

program libs
  implicit none
  integer :: h
  integer :: rec

  ! ── regex:模式匹配 ──
  call print_str('REGEX_HIT=')
  call println_int(re_test('abc', 'xxabcyy'))
  call print_str('REGEX_MISS=')
  call println_int(re_test('abc', 'xxabxyy'))
  call print_str('REGEX_VALID=')
  call println_int(re_is_valid('(a|b)+'))

  ! ── dbf:建表 → 塞两条 → 读记录数 ──
  ! 字段类型用**字符的字节值**:'C' = 67(字符型)· 'N' = 78(数字型)——
  ! Fortran 的字符字面量是字符串,而接口收的是 C 的 `char`(一个字节),所以这里写数字。
  ! Field types are the **byte value of the character**: 'C' = 67, 'N' = 78 -- a Fortran character
  ! literal is a string while the entry point takes C's `char` (one byte), so the number goes in.
  h = dbf_new('libdemo.dbf')
  call dbf_addfield(h, 'NAME', 67, 8, 0)
  call dbf_addfield(h, 'AGE', 78, 3, 0)
  call dbf_build(h)

  rec = alloc(64)
  call dbf_mkrec(h, rec)
  call dbf_put(h, rec, 0, 'Alice')
  call dbf_put(h, rec, 1, '30')
  call dbf_add(h, rec)
  call dbf_mkrec(h, rec)
  call dbf_put(h, rec, 0, 'Bob')
  call dbf_put(h, rec, 1, '7')
  call dbf_add(h, rec)
  call dbf_flush(h)

  call print_str('DBF_ROWS=')
  call println_int(dbf_records(h))
  call print_str('DBF_FIELDS=')
  call println_int(dbf_fields(h))
  call print_str('DBF_FIELD0_LEN=')
  call println_int(dbf_fname(h, 0, 0))
  call dbf_close(h)

  ! ── sql:在刚建的表上查 ──
  call print_str('SQL_ROWS=')
  call println_int(sql_run('libdemo.dbf', 'SELECT * FROM t WHERE AGE > 20'))
  call print_str('SQL_COLS=')
  call println_int(sql_cols())
  call print_str('SQL_COL0_LEN=')
  call println_int(sql_colname(0, 0))

  ! ── turtle:抬笔走 50 步(落笔会去画屏幕,那要窗口)──
  call turtle_reset()
  call turtle_pen_up()
  call turtle_forward(50)
  call print_str('TURTLE_X=')
  call println_int(turtle_x())
  call print_str('TURTLE_Y=')
  call println_int(turtle_y())

! ── sed:sed 的替换规则(s / y 两条命令,依附 regex 库)—— 缓冲区那一半只有 C 拿得到,
!    这里压的是「只问长度」那一支(cap 传 0)与对账用的 sed_count。
call print_str('SED_COUNT=')
call println_int(sed_count('s/a/X/g', 'banana'))
call print_str('SED_LEN=')
call println_int(sed_sub('s/a/X/g', 'banana', 0, 0))
  call print_str('DONE=')
  call println_int(1)
end program libs

! 期望(scripts/lib-examples-check.sh 按这一行比对):
! EXPECT: REGEX_HIT=1|REGEX_MISS=0|REGEX_VALID=1|DBF_ROWS=2|DBF_FIELDS=2|DBF_FIELD0_LEN=4|SQL_ROWS=1|SQL_COLS=2|SQL_COL0_LEN=4|TURTLE_X=0|TURTLE_Y=50|SED_COUNT=3|SED_LEN=6|DONE=1