File Coverage

lib/Acme/ExtUtils/XSOne/Test/_header.xs
Criterion Covered Total %
statement 60 64 93.7
branch 30 48 62.5
condition n/a
subroutine n/a
pod n/a
total 90 112 80.3


line stmt bran cond sub pod time code
1             /*
2             * Acme::ExtUtils::XSOne::Test::Calculator - A demonstration of ExtUtils::XSOne
3             *
4             * This header file contains shared state and helper functions
5             * accessible from all Calculator submodules.
6             */
7              
8             #define PERL_NO_GET_CONTEXT
9             #include "EXTERN.h"
10             #include "perl.h"
11             #include "XSUB.h"
12              
13             #include
14             #include
15              
16             /* ========== Shared State ========== */
17              
18             /* Memory for storing calculation results */
19             #define MAX_MEMORY_SLOTS 10
20             static double memory_slots[MAX_MEMORY_SLOTS];
21             static int memory_initialized = 0;
22              
23             /* Calculation history */
24             #define MAX_HISTORY 100
25             typedef struct {
26             char operation; /* +, -, *, /, ^, r (root), etc. */
27             double operand1;
28             double operand2;
29             double result;
30             } HistoryEntry;
31              
32 21           static HistoryEntry history[MAX_HISTORY];
33 21 100         static int history_count = 0;
34 33 100          
35 30           /* Last result (ANS functionality) */
36             static double last_result = 0.0;
37 3            
38             /* ========== Helper Functions ========== */
39 21            
40             static void init_memory(void) {
41 112           if (!memory_initialized) {
42 112 50         for (int i = 0; i < MAX_MEMORY_SLOTS; i++) {
43 112           memory_slots[i] = 0.0;
44 112           }
45 112           memory_initialized = 1;
46 112           }
47 112           }
48              
49 112           static void add_to_history(char op, double a, double b, double result) {
50 112           if (history_count < MAX_HISTORY) {
51             history[history_count].operation = op;
52 8           history[history_count].operand1 = a;
53 8           history[history_count].operand2 = b;
54             history[history_count].result = result;
55             history_count++;
56 8           }
57 8           last_result = result;
58 8 50         }
    50          
59 0            
60             static double get_last_result(void) {
61 8           return last_result;
62 8           }
63              
64             static int store_memory(int slot, double value) {
65 10           init_memory();
66 10           if (slot < 0 || slot >= MAX_MEMORY_SLOTS) {
67 10 50         return 0;
    50          
68 0           }
69             memory_slots[slot] = value;
70 10           return 1;
71             }
72              
73 10           static double recall_memory(int slot) {
74 110 100         init_memory();
75 100           if (slot < 0 || slot >= MAX_MEMORY_SLOTS) {
76             return 0.0;
77 10           }
78 10           return memory_slots[slot];
79 10           }
80              
81             static void clear_all_memory(void) {
82             for (int i = 0; i < MAX_MEMORY_SLOTS; i++) {
83             memory_slots[i] = 0.0;
84             }
85             history_count = 0;
86             last_result = 0.0;
87             }
88              
89 51           /* ========== Generic Import Helper ========== */
90              
91             /*
92             * export_sub - Export a subroutine from source package to caller's namespace
93             * src_pkg: source package name (e.g., "Acme::ExtUtils::XSOne::Test::Calculator::Basic")
94             * name: function name (e.g., "add")
95             * caller: caller's package name
96             */
97 51           static void export_sub(pTHX_ const char *src_pkg, const char *name, const char *caller) {
98             GV *src_gv;
99             GV *dst_gv;
100 51           CV *cv;
101 51           SV *src_name;
102             SV *dst_name;
103 51 50          
    50          
104 0           /* Build fully qualified source name */
105             src_name = newSVpvf("%s::%s", src_pkg, name);
106 51            
107             /* Get the source CV */
108             src_gv = gv_fetchpv(SvPV_nolen(src_name), 0, SVt_PVCV);
109 51           SvREFCNT_dec(src_name);
110              
111             if (!src_gv || !GvCV(src_gv)) {
112 51           croak("\"%s\" is not defined in package %s", name, src_pkg);
113 51           }
114             cv = GvCV(src_gv);
115 51 50          
116 51           /* Build fully qualified destination name */
117 51           dst_name = newSVpvf("%s::%s", caller, name);
118              
119 51           /* Install in caller's namespace */
120             dst_gv = gv_fetchpv(SvPV_nolen(dst_name), GV_ADD, SVt_PVCV);
121             SvREFCNT_dec(dst_name);
122              
123             if (dst_gv) {
124             SvREFCNT_inc((SV*)cv);
125             GvCV_set(dst_gv, cv);
126             }
127             }
128              
129             /*
130             * do_import - Generic import handler
131             * pkg: the package being imported from
132             * exports: array of exportable function names
133 5           * export_count: number of exports
134             * items: number of arguments to import()
135             * ax: argument stack offset
136             *
137             * Call from import() like:
138 5 50         * static const char *basic_exports[] = {"add", "subtract", ...};
    50          
    50          
    50          
    0          
    50          
    50          
139 5 50         * do_import(aTHX_ "...::Basic", basic_exports, 10, items, ax);
    50          
140 0           */
141             static void do_import(pTHX_ const char *pkg, const char **exports, int export_count, I32 items, I32 ax) {
142             const char *caller;
143             int i, j;
144 56 100          
145 52           /* Get caller's package name */
146             caller = CopSTASHPV(PL_curcop);
147             if (!caller || !*caller) {
148 52           caller = "main";
149             }
150 52            
151             /* Process import list (skip first arg which is the package name) */
152             for (i = 1; i < items; i++) {
153 369 100         SV *arg = ST(i);
154 368 100         const char *name;
155 51           STRLEN name_len;
156 51           int found = 0;
157 51            
158             name = SvPV(arg, name_len);
159              
160             /* Find the export */
161 52 100         for (j = 0; j < export_count; j++) {
162 1           if (strcmp(name, exports[j]) == 0) {
163             export_sub(aTHX_ pkg, name, caller);
164             found = 1;
165 4           break;
166             }
167             }
168              
169             if (!found) {
170             croak("\"%s\" is not exported by the %s module", name, pkg);
171             }
172             }
173             }