# PLIB Core API Reference (Psion SIBO / Workabout MX)

Categorised function reference for the core **PLIB** library, drawn from the
*PLIB Reference*, Version 2.10 (3 February 1995), (C) Psion PLC.

## Conventions

- Signatures are transcribed from the manual. The OCR source occasionally
  mangles glyphs; signatures below are corrected to the manual's own C types
  where the intent is unambiguous. Uncertain items are marked **[?]**.
- Types: `TEXT` = char/byte string, `UBYTE`/`BYTE`, `UWORD`/`WORD` (16-bit),
  `UINT`/`INT` (16-bit), `ULONG`/`LONG` (32-bit), `DOUBLE` (64-bit float),
  `VOID`, `HANDLE`, `BOOL`.
- Many functions return `0` on success and a negative `E_*` error number
  (defined in `p_gen.h` etc.) on failure.
- `f_*` twins of `p_*` allocators/senders behave identically except they call
  `p_leave(E_GEN_NOMEMORY)` / `p_leave(err)` instead of returning `NULL`/`err`.

---

## 1. String & Buffer Handling

Declared chiefly in `p_std.h` / `plib.h`. Buffers (`b*`) take an explicit
length; strings (`s*`) are zero-terminated.

### 1.1 Copy, length, concatenate, fill

| Signature | Purpose |
|---|---|
| `UBYTE *p_bcpy(VOID *target, VOID *source, UINT len);` | Copy `len` bytes source→target (overlap-safe); returns `target+len`. |
| `UINT p_slen(TEXT *str);` | Return length of zero-terminated string, excluding the terminator. |
| `TEXT *p_scpy(TEXT *target, TEXT *source);` | Copy string source→target; returns address of target's terminating zero. |
| `TEXT *p_scpym(TEXT *target, ...);` | Copy+concatenate a NULL-terminated list of strings into target. |
| `TEXT *p_scat(TEXT *lstr, TEXT *rstr);` | Append rstr to lstr; returns address of new terminating zero. |
| `TEXT *p_scatm(TEXT *lstr, ...);` | Append a NULL-terminated list of strings to lstr. |
| `UBYTE *p_brep(VOID *buf, INT buf_len, VOID *pattern, INT pat_len);` | Fill buf by replicating a byte pattern; returns `buf+buf_len`. |
| `TEXT *p_srep(TEXT *buf, INT buf_len, TEXT *pattern);` | Fill buf by replicating a string pattern (terminator excluded). |
| `VOID p_bswap(VOID *buf1, VOID *buf2, INT len);` | Swap `len` bytes between two buffers. |
| `UBYTE *p_bfil(VOID *buf, UINT buf_len, INT fill_byte);` | Fill buf with a repeated byte; returns `buf+buf_len`. |
| `TEXT *p_jtob(TEXT *tbuf, INT tlen, TEXT *sbuf, INT slen, INT type, INT fill);` | Left/right/centre-align sbuf in tbuf (`P_JLEFT`/`P_JRIGHT`/`P_JCENTRE`), padding with `fill`. |

### 1.2 Comparison

| Signature | Purpose |
|---|---|
| `INT p_bcmp(VOID *lbuf, INT lbuf_len, VOID *rbuf, INT rbuf_len);` | Compare two buffers byte-wise; returns lbuf−rbuf (<0 / 0 / >0). |
| `INT p_scmp(TEXT *lstr, TEXT *rstr);` | Compare two strings; returns lstr−rstr. |
| `INT p_bcmpi(TEXT *lbuf, INT lbuf_len, TEXT *rbuf, INT rbuf_len);` | Case-independent buffer compare. |
| `INT p_scmpi(TEXT *lstr, TEXT *rstr);` | Case-independent string compare. |

*(OCR renders these as `p_bemp`/`p_bempi`; the intended names are `p_bcmp`/`p_bcmpi`.)*

### 1.3 Searching (character, substring, wildcard)

