Skip to content

Commit 0a3aab1

Browse files
committed
Start of a wiki describing the fujinet-lib API.
1 parent 58349fa commit 0a3aab1

File tree

93 files changed

+6691
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

93 files changed

+6691
-0
lines changed

generate_full_wiki.py

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
#!/usr/bin/env python3
2+
"""
3+
generate_full_wiki.py
4+
5+
Usage:
6+
cd /home/rich/fujinet-lib
7+
python3 wiki/generate_full_wiki.py [--outdir wiki] [--headers fujinet-fuji.h,fujinet-network.h,fujinet-clock.h]
8+
9+
Creates:
10+
wiki/index.md
11+
wiki/generated/<function>.md
12+
"""
13+
import re
14+
import os
15+
import sys
16+
import argparse
17+
import subprocess
18+
from pathlib import Path
19+
20+
parser = argparse.ArgumentParser()
21+
parser.add_argument('--outdir', default='wiki', help='Output wiki directory (default: wiki)')
22+
parser.add_argument('--headers', default='fujinet-fuji.h,fujinet-network.h,fujinet-clock.h',
23+
help='Comma-separated header filenames relative to repo root')
24+
args = parser.parse_args()
25+
26+
repo_root = Path.cwd()
27+
outdir = (repo_root / args.outdir).resolve()
28+
gen_dir = outdir / 'generated'
29+
gen_dir.mkdir(parents=True, exist_ok=True)
30+
31+
headers = [repo_root / h.strip() for h in args.headers.split(',')]
32+
33+
def read_file(p):
34+
try:
35+
return p.read_text(encoding='utf-8')
36+
except Exception:
37+
return ''
38+
39+
# Heuristic: split header text on semicolons to get candidate declarations
40+
def find_prototypes(text):
41+
candidates = []
42+
parts = re.split(r';', text)
43+
pos = 0
44+
for part in parts:
45+
seg = part.strip()
46+
if not seg:
47+
pos += len(part) + 1
48+
continue
49+
# ignore macros/typedefs/struct/enum lines
50+
if re.search(r'^\s*(#|typedef|struct|enum)\b', seg):
51+
pos += len(part) + 1
52+
continue
53+
# must contain '(' and ')'
54+
if '(' not in seg or ')' not in seg:
55+
pos += len(part) + 1
56+
continue
57+
# avoid function pointer typedefs that start with 'typedef'
58+
# attempt to match a function-like declaration ending with ')'
59+
candidates.append((seg, pos))
60+
pos += len(part) + 1
61+
return candidates
62+
63+
# Extract function name, return type, params from a segment
64+
def parse_candidate(seg):
65+
seg = seg.strip()
66+
# remove possible leading attribute macros like 'extern ' or qualifiers
67+
# attempt regex: (ret_type) (name) (params)
68+
# allow multiline params; remove trailing comments inside
69+
s = re.sub(r'/\*.*?\*/', '', seg, flags=re.DOTALL)
70+
s = re.sub(r'//.*$', '', s, flags=re.MULTILINE)
71+
# Try to find the last identifier before '('
72+
m = re.search(r'([A-Za-z_][A-Za-z0-9_]*)\s*\(\s*([^)]*)\s*\)\s*$', s, flags=re.DOTALL)
73+
if not m:
74+
return None
75+
name = m.group(1)
76+
params = m.group(2).strip()
77+
pre = s[:m.start(1)]
78+
# derive return type = pre trimmed
79+
ret = pre.strip()
80+
# normalize whitespace
81+
ret = re.sub(r'\s+', ' ', ret)
82+
return {'name': name, 'params': params, 'ret': ret, 'raw': seg}
83+
84+
# find header comment block (/** ... */) immediately above a substring index
85+
def find_comment_before(text, seg):
86+
# find segment position
87+
idx = text.find(seg)
88+
if idx == -1:
89+
return ''
90+
# search backward for /** ... */ that ends before idx
91+
# we'll find the last /** ... */ that ends before idx
92+
matches = list(re.finditer(r'/\*\*.*?\*/', text, flags=re.DOTALL))
93+
for m in reversed(matches):
94+
if m.end() <= idx:
95+
# return trimmed comment
96+
return m.group(0).strip()
97+
return ''
98+
99+
# run git grep to find implementations (best-effort). Returns list of matches.
100+
def git_grep(fn_name):
101+
try:
102+
out = subprocess.check_output(['git', 'grep', '-n', '--break', '--heading', '-E', rf'{re.escape(fn_name)}\s*\('],
103+
cwd=repo_root, stderr=subprocess.DEVNULL, text=True)
104+
return [line.rstrip('\n') for line in out.splitlines()]
105+
except Exception:
106+
return []
107+
108+
# Search headers and build function map (header -> list of parsed prototypes)
109+
function_map = {} # header path -> list of entries
110+
for h in headers:
111+
text = read_file(h)
112+
function_map[str(h)] = []
113+
if not text:
114+
continue
115+
candidates = find_prototypes(text)
116+
for seg, _pos in candidates:
117+
parsed = parse_candidate(seg)
118+
if parsed:
119+
# filter out some non-functions (e.g., macros that look like calls)
120+
# ensure name not keyword
121+
if parsed['name'] and not parsed['name'].startswith('('):
122+
parsed['comment'] = find_comment_before(text, seg)
123+
function_map[str(h)].append(parsed)
124+
125+
# Write index.md
126+
index_path = outdir / 'index.md'
127+
with index_path.open('w', encoding='utf-8') as f:
128+
f.write('# FujiNet-lib API Reference\n\n')
129+
f.write('This documentation is generated from the root header files:\n\n')
130+
for h in headers:
131+
f.write(f'- `{h.name}`\n')
132+
f.write('\n## Headers and Functions\n\n')
133+
for h in headers:
134+
f.write(f'### `{h.name}`\n\n')
135+
funcs = function_map.get(str(h), [])
136+
if not funcs:
137+
f.write('_No functions detected in this header._\n\n')
138+
continue
139+
f.write('Functions declared in this header:\n\n')
140+
for p in funcs:
141+
f.write(f'- [`{p["name"]}`](generated/{p["name"]}.md)\n')
142+
f.write('\n')
143+
144+
# Generate per-function pages
145+
for h in headers:
146+
for p in function_map.get(str(h), []):
147+
name = p['name']
148+
out_file = gen_dir / f'{name}.md'
149+
with out_file.open('w', encoding='utf-8') as fh:
150+
fh.write(f'# {name}\n\n')
151+
fh.write(f'**Declared in:** `{h.name}`\n\n')
152+
fh.write('## Prototype\n\n')
153+
fh.write('```c\n')
154+
fh.write(p['raw'].strip() + ';\n')
155+
fh.write('```\n\n')
156+
fh.write('## Description\n\n')
157+
fh.write('_No description available — please add a detailed description of what this function does._\n\n')
158+
fh.write('## Parameters\n\n')
159+
if not p['params'] or p['params'].strip().lower() == 'void':
160+
fh.write('_This function takes no parameters._\n\n')
161+
else:
162+
# split parameters by commas at top-level (no parentheses support of nested)
163+
parts = [pp.strip() for pp in re.split(r',\s*(?![^()]*\))', p['params'])]
164+
fh.write('| Name | Type | Description |\n')
165+
fh.write('|---|---|---|\n')
166+
for part in parts:
167+
# try to split last token as name
168+
if not part:
169+
continue
170+
tokens = part.rsplit(None, 1)
171+
if len(tokens) == 1:
172+
ptype = tokens[0]
173+
pname = ''
174+
else:
175+
ptype, pname = tokens
176+
fh.write(f'| `{pname}` | `{ptype}` | _TODO: describe parameter_ |\n')
177+
fh.write('\n')
178+
fh.write('## Return Value\n\n')
179+
ret = p['ret'] or 'void'
180+
fh.write(f'- **Type:** `{ret}`\n\n')
181+
fh.write('- **Meaning:** _TODO: describe return value and error conditions._\n\n')
182+
fh.write('## Header notes\n\n')
183+
if p.get('comment'):
184+
fh.write('```\n')
185+
fh.write(p['comment'] + '\n')
186+
fh.write('```\n\n')
187+
else:
188+
fh.write('_No header comments found; placeholder for details._\n\n')
189+
fh.write('## Implementations (git grep results)\n\n')
190+
impls = git_grep(name)
191+
if impls:
192+
for line in impls:
193+
fh.write(f'- {line}\n')
194+
else:
195+
fh.write('_No implementations found via git grep._\n')
196+
fh.write('\n')
197+
# Platform stub detection removed per user request.
198+
fh.write('\n----\n\n')
199+
fh.write('[Back to index](../index.md)\n')
200+
201+
print('Generation complete.')
202+
print(f'Main index: {index_path}')
203+
print(f'Per-function pages: {gen_dir}')

