fix: VarChar handling raw string, VarChar Inz silent drop

This commit is contained in:
2026-03-12 23:19:46 -07:00
parent 8e36afbf67
commit 832dae44fb
3 changed files with 146 additions and 35 deletions

View File

@@ -11,6 +11,8 @@
//! | `rpg_dsply_cstr` | `(ptr: *const c_char)` | Display a null-terminated C string |
//! | `rpg_dsply_i64` | `(n: i64)` | Display a signed 64-bit integer |
//! | `rpg_dsply_f64` | `(f: f64)` | Display a double-precision float |
//! | `rpg_dsply_read` | `(prompt: *const c_char, response: *mut i64)` | Display null-term prompt & read i64 |
//! | `rpg_dsply_read_len`| `(ptr: *const u8, len: i64, response: *mut i64)` | Display length-delimited prompt & read i64 |
//! | `rpg_halt` | `(code: i32)` | Abnormal program termination |
//! | `rpg_char_i64` | `(n: i64) -> *const c_char` | Format integer as null-term C string |
//! | `rpg_concat` | `(a: *const c_char, b: *const c_char) -> *const c_char` | Concatenate two C strings |
@@ -209,6 +211,59 @@ pub unsafe extern "C" fn rpg_dsply_read(
}
}
// ─────────────────────────────────────────────────────────────────────────────
// rpg_dsply_read_len — display a length-delimited prompt and read a response
// ─────────────────────────────────────────────────────────────────────────────
/// Three-operand DSPLY where the prompt is a fixed-length (or VarChar) field
/// passed as `(ptr, len)` rather than a null-terminated C string.
///
/// This is called when the prompt operand is a `Char` or `VarChar` variable —
/// those are stored as raw byte buffers with no null terminator, so
/// `rpg_dsply_read` (which calls `CStr::from_ptr`) cannot be used safely.
///
/// Trailing ASCII spaces are stripped from the prompt before display, matching
/// the behaviour of `rpg_dsply`.
///
/// # Safety
///
/// * `ptr` must be valid for at least `len` bytes (or be null).
/// * `response` must be a valid, writable `i64` pointer.
#[no_mangle]
pub unsafe extern "C" fn rpg_dsply_read_len(
ptr: *const u8,
len: i64,
response: *mut i64,
) {
use std::io::BufRead;
// Build the prompt string the same way rpg_dsply does.
let bytes = if ptr.is_null() || len <= 0 {
b"" as &[u8]
} else {
unsafe { slice::from_raw_parts(ptr, len as usize) }
};
let trimmed = rtrim_spaces(bytes);
let text = String::from_utf8_lossy(trimmed);
{
let stdout = io::stdout();
let mut out = stdout.lock();
let _ = writeln!(out, "DSPLY {}", text);
let _ = out.flush();
}
// Read one line from stdin and parse it as i64.
let stdin = io::stdin();
let mut line = String::new();
if stdin.lock().read_line(&mut line).is_ok() {
let trimmed_line = line.trim();
if let Ok(n) = trimmed_line.parse::<i64>() {
unsafe { *response = n; }
}
}
}
// ─────────────────────────────────────────────────────────────────────────────
// rpg_halt — abnormal termination
// ─────────────────────────────────────────────────────────────────────────────