| Signature | Purpose |
|---|---|
| `INT p_bloc(VOID *buf, INT buf_len, INT ch);` | Index of first `ch` in buffer, or −1. |
| `INT p_sloc(TEXT *str, INT ch);` | Index of first `ch` in string, or −1. |
| `INT p_bloci(TEXT *buf, INT buf_len, INT ch);` | Case-independent forward char search in buffer. |
| `INT p_sloci(TEXT *str, INT ch);` | Case-independent forward char search in string. |
| `INT p_slocr(TEXT *str, INT ch);` | Reverse (last-occurrence) char search in string. |
| `INT p_slocri(TEXT *str, INT ch);` | Case-independent reverse char search in string. |
| `INT p_bsub(VOID *buf, INT buf_len, VOID *sbuf, INT sbuf_len);` | Index of first occurrence of a byte sequence in buffer, or −1. |
| `INT p_ssub(TEXT *str, TEXT *substr);` | Index of first occurrence of substring in string, or −1. |
| `INT p_bsubi(TEXT *buf, INT buf_len, TEXT *sbuf, INT sbuf_len);` | Case-independent buffer subsequence search. |
| `INT p_ssubi(TEXT *str, TEXT *substr);` | Case-independent substring search. |
| `INT p_bmatch(TEXT *buf, INT blen, TEXT *mbuf, INT mlen);` | Match buffer against a wildcard spec (`*`, `?`); returns TRUE/FALSE. |
| `INT p_bmatchi(TEXT *buf, INT blen, TEXT *mbuf, INT mlen);` | Case-independent wildcard buffer match. |
| `INT p_smatch(TEXT *str, TEXT *mstr);` | Match string against wildcard spec (`*`, `?`). |
| `INT p_smatchi(TEXT *str, TEXT *mstr);` | Case-independent wildcard string match. |

### 1.4 Character classification (return TRUE/FALSE for `c` modulo 256)

| Signature | Purpose |
|---|---|
| `INT p_isupper(INT c);` | Uppercase alphabetic (accented or not). |
| `INT p_islower(INT c);` | Lowercase alphabetic. |
| `INT p_isalpha(INT c);` | Alphabetic either case. |
| `INT p_isdigit(INT c);` | Decimal digit 0–9. |
| `INT p_isalnum(INT c);` | Alphanumeric. |
| `INT p_isxdigit(INT c);` | Hex digit 0–9, A–F, a–f. |
| `INT p_isspace(INT c);` | Whitespace (space, HT, NL, VT, FF, CR). |
| `INT p_iscntrl(INT c);` | Control character (0–31, 127). |
| `INT p_ispunct(INT c);` | Printable graphic, not alphanumeric/space. |
| `INT p_isgraph(INT c);` | Printable graphic (alnum or punct). |
| `INT p_isprint(INT c);` | Printable, i.e. `p_isgraph` plus space. |

### 1.5 Folding & case conversion, skipping

| Signature | Purpose |
|---|---|
| `TEXT *p_skipwh(TEXT *str);` | Skip leading whitespace; return first non-white char. |
| `TEXT *p_skipch(TEXT *str);` | Skip non-white chars; return first whitespace/terminator. |
| `INT p_tofold(INT c);` | Fold char via built-in fold table (for case-insensitive matching). |
| `TEXT *p_scpyf(TEXT *target, TEXT *source);` | Copy string folding each char (like `p_scpy`). |
| `VOID p_sconf(TEXT *str);` | Fold the characters of a string in place. |
| `INT p_toupper(INT c);` | Convert char to upper case (display use, not matching). |
| `INT p_tolower(INT c);` | Convert char to lower case (display use, not matching). |
| `VOID p_scap(TEXT *str);` | Capitalise string: first char upper, rest lower. *(EPOC 2.14+)* |

