! 共享库一览 —— 用 **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