wiki/generated/clock_get_time.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# clock_get_time
2+
3+
**Declared in:** `fujinet-clock.h`
4+
5+
## Prototype
6+
7+
```c
8+
/**
9+
* @brief Get the current time in the format specified using the FN timezone.
10+
* @param time_data pointer to buffer for the response. This is uint8_t, but for STRING formats, will be null terminated and can be treated as a string.
11+
* @param format a TimeFormat value to specify how the data should be returned.
12+
* @return fujinet-clock status/error code (See FN_ERR_* values)
13+
*/
14+
uint8_t clock_get_time(uint8_t* time_data, TimeFormat format);
15+
```
16+
17+
## Description
18+
19+
_No description available — please add a detailed description of what this function does._
20+
21+
## Parameters
22+
23+
| Name | Type | Description |
24+
|---|---|---|
25+
| `time_data` | `uint8_t*` | _TODO: describe parameter_ |
26+
| `format` | `TimeFormat` | _TODO: describe parameter_ |
27+
28+
## Return Value
29+
30+
- **Type:** `uint8_t`
31+
32+
- **Meaning:** _TODO: describe return value and error conditions._
33+
34+
## Header notes
35+
36+
```
37+
/**
38+
* @brief Get the FN clock's timezone
39+
* @param tz pointer to the receiving timezone buffer
40+
* @return fujinet-clock status/error code (See FN_ERR_* values)
41+
*/
42+
```
43+
44+
## Implementations (git grep results)
45+
46+
- apple2/apple2-6502/fn_clock/clock_get_time.s
47+
- 52:; uint8_t clock_get_time(uint8_t* time_data, TimeFormat format);
48+
-
49+
- apple2/apple2gs/fn_clock/clock_get_time.asm
50+
- 1:; uint8_t clock_get_time(uint8_t* time_data, TimeFormat format);
51+
-
52+
- atari/src/fn_clock/clock_get_time.s
53+
- 50:; uint8_t clock_get_time(uint8_t* time_data, TimeFormat format);
54+
-
55+
- fujinet-clock.h
56+
- 16:// UNLESS YOU REFACTOR clock_get_time() FUNCTIONS FOR THE PLATFORMS
57+
- 53:uint8_t clock_get_time(uint8_t* time_data, TimeFormat format);
58+
59+
60+
----
61+
62+
[Back to index](../index.md)
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# clock_get_time_tz
2+
3+
**Declared in:** `fujinet-clock.h`
4+
5+
## Prototype
6+
7+
```c
8+
/**
9+
* @brief Get the current time in the format specified for the given timezone without affecting the system timezone
10+
* @param time_data pointer to buffer for the response. This is uint8_t, but for STRING formats, will be null terminated and can be treated as a string.
11+
* @param tz pointer to the receiving timezone buffer.
12+
* @param format a TimeFormat value to specify how the data should be returned.
13+
* @return fujinet-clock status/error code (See FN_ERR_* values)
14+
*/
15+
uint8_t clock_get_time_tz(uint8_t* time_data, const char* tz, TimeFormat format);
16+
```
17+
18+
## Description
19+
20+
_No description available — please add a detailed description of what this function does._
21+
22+
## Parameters
23+
24+
| Name | Type | Description |
25+
|---|---|---|
26+
| `time_data` | `uint8_t*` | _TODO: describe parameter_ |
27+
| `tz` | `const char*` | _TODO: describe parameter_ |
28+
| `format` | `TimeFormat` | _TODO: describe parameter_ |
29+
30+
## Return Value
31+
32+
- **Type:** `uint8_t`
33+
34+
- **Meaning:** _TODO: describe return value and error conditions._
35+
36+
## Header notes
37+
38+
```
39+
/**
40+
* @brief Get the current time in the format specified using the FN timezone.
41+
* @param time_data pointer to buffer for the response. This is uint8_t, but for STRING formats, will be null terminated and can be treated as a string.
42+
* @param format a TimeFormat value to specify how the data should be returned.
43+
* @return fujinet-clock status/error code (See FN_ERR_* values)
44+
*/
45+
```
46+
47+
## Implementations (git grep results)
48+
49+
- apple2/apple2-6502/fn_clock/clock_get_time.s
50+
- 26:; uint8_t clock_get_time_tz(uint8_t* time_data, const char* tz, TimeFormat format);
51+
-
52+
- atari/src/fn_clock/clock_get_time.s
53+
- 21:; uint8_t clock_get_time_tz(uint8_t* time_data, const char* tz, TimeFormat format);
54+
-
55+
- fujinet-clock.h
56+
- 62:uint8_t clock_get_time_tz(uint8_t* time_data, const char* tz, TimeFormat format);
57+
58+
59+
----
60+
61+
[Back to index](../index.md)