> **Folding vs. case:** `p_tofold`/`p_sconf` are for case-insensitive
> ordering/matching (symbol tables); `p_toupper`/`p_tolower`/`p_scap` are for
> human-visible text and must **not** be used for comparison.

---

## 2. Arrays, Queues & Sorting (misc utilities)

Doubly-linked circular queues use `P_QUE` headers; delta queues use `P_DELTA`.

| Signature | Purpose |
|---|---|
| `INT p_bsrch(INT nrec, INT (*compf)(), INT *pmid, UBYTE *pmatch);` | Binary search over `nrec` records via callback; writes found index to `*pmid`. |
| `INT p_qsort(INT nrec, INT (*ordf)(), VOID (*excf)(), UBYTE *base);` | Quicksort `nrec` records using ordering and exchange callbacks. |
| `VOID p_enque(P_QUE *pNew, P_QUE *pEntry);` | Insert `pNew` before `pEntry` in its doubly-linked queue. |
| `VOID p_deque(P_QUE *pEntry);` | Unlink `pEntry` from its queue. |

*(The manual also documents `p_dequed` for delta queues; its clean signature is
not printed in the source text — **[?]**.)*

---

## 3. CRC & Checksums

| Signature | Purpose |
|---|---|
| `VOID p_crc(UWORD *pcrc, UBYTE *buf, UINT len);` | Incrementally accumulate CCITT CRC-16 (x¹⁶+x¹²+x⁵+1) over `len` bytes; init `*pcrc` to 0 first. |

---

## 4. Console I/O

Primitive console services layered on the `CON:` device / window server. The
console is opened automatically on first use. PLIB offers only line output of
mono-spaced text and simple backspace-edited line input; richer row/column
control lives in the `CON:` device driver, and full UI in the Window Server.
Internal buffer is `P_MAXSYSIO` (258) bytes, limiting output to 256 bytes/call.

| Signature | Purpose |
|---|---|
| `VOID p_putch(UINT c);` | Write one character to the console. |
| `VOID p_puts(TEXT *str);` | Write a string and start a new line. |
| `VOID p_printf(TEXT *fstr, ...);` | Format args (as `p_atob`), write line, advance to next line. |
| `VOID p_print(TEXT *fstr, ...);` | As `p_printf` but no automatic newline (use `\r`,`\n`). |
| `INT p_getch(VOID);` | Wait for a keypress; return its character code. |
| `INT p_gets(TEXT *str);` | Read a line (backspace editing) up to `P_MAXSYSIO-1`; returns length. |
| `INT p_getl(TEXT *pmt, TEXT *str, INT len);` | Write prompt `pmt`, read up to `len` chars into `str`; returns length. |

---

## 5. Number ↔ String Conversion

Declared in the *Integer Conversion and Rectangle Functions* chapter.

### 5.1 Integer/long → text

| Signature | Purpose |
|---|---|
| `UINT p_itob(TEXT *buf, INT value);` | Signed decimal of INT → buf; returns chars written. |
| `INT p_ltob(TEXT *buf, LONG value);` | Signed decimal of LONG → buf; returns chars written. |
| `INT p_gtob(TEXT *buf, UINT value, INT radix);` | Unsigned UINT in any radix → buf. |
| `INT p_gltob(TEXT *buf, ULONG value, INT radix);` | Unsigned ULONG in any radix → buf. |

### 5.2 Formatted multi-argument output

| Signature | Purpose |
|---|---|
| `INT p_atob(TEXT *buf, TEXT *fstr, VOID *parg);` | `printf`-style format of arg list `parg` into buf; returns chars written. |
| `VOID p_atos(TEXT *str, TEXT *fstr, ...);` | Convenience variadic wrapper over `p_atob` producing a zero-terminated string. |

Format `%[<align>][<fill>]<width><type>`; types: `b` binary, `c` char, `d`
signed dec, `f` fill only, `m`/`w` 2-byte MSB/LSB binary *(EPOC 2.17+)*, `o`
octal, `s` string, `u` unsigned dec, `x` hex. Widen to long with `l`/`L` or
upper-case type; `<width>`/`<fill>` may be `*` (taken from args).

