Fun API Documentation
0.42.1
The programming language that makes you have fun!
Main Page
Data Structures
Files
File List
Globals
Loading...
Searching...
No Matches
src
extensions
pcsc.c
Go to the documentation of this file.
1
/*
2
* This file is part of the Fun programming language.
3
* https://fun-lang.xyz/
4
*
5
* Copyright 2025 Johannes Findeisen <you@hanez.org>
6
* Licensed under the terms of the Apache-2.0 license.
7
* https://opensource.org/license/apache-2-0
8
*/
9
10
/**
11
* @file pcsc.c
12
* @brief PC/SC smartcard helper registries and lookup utilities for VM opcodes.
13
*
14
* This module centralizes tiny fixed-size registries for PC/SC resources and
15
* minimal helper functions used by VM opcodes under src/vm/pcsc/*.c. Keeping
16
* the concrete handle management here allows the opcode implementations to
17
* focus on VM stack marshalling, mirroring the approach taken by other
18
* extensions (PCRE2, SQLite, XML2, JSON, INI, cURL, OpenSSL).
19
*
20
* Build-time feature flag:
21
* - All code in this file is compiled only when FUN_WITH_PCSC is enabled. When
22
* disabled, the referencing opcodes should compile to safe no-op fallbacks
23
* (typically pushing 0, Nil, or empty arrays) while retaining the same stack
24
* behaviour.
25
*
26
* Registries and ownership model:
27
* - Context registry (g_pcsc_ctx): stores SCARDCONTEXT values obtained via
28
* SCardEstablishContext(). The registry DOES NOT call SCardReleaseContext()
29
* automatically — releasing is the responsibility of the opcode that owns
30
* the lifecycle. The registry merely tracks usage and provides a stable,
31
* small integer id for referencing a context in later operations.
32
* - Card registry (g_pcsc_card): stores SCARDHANDLE and the negotiated
33
* protocol (proto) obtained via SCardConnect(). Similarly, the registry does
34
* not call SCardDisconnect(); the VM opcode that created the handle is in
35
* charge of eventual teardown.
36
* - Handles are 1-based indices into the fixed arrays (contexts: up to 8,
37
* cards: up to 32). A return value of 0 indicates failure (no free slot or
38
* invalid request).
39
*
40
* Error handling and limits:
41
* - Allocation helpers return 0 when no free slot is available. Lookup helpers
42
* return NULL if the id is out of range or the slot is not currently in use.
43
* - The fixed sizes (8 contexts, 32 cards) are pragmatic defaults for typical
44
* scripts. Increase cautiously if your workloads require more concurrent
45
* resources.
46
*
47
* Thread-safety:
48
* - This module is not thread-safe. If the interpreter is used from multiple
49
* threads, coordinate access to these registries externally.
50
*/
51
52
#ifdef FUN_WITH_PCSC
53
#if defined(__has_include)
54
#if __has_include(<PCSC/winscard.h>)
55
#include <PCSC/winscard.h>
56
#include <PCSC/wintypes.h>
57
#elif __has_include(<winscard.h>)
58
#include <winscard.h>
59
#else
60
#error "FUN_WITH_PCSC is enabled but PCSC headers were not found"
61
#endif
62
#else
63
#include <PCSC/winscard.h>
64
#include <PCSC/wintypes.h>
65
#endif
66
#include <string.h>
67
#include <stdio.h>
68
69
/**
70
* @brief One slot in the PC/SC context registry.
71
*
72
* Ownership notes:
73
* - The registry does not own the context; it merely stores the value returned
74
* by SCardEstablishContext(). Callers/opcodes are responsible for invoking
75
* SCardReleaseContext() at the appropriate time.
76
*/
77
typedef
struct
{
78
SCARDCONTEXT
ctx
;
/**< Established context value. */
79
int
in_use
;
/**< 1 if the slot is currently allocated; 0 otherwise. */
80
}
pcsc_ctx_entry
;
81
82
/**
83
* @brief One slot in the PC/SC card handle registry.
84
*
85
* Ownership notes:
86
* - The registry does not disconnect cards; it only stores the handle returned
87
* by SCardConnect() and the negotiated protocol. The VM opcode that created
88
* the handle is responsible for calling SCardDisconnect().
89
*/
90
typedef
struct
{
91
SCARDHANDLE
h
;
/**< Connected card handle from SCardConnect(). */
92
DWORD
proto
;
/**< Negotiated protocol flags (e.g., SCARD_PROTOCOL_T0/T1). */
93
int
in_use
;
/**< 1 if the slot is currently allocated; 0 otherwise. */
94
}
pcsc_card_entry
;
95
96
static
pcsc_ctx_entry
g_pcsc_ctx
[8];
97
static
pcsc_card_entry
g_pcsc_card
[32];
98
99
/**
100
* @brief Allocate a free context slot in the PC/SC registry.
101
*
102
* Scans the small fixed-size context registry for an available slot, marks it
103
* as in use, clears the stored value, and returns a 1-based identifier.
104
*
105
* @return int A 1-based slot id on success; 0 if no free slot is available.
106
*/
107
static
int
pcsc_alloc_ctx_slot
(
void
) {
108
for
(
int
i = 0; i < (int)(
sizeof
(
g_pcsc_ctx
) /
sizeof
(
g_pcsc_ctx
[0])); ++i) {
109
if
(!
g_pcsc_ctx
[i].in_use) {
110
g_pcsc_ctx
[i].in_use = 1;
111
g_pcsc_ctx
[i].ctx = 0;
112
return
i + 1;
113
}
114
}
115
return
0;
116
}
117
118
/**
119
* @brief Allocate a free card slot in the PC/SC registry.
120
*
121
* Scans the card registry for an unused entry, sets initial values, and
122
* returns a small positive identifier that can be used by opcodes to index the
123
* slot later.
124
*
125
* @return int A 1-based slot id on success; 0 if no free slot is available.
126
*/
127
static
int
pcsc_alloc_card_slot
(
void
) {
128
for
(
int
i = 0; i < (int)(
sizeof
(
g_pcsc_card
) /
sizeof
(
g_pcsc_card
[0])); ++i) {
129
if
(!
g_pcsc_card
[i].in_use) {
130
g_pcsc_card
[i].in_use = 1;
131
g_pcsc_card
[i].h = 0;
132
g_pcsc_card
[i].proto = 0;
133
return
i + 1;
134
}
135
}
136
return
0;
137
}
138
139
/**
140
* @brief Lookup a context slot by id.
141
*
142
* Validates the provided 1-based identifier, ensures the slot is currently in
143
* use, and returns a pointer to the internal registry entry.
144
*
145
* @param id int 1-based context id previously returned by pcsc_alloc_ctx_slot().
146
* @return pcsc_ctx_entry* Pointer to the entry if valid and in use; NULL otherwise.
147
*/
148
static
pcsc_ctx_entry
*
pcsc_get_ctx
(
int
id
) {
149
if
(
id
<= 0)
return
0;
150
int
idx =
id
- 1;
151
if
(idx < 0 || idx >= (
int
)(
sizeof
(
g_pcsc_ctx
) /
sizeof
(
g_pcsc_ctx
[0])))
return
0;
152
if
(!
g_pcsc_ctx
[idx].in_use)
return
0;
153
return
&
g_pcsc_ctx
[idx];
154
}
155
156
/**
157
* @brief Lookup a card slot by id.
158
*
159
* Validates the provided 1-based identifier, ensures the slot is currently in
160
* use, and returns a pointer to the internal registry entry, which exposes the
161
* SCARDHANDLE and negotiated protocol for subsequent operations (e.g.,
162
* SCardTransmit()).
163
*
164
* @param id int 1-based card id previously returned by pcsc_alloc_card_slot().
165
* @return pcsc_card_entry* Pointer to the entry if valid and in use; NULL otherwise.
166
*/
167
static
pcsc_card_entry
*
pcsc_get_card
(
int
id
) {
168
if
(
id
<= 0)
return
0;
169
int
idx =
id
- 1;
170
if
(idx < 0 || idx >= (
int
)(
sizeof
(
g_pcsc_card
) /
sizeof
(
g_pcsc_card
[0])))
return
0;
171
if
(!
g_pcsc_card
[idx].in_use)
return
0;
172
return
&
g_pcsc_card
[idx];
173
}
174
#endif
g_pcsc_card
static pcsc_card_entry g_pcsc_card[32]
Definition
pcsc.c:97
pcsc_get_card
static pcsc_card_entry * pcsc_get_card(int id)
Lookup a card slot by id.
Definition
pcsc.c:167
pcsc_alloc_ctx_slot
static int pcsc_alloc_ctx_slot(void)
Allocate a free context slot in the PC/SC registry.
Definition
pcsc.c:107
g_pcsc_ctx
static pcsc_ctx_entry g_pcsc_ctx[8]
Definition
pcsc.c:96
pcsc_alloc_card_slot
static int pcsc_alloc_card_slot(void)
Allocate a free card slot in the PC/SC registry.
Definition
pcsc.c:127
pcsc_get_ctx
static pcsc_ctx_entry * pcsc_get_ctx(int id)
Lookup a context slot by id.
Definition
pcsc.c:148
pcsc_card_entry
One slot in the PC/SC card handle registry.
Definition
pcsc.c:90
pcsc_card_entry::proto
DWORD proto
Definition
pcsc.c:92
pcsc_card_entry::h
SCARDHANDLE h
Definition
pcsc.c:91
pcsc_card_entry::in_use
int in_use
Definition
pcsc.c:93
pcsc_ctx_entry
One slot in the PC/SC context registry.
Definition
pcsc.c:77
pcsc_ctx_entry::ctx
SCARDCONTEXT ctx
Definition
pcsc.c:78
pcsc_ctx_entry::in_use
int in_use
Definition
pcsc.c:79
Generated on
for Fun API Documentation by
1.16.1