wiki/generated/clock_get_tz.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# clock_get_tz
2+
3+
**Declared in:** `fujinet-clock.h`
4+
5+
## Prototype
6+
7+
```c
8+
/**
9+
* @brief Get the FN clock's timezone
10+
* @param tz pointer to the receiving timezone buffer
11+
* @return fujinet-clock status/error code (See FN_ERR_* values)
12+
*/
13+
uint8_t clock_get_tz(char *tz);
14+
```
15+
16+
## Description
17+
18+
_No description available — please add a detailed description of what this function does._
19+
20+
## Parameters
21+
22+
| Name | Type | Description |
23+
|---|---|---|
24+
| `*tz` | `char` | _TODO: describe parameter_ |
25+
26+
## Return Value
27+
28+
- **Type:** `uint8_t`
29+
30+
- **Meaning:** _TODO: describe return value and error conditions._
31+
32+
## Header notes
33+
34+
```
35+
/**
36+
* @brief Set the FN clock's timezone
37+
* @param tz the timezone string to apply
38+
* @return fujinet-clock status/error code (See FN_ERR_* values)
39+
*/
40+
```
41+
42+
## Implementations (git grep results)
43+
44+
- apple2/apple2-6502/fn_clock/clock_get_tz.s
45+
- 15:; uint8_t clock_get_tz(uint8_t* tz);
46+
-
47+
- apple2/apple2gs/fn_clock/clock_get_tz.asm
48+
- 1:; uint8_t clock_get_tz(uint8_t* tz);
49+
-
50+
- atari/src/fn_clock/clock_get_tz.s
51+
- 14:; uint8_t clock_get_tz(uint8_t* tz);
52+
-
53+
- fujinet-clock.h
54+
- 45:uint8_t clock_get_tz(char *tz);
55+
56+
57+
----
58+
59+
[Back to index](../index.md)

0 commit comments

Comments
 (0)