### 5.3 Text → integer/long (radix conversions)

All take `TEXT **pstr` (advanced past the parsed field on success), return 0 or
`E_GEN_OVER`/`E_GEN_FAIL`.

| Signature | Purpose |
|---|---|
| `INT p_stoi(TEXT **pstr, WORD *pval);` | Signed decimal string → 16-bit WORD. |
| `INT p_stol(TEXT **pstr, LONG *pval);` | Signed decimal string → 32-bit LONG. |
| `INT p_stog(TEXT **pstr, UWORD *pval, INT radix);` | Unsigned string in any radix → 16-bit UWORD. |
| `INT p_stogl(TEXT **pstr, ULONG *pval, INT radix);` | Unsigned string in any radix → 32-bit ULONG. |
| `INT p_stoa(TEXT **pstr, TEXT *fstr, ...);` | Scan multiple fields from a string into args per format `fstr`. |

### 5.4 Double ↔ text (floating point conversion)

| Signature | Purpose |
|---|---|
| `INT p_dtob(TEXT *pbuf, DOUBLE *pval, P_DTOB *pformat);` | Format a double to text per `P_DTOB` (type/width/decimals/point/triad); returns chars or `E_GEN_*`. |
| `INT p_stod(TEXT **pstr, DOUBLE *pval, INT point);` | Parse a floating-point number from text (`point` = decimal-point char) → double. |

> Note: the manual provides no `p_dtos` — double→string is `p_dtob`.

---

## 6. Floating Point, Scientific & Math

Declared in `p_math.h`. Trig args are in **radians**. `E_CONFIG`/config via
`p_getctd`. Two families exist:

- **Scientific functions** (`p_sin` … `p_pow`) and `p_rand`/`p_frand` require the
  8087 emulator (`sys$8087.ldd`).
- **Arithmetic primitives** (`p_fld` … `p_longtof`) are emulator-independent —
  usable to do FP without loading the emulator.

Macros (also emulator-triggering with FP operands): `ABS(x)`, `MAX(a,b)`, `MIN(a,b)`.

### 6.1 Scientific (require emulator)

All return 0 or `E_GEN_ARG`/`E_GEN_UNDER`/`E_GEN_OVER`.

| Signature | Purpose |
|---|---|
| `INT p_sin(DOUBLE *pret, DOUBLE *parg);` | Sine. |
| `INT p_cos(DOUBLE *pret, DOUBLE *parg);` | Cosine. |
| `INT p_tan(DOUBLE *pret, DOUBLE *parg);` | Tangent (arg magnitude limited). |
| `INT p_asin(DOUBLE *pret, DOUBLE *parg);` | Arc sine (`ABS(*parg)<=1`). |
| `INT p_acos(DOUBLE *pret, DOUBLE *parg);` | Arc cosine (`ABS(*parg)<=1`). |
| `INT p_atan(DOUBLE *pret, DOUBLE *parg);` | Arc tangent. |
| `INT p_ln(DOUBLE *pret, DOUBLE *parg);` | Natural (base-e) log. |
| `INT p_exp(DOUBLE *pret, DOUBLE *parg);` | e raised to `*parg`. |
| `INT p_log(DOUBLE *pret, DOUBLE *parg);` | Base-10 log. |
| `INT p_sqrt(DOUBLE *pret, DOUBLE *parg);` | Square root. |
| `INT p_pow(DOUBLE *pret, DOUBLE *parg1, DOUBLE *parg2);` | `*parg1` raised to `*parg2`. |

### 6.2 Emulator-independent FP arithmetic

For one-arg functions, `pret` and `parg` may alias. Return 0 or `E_GEN_*`.

| Signature | Purpose |
|---|---|
| `INT p_fld(DOUBLE *pret, DOUBLE *parg);` | Load: `*pret = *parg`. |
| `INT p_fadd(DOUBLE *pret, DOUBLE *parg);` | `*pret += *parg`. |
| `INT p_fsub(DOUBLE *pret, DOUBLE *parg);` | `*pret -= *parg`. |
| `INT p_fmul(DOUBLE *pret, DOUBLE *parg);` | `*pret *= *parg`. |
| `INT p_fdiv(DOUBLE *pret, DOUBLE *parg);` | `*pret /= *parg`. |
| `INT p_fcmp(DOUBLE *parg1, DOUBLE *parg2);` | Compare: returns 1 / 0 / −1. *(OCR: `p_femp`.)* |
| `INT p_fneg(DOUBLE *parg);` | Negate `*parg` in place. |
| `INT p_mod(DOUBLE *pret, DOUBLE *parg1, DOUBLE *parg2);` | Remainder of `*parg1 / *parg2`. |
| `INT p_int(DOUBLE *pret, DOUBLE *parg);` | Integer part (toward zero) → double. |
| `INT p_inti(WORD *pret, DOUBLE *parg);` | Integer part → 16-bit WORD (range-checked). |
| `INT p_intl(LONG *pret, DOUBLE *parg);` | Integer part → 32-bit LONG (range-checked). |
| `VOID p_itof(DOUBLE *pret, WORD *parg);` | Convert WORD → double. |
| `VOID p_longtof(DOUBLE *pret, LONG *parg);` | Convert LONG → double. |

### 6.3 Random numbers

| Signature | Purpose |
|---|---|
| `ULONG p_randl(ULONG *pseed);` | Next pseudo-random 32-bit long; updates `*pseed`. (No emulator.) |
| `DOUBLE p_rand(ULONG *pseed);` | Random double in [0,1); updates `*pseed`. (Emulator required.) |
| `VOID p_frand(DOUBLE *pret, ULONG *pseed);` | Random double in [0,1) → `*pret`; updates `*pseed`. |

> **Long integer arithmetic:** PLIB exposes no dedicated `p_lmul`/`p_ldiv`
> helpers; 32-bit `LONG`/`ULONG` work is done with native C, the `l*`
> conversion routines above, and `p_ltob`/`p_stol`/`p_stogl`/`p_randl`.

---

## 7. Rectangle & Geometry Utilities

Operate on `P_RECT` / `P_POINT` (declared with the integer-conversion chapter).

| Signature | Purpose |
|---|---|
| `VOID p_offrec(P_RECT *rect, INT xoffset, INT yoffset);` | Move a rectangle by an offset. |
| `VOID p_insrec(P_RECT *rect, INT xinset, INT yinset);` | Shrink/expand a rectangle about its centre. |
| `VOID p_unirec(P_RECT *rect1, P_RECT *rect2, P_RECT *result);` | Union (smallest enclosing rectangle). |
| `INT p_intrec(P_RECT *rect1, P_RECT *rect2, P_RECT *result);` | Intersection; returns TRUE if they intersect. |
| `INT p_pinrec(P_POINT *point, P_RECT *rect);` | TRUE if point lies inside rectangle. |
| `INT p_emprec(P_RECT *rect);` | TRUE if rectangle is empty. |
| `VOID p_absrec(P_RECT *rect, P_RECT *result);` | Normalise negative sides to positive. |

---

## 8. Memory Allocation & the Heap

Heap cells are allocated from the process data segment (max ~64K). `f_*`
variants leave with `E_GEN_NOMEMORY` instead of returning `NULL`.

### 8.1 Cell allocation

| Signature | Purpose |
|---|---|
| `VOID *p_alloc(UINT size);` | Allocate a heap cell ≥ `size` bytes; returns address or `NULL`. |
| `VOID *f_alloc(UINT size);` | As `p_alloc` but leaves on failure. |
| `VOID p_free(VOID *pcell);` | Free a cell (no-op if `pcell` is 0). |
| `VOID *p_realloc(VOID *pcell, UINT size);` | Resize a cell (preserving contents); `pcell==0` ⇒ `p_alloc`. |
| `VOID *f_realloc(VOID *pcell, UINT size);` | As `p_realloc` but leaves on failure. |
| `VOID *p_adjust(VOID *pcell, UINT offset, INT amount);` | Open (+) or close (−) a gap mid-cell for insert/delete. |
| `UINT p_alen(VOID *pcell);` | Return actual cell length in bytes (≥ requested). |

### 8.2 Heap tuning & diagnostics

| Signature | Purpose |
|---|---|
| `VOID p_hgran(UINT nparas);` | Set heap growth granularity (paragraphs of 16 bytes; ≤ `E_MAX_GROWBY`). |
| `VOID p_allwalk(VOID (*fptr)(VOID *fpar, INT isalloc, UINT len), VOID *fpar);` | Walk every heap cell, calling `fptr`; panics on inconsistency. |
| `VOID p_allchk(INT num);` | Check allocated cells vs. free list; `p_panic(0xff)` with diagnostics if corrupt. |
| `UINT p_allspc(VOID **pheap);` | Return potential free heap space; write heap start to `*pheap`. |
| `p_altchk(...)` **[?]** | Thorough heap-integrity check (referenced by name; full signature not printed in source). |

### 8.3 System memory info

| Signature | Purpose |
|---|---|
| `UINT p_getram(VOID);` | Addressable system RAM in 16-byte paragraphs (≤ 32768). |
| `UINT p_totalK(VOID);` | Total machine RAM in KB, ignoring bank-switching. *(EPOC 3.50+)* |
| `UINT p_sgfree(VOID);` | Available addressable segmented memory in paragraphs. |
| `UINT p_sgramdisk(VOID);` | Paragraphs of addressable RAM used by the internal RAM disk. |

### 8.4 External data segments (shared memory / IPC)

| Signature | Purpose |
|---|---|
| `INT p_sgdelete(TEXT *pName);` | Delete a named external data segment. |
| `INT p_sgcopyto(HANDLE nHandle, LONG pos, VOID *source, UINT len);` | Write `len` bytes into an open segment at `pos`. |
| `INT p_sgcopyfr(HANDLE nHandle, LONG pos, VOID *target, UINT len);` | Read `len` bytes from an open segment at `pos`. |
| `UINT p_sgsize(HANDLE nHandle);` | Size of an open segment in 16-byte paragraphs. |
| `INT p_sgadjust(HANDLE nHandle, INT nParas);` | Grow/shrink an open segment by `nParas` paragraphs. |
| `INT p_sgclose(HANDLE nHandle);` | Close an open segment. |
| `VOID p_sglock(HANDLE nHandle);` | Lock a segment against relocation. |
| `VOID p_sgunlock(HANDLE nHandle);` | Unlock a previously locked segment. |

*(The chapter also references `p_sgcreate`/`p_sgopen`/`p_sgfind`; their clean
signatures are not isolated in the source text — **[?]**.)*

### 8.5 Environment variables

| Signature | Purpose |
|---|---|
| `INT p_getenv(TEXT *pMatch, TEXT *pValue);` | Get value of matching env var (string). |
| `INT p_getenviron(TEXT *pMatch, INT mLength, VOID *pValue);` | Get env var value (binary, length-specified match). |
| `INT p_setenv(TEXT *pName, TEXT *pValue);` | Set/create a string env var. |
| `INT p_setenviron(TEXT *pName, INT nLength, VOID *pValue, INT vLength);` | Set a binary env var. |
| `INT p_delenv(TEXT *pMatch);` | Delete matching env var. |
| `INT p_delenviron(TEXT *pMatch, INT mLength);` | Delete env var (length-specified match). |
| `INT p_fndenv(TEXT *pMatch, TEXT *pName, TEXT *pValue, HANDLE *pHandle);` | Iterate/find env vars by name pattern. |
| `INT p_findenviron(TEXT *pMatch, INT mLength, UBYTE *pBuf, HANDLE *pHandle);` | Iterate/find env vars (binary). |

---

## 9. Date, Time & Timers

System time = seconds since 00:00:00 1 Jan 1970 (`ULONG`). Day-based math uses
`P_DAYSEC` (days since 1900 + seconds in day); human form uses `P_DATE`
(year-1900, month 0–11, day 0–30, h/m/s, yrday). Declared in `p_date.h`.

### 9.1 System clock

| Signature | Purpose |
|---|---|
| `ULONG p_date(VOID);` | Return current system time (seconds since 1970). |
| `VOID p_sdate(ULONG newTime);` | Set system time (may fire due absolute timers). |

### 9.2 Sleeping / synchronous timers

| Signature | Purpose |
|---|---|
| `INT p_sleep(ULONG n);` | Sleep `n` tenths of a second (relative timer). |
| `INT p_sleept(LONG nTicks);` | Sleep `nTicks` system ticks (32/s SIBO). |
| `INT p_sleepa(ULONG time);` | Sleep until absolute system `time` (wakes machine). |

*(Asynchronous timers are driven through an open `TIM:` channel via
`p_ioc(P_FRELATIVE)` / `p_ioc(P_FABSOLUTE)` and cancelled with `p_iow(...,P_FCANCEL)`.)*

### 9.3 Date/time conversions

| Signature | Purpose |
|---|---|
| `VOID p_sttods(ULONG *pstim, P_DAYSEC *pds);` | System time → days-since-1900 + seconds-in-day. |
| `INT p_dstost(P_DAYSEC *pds, ULONG *pstim);` | `P_DAYSEC` → system time. |
| `INT p_dstodt(P_DAYSEC *pds, P_DATE *pdt);` | `P_DAYSEC` → `P_DATE` (fills yrday). |
| `INT p_dttods(P_DATE *pdt, P_DAYSEC *pds);` | Validate `P_DATE` → `P_DAYSEC`. |
| `INT p_dayinm(INT year, INT month);` | Days in given month (leap-aware); year since 1900. |
| `INT p_wkday(ULONG nDay);` | Weekday (0=Mon … 6=Sun) for day-since-1900. |
| `INT p_weekno(ULONG nDay);` | Week number 1–53 for day-since-1900. |

### 9.4 Localised name/text lookups

| Signature | Purpose |
|---|---|
| `INT p_nmday(TEXT *buf, INT daynum);` | Language day name (0=Mon … 6). |
| `INT p_nmdaya(TEXT *buf, INT daynum);` | Abbreviated day name. *(EPOC 3.18+)* |
| `INT p_nmmon(TEXT *buf, INT monthnum);` | Language month name (0=Jan … 11). |
| `INT p_nmmona(TEXT *buf, INT monthnum);` | Abbreviated month name. *(EPOC 3.18+; OCR prints this as a second `p_nmmon`.)* |
| `VOID p_getsuffixes(TEXT *buf);` | Fill array of 31 day-of-month suffixes (3-byte elements). |
| `VOID p_getampmtext(TEXT *buf, INT n);` | am (`n=0`) / pm (`n=1`) suffix text. |
| `VOID p_getctd(E_CONFIG *pcfg);` | Copy system locale/config (`E_CONFIG`) struct. |

---

## 10. Object-Oriented Programming Primitives (brief)

PLIB provides run-time OOP: categories (load modules of classes) identified by
category number or `HANDLE`; objects are heap instances with a class header.
`f_*` twins leave with `p_leave` on failure. Declared with the OOP chapter.

### 10.1 Category / object creation & class management

| Signature | Purpose |
|---|---|
| `HANDLE p_getlibh(INT catNum);` | Convert a category number to a category handle (0 = local). |
| `VOID *p_new(INT catNum, INT classNum);` | Create an instance of `classNum` in category `catNum`; property zeroed. |
| `VOID *f_new(INT catNum, INT classNum);` | As `p_new`, leaves on OOM. |
| `VOID *p_newlibh(HANDLE catHandle, INT classNum);` | Create instance by category handle. |
| `VOID *f_newlibh(HANDLE catHandle, INT classNum);` | As `p_newlibh`, leaves on OOM. |
| `VOID *f_newsend(INT catNum, INT classNum, INT methodNum, ...);` | Create then send init `methodNum`; cleans up (destroy) on leave. |
| `VOID *f_newlibhsend(HANDLE catHandle, INT classNum, INT methodNum, ...);` | As `f_newsend` but by category handle. |
| `VOID p_reclass(INT catNum, INT classNum, VOID *pObject);` | Change an object's class (same property length). |
| `VOID p_reclassbyhandle(HANDLE catHandle, INT classNum, VOID *pObject);` | Reclass by category handle. |
| `INT p_loadfilelib(VOID *fcb, UINT n, HANDLE *pCatHandle, INT link);` | Load an external category (load module) and get its handle. |
| `VOID p_linklib(HANDLE catHandle);` | Link a loaded category to the local process. |
| `VOID p_ccpy(VOID *pTarget, VOID *pSource, UINT count);` | Copy `count` bytes (category/object helper copy). |

### 10.2 Message sending

`p_send*` use the stack (`CDECL`) convention; the `p_send2..5` / `f_send2..5`
numbered variants use the faster register convention. `f_*` leaves with
`p_leave(err)` if the method returns negative.

| Signature | Purpose |
|---|---|
| `INT p_send(VOID *pObject, INT methodNum, ...);` | Dispatch `methodNum` to object, searching class then superclasses. |
| `INT f_send(VOID *pObject, INT methodNum, ...);` | As `p_send`, leaves on negative return. |
| `INT p_send2(VOID *pObject, INT methodNum);` … `p_send5(VOID *pObject, INT methodNum, VOID *p1, VOID *p2, VOID *p3);` | Register-convention sends with 0–3 extra args (`f_send2..5` twins). |
| `INT p_supersend(VOID *pObject, INT methodNum, ...);` | Dispatch starting at the superclass of the calling method (`p_supersend2..5`). |
| `INT p_entersend(VOID *pObject, INT methodNum, ...);` | Dispatch as if via `p_enter` (unwinds on `p_leave`) (`p_entersend2..5`). |
| `INT p_exactsend(HANDLE catHandle, INT classNum, VOID *pObject, INT methodNum, ...);` | Dispatch starting at an explicitly named class. |

---

## 11. Related Error/Process Primitives (referenced above)

These appear alongside the categories above and are commonly used with them:

| Signature | Purpose |
|---|---|
| `INT p_enter(VOID *pfunc, ...);` | Enter a function under structured error trapping. |
| `VOID p_panic(INT nPanic);` | Abort the process with a panic number (unrecoverable). |
| `VOID p_exit(INT nReason);` | Graceful process termination. |

*(Full error-handling and process/IPC APIs are outside this core-PLIB scope but
`p_enter`/`p_leave`/`p_panic` underpin the `f_*` allocator and sender twins.)*

---

### Uncertainty notes

- OCR corrected: `p_bcmp`/`p_bcmpi` (src `p_bemp`), `p_fcmp` (src `p_femp`),
  `p_pow` (src fragment `p (…)1_POw`), `p_nmmona` (src duplicate `p_nmmon`).
- `p_altchk`, `p_dequed`, `p_sgcreate`, `p_sgopen`, `p_sgfind` are named in the
  manual but their clean C signatures are not isolated in the source text; marked **[?]**.
- Version-gated functions annotated where the manual states a minimum EPOC version.
