Check-in [d91d2ed686]

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:added struct types as defined in ffcall, as 't' and 'T' based on pointers with explicit size. !! only for imported functions currently.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256:d91d2ed6865fecd368902289a13ade97457297260f8b1fed28fe8d68a816ab42
User & Date: grable 2018-10-31 22:34:17
Original Comment: added struct types as defined in ffcall as 't' and 'T' based on pointers with explicit size.
Context
2018-10-31
22:37
removed some old todos check-in: 73ad0dee58 user: grable tags: trunk
22:34
added struct types as defined in ffcall, as 't' and 'T' based on pointers with explicit size. !! only for imported functions currently. check-in: d91d2ed686 user: grable tags: trunk
20:16
changes for testing callback typetags check-in: 87ae944ab1 user: grable tags: trunk
Changes

Changes to jimff-call.c.

1
2
3
4
5




6
7
8
9
10
11
12





13
14
15
16
17
18
19
20
21
22
23
24



25
26
27
28
29



30
31
32
33
34
35

36
37
38
39
40
41
42
..
89
90
91
92
93
94
95
96

97




98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
...
145
146
147
148
149
150
151















152
153
154
155
156
157
158
...
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
...
216
217
218
219
220
221
222
223
224
225
226




227
228
229
230
231
232
233
...
258
259
260
261
262
263
264

265


266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285

/****************************************************************************************************
 * jimff - jimtcl function symbols
 *
 */





// helper macro for calling avcall_start & vacall_start using the type enums instead of the named macros
#define av_start( LIST, FUNC, RADDR, TYPE)														\
	avcall_start( &(LIST), (LIST)._av_alist_flexarray._av_m_args,							\
						&(LIST)._av_alist_flexarray._av_m_args[__AV_ALIST_WORDS],	\
						(__avword(*)())(FUNC), (RADDR), (TYPE), __AV_START_FLAGS)
						





#define DPFLAGS(t)	(((t) == 'P') ? JIMFF_DYNAMIC_POINTER_FLAGS : 0)

static int prepare_call( struct jimff_context* ctx, av_alist* avlist, const struct jimff_symbol* sym, int argc, Jim_Obj* const argv[], union jimff_result* result) {
	union jimff_result tmp;
	struct {
		const char* p;
		int l;
	} str;
	char* errmsg;
	int errlen;
	
#define AV	(*avlist)



	
	// handle blitzmax Long results via pointer argument
	if(sym->typeinfo.typetag[0] == 'q' || sym->typeinfo.typetag[0] == 'Q') {
		av_start( AV, sym->addr, NULL, JIMFF_TYPE_VOID);
		av_ptr( AV, union jimff_result*, result);



	} else {
		av_start( AV, sym->addr, result, sym->typeinfo.returntype);
	}
	
	int numptrs = 0;
	int numcbs = 0;

	int arg = 0;
	const char* t;
	for( t = sym->typeinfo.typetag + 1; ; t++) {
		if(arg >= argc) goto done_with_args;
		switch(*t) {
			case '\0':	goto done_with_args;
			
................................................................................
			case 'f':
			case 'd':
				if(Jim_GetDouble( ctx->interp, argv[arg], &tmp.d) != JIM_OK) return JIM_ERR;
				if(*t == 'd') av_double( AV, tmp.d);
				else av_float( AV, (float)tmp.d);
				break;
			
			case 'p': {

				int size;




				void* p = jimff_getpointer( ctx, argv[arg], &size, 0);
				if(size == -1) goto err_invalid_pointer;
				if(sym->typeinfo.pointersizes[numptrs] && sym->typeinfo.pointersizes[numptrs] != size) goto err_invalid_ptrsize;
				numptrs++;
				av_ptr( AV, void*, p);
				break;
			}
			
			case 'P': {
				int size;
				void* p = jimff_forget_pointer( ctx, argv[arg], &size, sym->typeinfo.pointersizes[numptrs]);
				if(size == -1) goto err_invalid_pointer;
				numptrs++;
				av_ptr( AV, void*, p);
				break;
			}
			
			case 'x': {
				struct jimff_callback* cb = jimff_getcallback( ctx, argv[arg]);
				if(!cb || !(cb->flags & JIMFF_FLAG_REGISTERED)) goto err_invalid_callback;
................................................................................
				if(Jim_GetWide( ctx->interp, argv[arg], &tmp.w) == JIM_OK) av_longlong( AV, tmp.w);
				else if(Jim_GetDouble( ctx->interp, argv[arg], &tmp.d) == JIM_OK) av_double( AV, tmp.d);
				else {
					str.p = Jim_GetString( argv[arg], &str.l);
					av_longlong( AV, (str.l > 0) ? (long long)(intptr_t)str.p : 0);
				}
				break;















		}
		
		arg++;
	}

done_with_args:
	if(*t != 0 || arg < argc) goto err_invalid_args;
................................................................................
	errmsg = Jim_Alloc(JIMFF_ERRMSG_MAXLEN);
	errlen = snprintf( errmsg, JIMFF_ERRMSG_MAXLEN, JIMFF_NAMESPACE_NAME ": argument #%d \"%s\" is not a valid callback", (1 + arg), Jim_String(argv[arg]));
	Jim_SetResult( ctx->interp, Jim_NewStringObjNoAlloc( ctx->interp, errmsg, errlen));
	return JIM_ERR;
	
err_invalid_callback_typetag:
	errmsg = Jim_Alloc(JIMFF_ERRMSG_MAXLEN);
	errlen = snprintf( errmsg, JIMFF_ERRMSG_MAXLEN, JIMFF_NAMESPACE_NAME ": argument #%d \"%s\" callback has invalid typetag", (1 + arg), Jim_String(argv[arg]));
	Jim_SetResult( ctx->interp, Jim_NewStringObjNoAlloc( ctx->interp, errmsg, errlen));
	return JIM_ERR;
	
err_invalid_pointer:
	errmsg = Jim_Alloc(JIMFF_ERRMSG_MAXLEN);
	errlen = snprintf( errmsg, JIMFF_ERRMSG_MAXLEN, JIMFF_NAMESPACE_NAME ": argument #%d \"%s\" is not a valid pointer", (1 + arg), Jim_String(argv[arg]));
	Jim_SetResult( ctx->interp, Jim_NewStringObjNoAlloc( ctx->interp, errmsg, errlen));
	return JIM_ERR;
	
err_invalid_ptrsize:
	errmsg = Jim_Alloc(JIMFF_ERRMSG_MAXLEN);
	errlen = snprintf( errmsg, JIMFF_ERRMSG_MAXLEN, JIMFF_NAMESPACE_NAME ": argument #%d \"%s\" pointer is not of valid size, expected %d", (1 + arg), Jim_String(argv[arg]), sym->typeinfo.pointersizes[arg]);
	Jim_SetResult( ctx->interp, Jim_NewStringObjNoAlloc( ctx->interp, errmsg, errlen));
	return JIM_ERR;
	
#undef AV
}

JIMFF_API Jim_Obj* jimff_newresult( struct jimff_context* ctx, const struct jimff_symbol* sym, const union jimff_result* result) {
................................................................................
				case 'Z': {
					Jim_Obj* obj = Jim_NewStringObj( ctx->interp, result->Z ?: "", -1);
					//TODO: is it correct to free Z return values?
					free(result->Z);
					return obj;
				}
				default:
					return jimff_newpointer( ctx, result->p, 0, DPFLAGS(sym->typeinfo.typetag[0]));
			}
		//TODO: implement avcall struct results
		//case JIMFF_TYPE_STRUCT:




	}
	return ctx->interp->emptyObj;
}

JIMFF_API int jimff_prepare_call( struct jimff_context* ctx, av_alist* avlist, const struct jimff_symbol* sym, int argc, Jim_Obj* const argv[], union jimff_result* result) {
	assert( ctx );
	assert( avlist );
................................................................................
}

JIMFF_API int jimff_call( struct jimff_context* ctx, const struct jimff_symbol* sym, int argc, Jim_Obj* const argv[]) {
	assert( ctx );
	assert( sym );
	
	av_alist avlist;

	union jimff_result result = { 0 };


	
	if(prepare_call( ctx, &avlist, sym, argc, argv, &result) != JIM_OK) return JIM_ERR;
	
	if(ctx->cberror) {
		Jim_DecrRefCount( ctx->interp, ctx->cberror);
		ctx->cberror = NULL;
	}
	av_call(avlist);
	if(ctx->cberror != NULL) {
		Jim_DecrRefCount( ctx->interp, ctx->cberror);
		Jim_SetResult( ctx->interp, ctx->cberror);
		ctx->cberror = NULL;
		return JIM_ERR;
	}
	
	Jim_SetResult( ctx->interp, jimff_newresult( ctx, sym, &result));
	return JIM_OK;
}

#undef DPFLAGS





>
>
>
>







>
>
>
>
>












>
>
>





>
>
>




|
|
>







 







|
>

>
>
>
>
|



<
<
<
<
<
<
<
<
<







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







|











|







 







|

<
|
>
>
>
>







 







>
|
>
>

|













|




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
...
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122









123
124
125
126
127
128
129
...
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
...
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
...
243
244
245
246
247
248
249
250
251

252
253
254
255
256
257
258
259
260
261
262
263
...
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318

/****************************************************************************************************
 * jimff - jimtcl function symbols
 *
 */
 
// this is the size of stack buffer used to hold structure results
#define JIMFF_MAXIMUM_STRUCT_SIZE	1024
 

// helper macro for calling avcall_start & vacall_start using the type enums instead of the named macros
#define av_start( LIST, FUNC, RADDR, TYPE)														\
	avcall_start( &(LIST), (LIST)._av_alist_flexarray._av_m_args,							\
						&(LIST)._av_alist_flexarray._av_m_args[__AV_ALIST_WORDS],	\
						(__avword(*)())(FUNC), (RADDR), (TYPE), __AV_START_FLAGS)
						
#define av_start_struct( LIST, FUNC, SIZE, RADDR)												\
	avcall_start_struct( &(LIST), (LIST)._av_alist_flexarray._av_m_args,					\
						&(LIST)._av_alist_flexarray._av_m_args[__AV_ALIST_WORDS],	\
						(__avword(*)())(FUNC), (SIZE), 0, (RADDR), __AV_START_FLAGS)
						
#define DPFLAGS(t)	(((t) == 'P') ? JIMFF_DYNAMIC_POINTER_FLAGS : 0)

static int prepare_call( struct jimff_context* ctx, av_alist* avlist, const struct jimff_symbol* sym, int argc, Jim_Obj* const argv[], union jimff_result* result) {
	union jimff_result tmp;
	struct {
		const char* p;
		int l;
	} str;
	char* errmsg;
	int errlen;
	
#define AV	(*avlist)
	
	int numptrs = 0;
	int numcbs = 0;
	
	// handle blitzmax Long results via pointer argument
	if(sym->typeinfo.typetag[0] == 'q' || sym->typeinfo.typetag[0] == 'Q') {
		av_start( AV, sym->addr, NULL, JIMFF_TYPE_VOID);
		av_ptr( AV, union jimff_result*, result);
	} else if(sym->typeinfo.returntype == JIMFF_TYPE_STRUCT) {
		av_start_struct( AV, sym->addr, sym->typeinfo.pointersizes[0], result);
		numptrs++;
	} else {
		av_start( AV, sym->addr, result, sym->typeinfo.returntype);
	}
	
	if(sym->typeinfo.typetag[0] == 'x') numcbs++;
	else if(sym->typeinfo.returntype == JIMFF_TYPE_VOIDP) numptrs++;
	
	int arg = 0;
	const char* t;
	for( t = sym->typeinfo.typetag + 1; ; t++) {
		if(arg >= argc) goto done_with_args;
		switch(*t) {
			case '\0':	goto done_with_args;
			
................................................................................
			case 'f':
			case 'd':
				if(Jim_GetDouble( ctx->interp, argv[arg], &tmp.d) != JIM_OK) return JIM_ERR;
				if(*t == 'd') av_double( AV, tmp.d);
				else av_float( AV, (float)tmp.d);
				break;
			
			case 'p':
			case 'P': {
				int size;
				void* p;
				if(*t == 'T')
					p = jimff_forget_pointer( ctx, argv[arg], &size, sym->typeinfo.pointersizes[numptrs]);
				else
					p = jimff_getpointer( ctx, argv[arg], &size, 0);
				if(size == -1) goto err_invalid_pointer;
				if(sym->typeinfo.pointersizes[numptrs] && sym->typeinfo.pointersizes[numptrs] != size) goto err_invalid_ptrsize;
				numptrs++;









				av_ptr( AV, void*, p);
				break;
			}
			
			case 'x': {
				struct jimff_callback* cb = jimff_getcallback( ctx, argv[arg]);
				if(!cb || !(cb->flags & JIMFF_FLAG_REGISTERED)) goto err_invalid_callback;
................................................................................
				if(Jim_GetWide( ctx->interp, argv[arg], &tmp.w) == JIM_OK) av_longlong( AV, tmp.w);
				else if(Jim_GetDouble( ctx->interp, argv[arg], &tmp.d) == JIM_OK) av_double( AV, tmp.d);
				else {
					str.p = Jim_GetString( argv[arg], &str.l);
					av_longlong( AV, (str.l > 0) ? (long long)(intptr_t)str.p : 0);
				}
				break;
			
			case 't':
			case 'T': {
				int size;
				void* p;
				if(*t == 'T')
					p = jimff_forget_pointer( ctx, argv[arg], &size, sym->typeinfo.pointersizes[numptrs]);
				else
					p = jimff_getpointer( ctx, argv[arg], &size, 0);
				if(size == -1) goto err_invalid_pointer;
				if(sym->typeinfo.pointersizes[numptrs] != size) goto err_invalid_ptrsize;
				avcall_arg_struct( avlist, size, 4, p);
				numptrs++;
				break;
			}
		}
		
		arg++;
	}

done_with_args:
	if(*t != 0 || arg < argc) goto err_invalid_args;
................................................................................
	errmsg = Jim_Alloc(JIMFF_ERRMSG_MAXLEN);
	errlen = snprintf( errmsg, JIMFF_ERRMSG_MAXLEN, JIMFF_NAMESPACE_NAME ": argument #%d \"%s\" is not a valid callback", (1 + arg), Jim_String(argv[arg]));
	Jim_SetResult( ctx->interp, Jim_NewStringObjNoAlloc( ctx->interp, errmsg, errlen));
	return JIM_ERR;
	
err_invalid_callback_typetag:
	errmsg = Jim_Alloc(JIMFF_ERRMSG_MAXLEN);
	errlen = snprintf( errmsg, JIMFF_ERRMSG_MAXLEN, JIMFF_NAMESPACE_NAME ": argument #%d \"%s\" callback has invalid typetag, expected \"%s\"", (1 + arg), Jim_String(argv[arg]), sym->typeinfo.callbacks[numcbs]);
	Jim_SetResult( ctx->interp, Jim_NewStringObjNoAlloc( ctx->interp, errmsg, errlen));
	return JIM_ERR;
	
err_invalid_pointer:
	errmsg = Jim_Alloc(JIMFF_ERRMSG_MAXLEN);
	errlen = snprintf( errmsg, JIMFF_ERRMSG_MAXLEN, JIMFF_NAMESPACE_NAME ": argument #%d \"%s\" is not a valid pointer", (1 + arg), Jim_String(argv[arg]));
	Jim_SetResult( ctx->interp, Jim_NewStringObjNoAlloc( ctx->interp, errmsg, errlen));
	return JIM_ERR;
	
err_invalid_ptrsize:
	errmsg = Jim_Alloc(JIMFF_ERRMSG_MAXLEN);
	errlen = snprintf( errmsg, JIMFF_ERRMSG_MAXLEN, JIMFF_NAMESPACE_NAME ": argument #%d \"%s\" pointer is not of valid size, expected %d", (1 + arg), Jim_String(argv[arg]), sym->typeinfo.pointersizes[numptrs]);
	Jim_SetResult( ctx->interp, Jim_NewStringObjNoAlloc( ctx->interp, errmsg, errlen));
	return JIM_ERR;
	
#undef AV
}

JIMFF_API Jim_Obj* jimff_newresult( struct jimff_context* ctx, const struct jimff_symbol* sym, const union jimff_result* result) {
................................................................................
				case 'Z': {
					Jim_Obj* obj = Jim_NewStringObj( ctx->interp, result->Z ?: "", -1);
					//TODO: is it correct to free Z return values?
					free(result->Z);
					return obj;
				}
				default:
					return jimff_newpointer( ctx, result->p, sym->typeinfo.pointersizes[0], DPFLAGS(sym->typeinfo.typetag[0]));
			}

		case JIMFF_TYPE_STRUCT: {
			void* p = malloc(sym->typeinfo.pointersizes[0]);
			memcpy( p, result, sym->typeinfo.pointersizes[0]);
			return jimff_newpointer( ctx, p, sym->typeinfo.pointersizes[0], JIMFF_DYNAMIC_POINTER_FLAGS);
		}
	}
	return ctx->interp->emptyObj;
}

JIMFF_API int jimff_prepare_call( struct jimff_context* ctx, av_alist* avlist, const struct jimff_symbol* sym, int argc, Jim_Obj* const argv[], union jimff_result* result) {
	assert( ctx );
	assert( avlist );
................................................................................
}

JIMFF_API int jimff_call( struct jimff_context* ctx, const struct jimff_symbol* sym, int argc, Jim_Obj* const argv[]) {
	assert( ctx );
	assert( sym );
	
	av_alist avlist;
	union {
		union jimff_result result;
		char bytes[JIMFF_MAXIMUM_STRUCT_SIZE];
	} buffer = { 0 };
	
	if(prepare_call( ctx, &avlist, sym, argc, argv, &buffer.result) != JIM_OK) return JIM_ERR;
	
	if(ctx->cberror) {
		Jim_DecrRefCount( ctx->interp, ctx->cberror);
		ctx->cberror = NULL;
	}
	av_call(avlist);
	if(ctx->cberror != NULL) {
		Jim_DecrRefCount( ctx->interp, ctx->cberror);
		Jim_SetResult( ctx->interp, ctx->cberror);
		ctx->cberror = NULL;
		return JIM_ERR;
	}
	
	Jim_SetResult( ctx->interp, jimff_newresult( ctx, sym, &buffer.result));
	return JIM_OK;
}

#undef DPFLAGS

Changes to jimff.c.

121
122
123
124
125
126
127


128
129
130
131
132
133
134
...
143
144
145
146
147
148
149
150

151
152
153
154
155
156
157
...
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
...
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
		case 'f':	return JIMFF_TYPE_FLOAT;
		case 'd':	return JIMFF_TYPE_DOUBLE;
		case 'p':
		case 'P':
		case 'x':
		case 'z':	
		case 'Z':	return JIMFF_TYPE_VOIDP;


		default:	return 0;
	}
}

//NOTE: checks if a typetag  string is valid, compresses it in the process and stores it in result, allso stores the returntype, returns 1=success or 0=failure
static int jimff_validate_typetag( const char* typetag, struct jimff_typeinfo* typeinfo) {
	assert( typetag );
................................................................................
	int mode = 0;
	char* tmp;
	char* end;
	int size;
	int numptrsizes = 0;
	int numcallbacks = 0;
	int lastwasp = 0;
	int lastwascb = 0;

	//TODO: define this magic "1 result + 126 arguments + zero terminator" somewhere
	int ptrsizes[128];
	char* callbacks[128];
	char buffer[128];
	char cbuffer[128];
	
	for( ;; typetag++) {
................................................................................
					ch = *(++typetag);
					if(ch == '\n') break;
					if(ch == '\0') goto done;
				}
				break;
				
			case '0' ... '9':
				if(!lastwasp) return 0;	// error
				size = strtol( typetag, &end, 0);
				if(end == typetag) return 0; // error
				typetag = end - 1;
				ptrsizes[numptrsizes-1] = size;
				break;
			
			case '(':
				if(!lastwascb) return 0; // error
				mode = 1;
				clen = 0;
				break;
			case ')':
				if(mode != 1) return 0; // error
				mode = 0;
				if(clen == 0) cbuffer[clen++] = 'v'; // default to void result if empty ()
................................................................................
						if(!gotrtype) {
							typeinfo->returntype = type;
							gotrtype = 1;
						} else {
							argc++;
						}
						buffer[len++] = ch;
						if(lastwasp = (ch == 'p' || ch == 'P')) {
							ptrsizes[numptrsizes++] = 0;
						} else if(lastwascb = (ch == 'x')) {
							callbacks[numcallbacks++] = 0;
						}
					} else if(mode == 1) {
						cbuffer[clen++] = ch;
					}
				} else {
					return 0; // error







>
>







 







|
>







 







|







|







 







|

|







121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
...
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
...
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
...
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
		case 'f':	return JIMFF_TYPE_FLOAT;
		case 'd':	return JIMFF_TYPE_DOUBLE;
		case 'p':
		case 'P':
		case 'x':
		case 'z':	
		case 'Z':	return JIMFF_TYPE_VOIDP;
		case 't':
		case 'T':	return JIMFF_TYPE_STRUCT;
		default:	return 0;
	}
}

//NOTE: checks if a typetag  string is valid, compresses it in the process and stores it in result, allso stores the returntype, returns 1=success or 0=failure
static int jimff_validate_typetag( const char* typetag, struct jimff_typeinfo* typeinfo) {
	assert( typetag );
................................................................................
	int mode = 0;
	char* tmp;
	char* end;
	int size;
	int numptrsizes = 0;
	int numcallbacks = 0;
	int lastwasp = 0;
	int lastwasx = 0;
	int lastwast = 0;
	//TODO: define this magic "1 result + 126 arguments + zero terminator" somewhere
	int ptrsizes[128];
	char* callbacks[128];
	char buffer[128];
	char cbuffer[128];
	
	for( ;; typetag++) {
................................................................................
					ch = *(++typetag);
					if(ch == '\n') break;
					if(ch == '\0') goto done;
				}
				break;
				
			case '0' ... '9':
				if(!lastwasp && !lastwast) return 0;	// error
				size = strtol( typetag, &end, 0);
				if(end == typetag) return 0; // error
				typetag = end - 1;
				ptrsizes[numptrsizes-1] = size;
				break;
			
			case '(':
				if(!lastwasx) return 0; // error
				mode = 1;
				clen = 0;
				break;
			case ')':
				if(mode != 1) return 0; // error
				mode = 0;
				if(clen == 0) cbuffer[clen++] = 'v'; // default to void result if empty ()
................................................................................
						if(!gotrtype) {
							typeinfo->returntype = type;
							gotrtype = 1;
						} else {
							argc++;
						}
						buffer[len++] = ch;
						if((lastwasp = (ch == 'p' || ch == 'P')) || (lastwast = (ch == 't' || ch == 'T'))) {
							ptrsizes[numptrsizes++] = 0;
						} else if(lastwasx = (ch == 'x')) {
							callbacks[numcallbacks++] = 0;
						}
					} else if(mode == 1) {
						cbuffer[clen++] = ch;
					}
				} else {
					return 0; // error

Changes to jimff.h.

61
62
63
64
65
66
67
68

69
70
71
72
73
74
75
	signed long long w, q;			// JIMFF_TYPE_LONGLONG
	unsigned long long W, Q;	// JIMFF_TYPE_ULONGLONG
	float f;									// JIMFF_TYPE_FLOAT
	double d;								// JIMFF_TYPE_DOUBLE
	callback_t x;							// JIMFF_TYPE_VOIDP
	const char* z;						// JIMFF_TYPE_VOIDP
	char* Z;								// JIMFF_TYPE_VOIDP
	void* p, *P;							// JIMFF_TYPE_VOIDP

};

// argument union for jimff_import_symbol()
union jimff_argument {
	const char* typetag;
	char* typetag_c;
	int size;







|
>







61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
	signed long long w, q;			// JIMFF_TYPE_LONGLONG
	unsigned long long W, Q;	// JIMFF_TYPE_ULONGLONG
	float f;									// JIMFF_TYPE_FLOAT
	double d;								// JIMFF_TYPE_DOUBLE
	callback_t x;							// JIMFF_TYPE_VOIDP
	const char* z;						// JIMFF_TYPE_VOIDP
	char* Z;								// JIMFF_TYPE_VOIDP
	void* p, *P;							// JIMFF_TYPE_STRUCT
	void* t, *T;							// JIMFF_TYPE_STRUCT
};

// argument union for jimff_import_symbol()
union jimff_argument {
	const char* typetag;
	char* typetag_c;
	int size;

Changes to jimff_test.tcl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15




16




17
18
19

20
21
22
23


24
25
26
27
28



29
30


31
32
33
34
35
36





37
38
39
40
41
42






43
44




45















lappend auto_path .
package require jimff

jimff ff

# returns symbol and typetag if imported/registered
proc find-symbol {{type -function} name} {
	set n [ff::info $type -typetags]
	set i [lsearch $n $name]
	if {$i >= 0} {
		lrange $n $i $i+1
	} else {
		return "symbol $type \"$name\" not found"
	}




}





set lib [ff::load test_lib.dll]


ff::import -function $lib {__malloc	malloc}	Pi
ff::import -function $lib {__strcpy	strcpy}	ppz
ff::import -function $lib {__strcat	strcat}	ppz
ff::import -function $lib {__free		free}		vP



ff::import -function test_callback vzx(iizd)
set test_1 [ff::callback test_1 iizd]
puts [find-symbol -function test_callback]
puts [find-symbol -callback test_1]




set p [malloc 64]


ff::pointer -size $p 64
strcpy $p "Hello"
strcat $p " World!"
puts p=[ff::gets $p]
puts gets->s=[ff::gets $p 6 s]
puts s=$s






proc test_1 {i z f} {
   puts "\ti=$i"
   puts "\tz=\"$z\""
   puts "\tf=$f"
   expr $i + 1






}
test_callback "message" $test_1

























|
<
<
<
<
<
<
<
|
>
>
>
>
|
>
>
>
>

<
<
>
|
|
|
|
>
>

<
<
|
|
>
>
>

<
>
>
|
<
<
<
<
|
>
>
>
>
>

<
<
<
<
<
>
>
>
>
>
>
|
<
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7







8
9
10
11
12
13
14
15
16
17
18


19
20
21
22
23
24
25
26


27
28
29
30
31
32

33
34
35




36
37
38
39
40
41
42





43
44
45
46
47
48
49

50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68

lappend auto_path .
package require jimff

jimff ff

ff::load test_lib.dll








# structs as arguments
ff::import test_Point vt8			;# struct Point { int x; int y; }
ff::import test_Symbol vt16	;# struct Symbol { int id; int flags; const char* name; int length; }
ff::import test_Buffer vt20		;# struct Buffer { int length; char bytes[16]; }

# structs as results
ff::import result_Point t8ii
ff::import result_Symbol t16iizi
ff::import result_Buffer t20ip



# for messing structs as pointers
ff::import read_int ipi
ff::import {read_int read_ptr} ppi
ff::import write_int vpii
ff::import {write_int write_ptr} vpip
ff::import {__strdup strdup} Pz
ff::import {__strlen strlen} ip



# testing struct Point argument, size=8
set point [ff::pointer -alloc 8]
write_int $point 0 100
write_int $point 4 200
test_Point $point


# testing struct Symbol argument, size=16
set name [strdup "symbol"]
ff::pointer -size $name [strlen $name]




set symbol [ff::pointer -alloc 16]
write_int $symbol 0 1
write_int $symbol 4 0x55
write_ptr $symbol 8 $name
write_int $symbol 12 [ff::pointer -size $name]
test_Symbol $symbol






# testing struct Buffer argument, size=20
set data "Hello World!\0"
set buffer [ff::pointer -alloc 20]
write_int $buffer 0 [string length $data]
ff::write $buffer 4 $data
test_Buffer $buffer


# testing struct Point result, size=8
set rpoint [result_Point 100 200]
if {$rpoint ne ""} {
	puts "result_Point [read_int $rpoint 0], [read_int $rpoint 4]"
}

# testing struct Symbol result, size=16
set rsymbol [result_Symbol 1 0x55 "symbol" 6]
if {$rsymbol ne ""} {
	puts "result_Symbol [read_int $rsymbol 0] [format 0x%X [read_int $rsymbol 4]] \"[ff::gets [read_ptr $rsymbol 8]]\"([read_int $rsymbol 12])"
}

# testing struct Buffer result, size=20
set bytes [strdup "Hello World!\0"]
set rbuffer [result_Buffer 13 $bytes]
if {$rbuffer ne ""} {
	puts "result_Buffer [read_int $rbuffer 0] \"[ff::gets $rbuffer 4]\""
}

Added jimff_test_callbacks.tcl.



























































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

lappend auto_path .
package require jimff

jimff ff

# returns symbol and typetag if imported/registered
proc find-symbol {{type -function} name} {
	set n [ff::info $type -typetags]
	set i [lsearch $n $name]
	if {$i >= 0} {
		lrange $n $i $i+1
	} else {
		return "symbol $type \"$name\" not found"
	}
}

set lib [ff::load test_lib.dll]

ff::import -function $lib {__malloc	malloc}	Pi
ff::import -function $lib {__strcpy	strcpy}	ppz
ff::import -function $lib {__strcat	strcat}	ppz
ff::import -function $lib {__free		free}		vP

ff::import -function test_callback vzx(iizd)
set test_1 [ff::callback test_1 iizd]
puts [find-symbol -function test_callback]
puts [find-symbol -callback test_1]

set p [malloc 64]
ff::pointer -size $p 64
strcpy $p "Hello"
strcat $p " World!"
puts p=[ff::gets $p]
puts gets->s=[ff::gets $p 6 s]
puts s=$s

proc test_1 {i z f} {
   puts "\ti=$i"
   puts "\tz=\"$z\""
   puts "\tf=$f"
   expr $i + 1
}
test_callback "message" $test_1

Added jimff_test_structs.tcl.









































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68

lappend auto_path .
package require jimff

jimff ff

ff::load test_lib.dll

# structs as arguments
ff::import test_Point vt8			;# struct Point { int x; int y; }
ff::import test_Symbol vt16	;# struct Symbol { int id; int flags; const char* name; int length; }
ff::import test_Buffer vt20		;# struct Buffer { int length; char bytes[16]; }

# structs as results
ff::import result_Point t8ii
ff::import result_Symbol t16iizi
ff::import result_Buffer t20ip

# for messing structs as pointers
ff::import read_int ipi
ff::import {read_int read_ptr} ppi
ff::import write_int vpii
ff::import {write_int write_ptr} vpip
ff::import {__strdup strdup} Pz
ff::import {__strlen strlen} ip

# testing struct Point argument, size=8
set point [ff::pointer -alloc 8]
write_int $point 0 100
write_int $point 4 200
test_Point $point

# testing struct Symbol argument, size=16
set name [strdup "symbol"]
ff::pointer -size $name [strlen $name]
set symbol [ff::pointer -alloc 16]
write_int $symbol 0 1
write_int $symbol 4 0x55
write_ptr $symbol 8 $name
write_int $symbol 12 [ff::pointer -size $name]
test_Symbol $symbol

# testing struct Buffer argument, size=20
set data "Hello World!\0"
set buffer [ff::pointer -alloc 20]
write_int $buffer 0 [string length $data]
ff::write $buffer 4 $data
test_Buffer $buffer

# testing struct Point result, size=8
set rpoint [result_Point 100 200]
if {$rpoint ne ""} {
	puts "result_Point [read_int $rpoint 0], [read_int $rpoint 4]"
}

# testing struct Symbol result, size=16
set rsymbol [result_Symbol 1 0x55 "symbol" 6]
if {$rsymbol ne ""} {
	puts "result_Symbol [read_int $rsymbol 0] [format 0x%X [read_int $rsymbol 4]] \"[ff::gets [read_ptr $rsymbol 8]]\"([read_int $rsymbol 12])"
}

# testing struct Buffer result, size=20
set bytes [strdup "Hello World!\0"]
set rbuffer [result_Buffer 13 $bytes]
if {$rbuffer ne ""} {
	puts "result_Buffer [read_int $rbuffer 0] \"[ff::gets $rbuffer 4]\""
}

Changes to test_lib.c.

1
2
3
4
5



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65














































#include <stdio.h>
#include <stdlib.h>
#include <string.h>




__declspec(dllexport) void print( const char* s) {
	puts(s);
}

__declspec(dllexport) long long test( void* x) {
	printf( "0x%p\n", x);
	return 0xCAFEF00DDEADBABELL;
}

typedef intptr_t (*callback_fn)();

__declspec(dllexport) void test_callback( const char* msg, callback_fn callback) {
	printf("begin test_callback %s\n", msg);
	printf( "result=%d\n", callback( 1, "2", 3.0));
	printf( "end\n");
}

__declspec(dllexport) int test_var_i = 100;
__declspec(dllexport) float test_var_f = 12.3;
__declspec(dllexport) const char* test_var_z = "Hello World!";
__declspec(dllexport) const char* test_var_p = "Another string!?";

__declspec(dllexport) char test_array[1024] = "Hello, this is an array of words defined in C\n"
																	"It has several strings seperated by newlines\n"
																	"And ending in a zero terminator";

__declspec(dllexport) int read_int( void* src, int offs) {
	return *(int*)(src + offs);
}
__declspec(dllexport) void write_int( void* dst, int offs, int val) {
	*(int*)(dst + offs) = val;
}

__declspec(dllexport) char* read_str( void* src, int offs, int len) {
	char* dst = malloc(len + 1);
	memcpy( dst, src + offs, len);
	((char*)dst)[len] = '\0';
	return dst;
}

__declspec(dllexport) void write_str( void* dst, int offs, void* src, int len) {
	memcpy( dst + offs, src, len);
	((char*)dst)[offs + len] = '\0';
}

__declspec(dllexport)  void* __malloc( size_t size) { return malloc(size); }
__declspec(dllexport)  void* __realloc( void* p, size_t size) { return realloc( p, size); }
__declspec(dllexport)  void __free( void* p) { free(p); }
__declspec(dllexport) char* __strdup( const char* s) { return strdup(s); }
__declspec(dllexport) int __strlen( const char* s) { return strlen(s); }
__declspec(dllexport) char* __strcpy( char* dst, const char* src) { return strcpy( dst, src); }
__declspec(dllexport) char* __strncpy( char* dst, const char* src, int len) { return strncpy( dst, src, len); }
__declspec(dllexport) char* __strcat( char* dst, const char* src) { return strcat( dst, src); }
__declspec(dllexport) int __strcmp( const char* dst, const char* src) { return strcmp( dst, src); }
__declspec(dllexport) int __strncmp( const char* dst, const char* src, int len) { return strncmp( dst, src, len); }
__declspec(dllexport) char* __strchr( const char* s, int ch) { return strchr( s, ch); }
__declspec(dllexport) char* __strrchr( const char* s, int ch) { return strrchr( s, ch); }

__declspec(dllexport) const char* strid( const char* p) { return p; }



















































>
>
>
|



|






|





|
|
|
|

|



|


|



|






|




|
|
|
|
|
|
|
|
|
|
|
|

|

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


#define TESTAPI	__declspec(dllexport)

TESTAPI void print( const char* s) {
	puts(s);
}

TESTAPI long long test( void* x) {
	printf( "0x%p\n", x);
	return 0xCAFEF00DDEADBABELL;
}

typedef intptr_t (*callback_fn)();

TESTAPI void test_callback( const char* msg, callback_fn callback) {
	printf("begin test_callback %s\n", msg);
	printf( "result=%d\n", callback( 1, "2", 3.0));
	printf( "end\n");
}

TESTAPI int test_var_i = 100;
TESTAPI float test_var_f = 12.3;
TESTAPI const char* test_var_z = "Hello World!";
TESTAPI const char* test_var_p = "Another string!?";

TESTAPI char test_array[1024] = "Hello, this is an array of words defined in C\n"
																	"It has several strings seperated by newlines\n"
																	"And ending in a zero terminator";

TESTAPI int read_int( void* src, int offs) {
	return *(int*)(src + offs);
}
TESTAPI void write_int( void* dst, int offs, int val) {
	*(int*)(dst + offs) = val;
}

TESTAPI char* read_str( void* src, int offs, int len) {
	char* dst = malloc(len + 1);
	memcpy( dst, src + offs, len);
	((char*)dst)[len] = '\0';
	return dst;
}

TESTAPI void write_str( void* dst, int offs, void* src, int len) {
	memcpy( dst + offs, src, len);
	((char*)dst)[offs + len] = '\0';
}

TESTAPI  void* __malloc( size_t size) { return malloc(size); }
TESTAPI  void* __realloc( void* p, size_t size) { return realloc( p, size); }
TESTAPI  void __free( void* p) { free(p); }
TESTAPI char* __strdup( const char* s) { return strdup(s); }
TESTAPI int __strlen( const char* s) { return strlen(s); }
TESTAPI char* __strcpy( char* dst, const char* src) { return strcpy( dst, src); }
TESTAPI char* __strncpy( char* dst, const char* src, int len) { return strncpy( dst, src, len); }
TESTAPI char* __strcat( char* dst, const char* src) { return strcat( dst, src); }
TESTAPI int __strcmp( const char* dst, const char* src) { return strcmp( dst, src); }
TESTAPI int __strncmp( const char* dst, const char* src, int len) { return strncmp( dst, src, len); }
TESTAPI char* __strchr( const char* s, int ch) { return strchr( s, ch); }
TESTAPI char* __strrchr( const char* s, int ch) { return strrchr( s, ch); }

TESTAPI const char* strid( const char* p) { return p; }

struct Point {
	int x;
	int y;
};

struct Symbol {
	int id;
	int flags;
	const char* name;
	int length;
};

struct Buffer {
	int length;
	char bytes[16];
};

TESTAPI void test_Point( struct Point point) {
	printf( "test_Point %d,%d\n", point.x, point.y);
}

TESTAPI void test_Symbol( struct Symbol symbol) {
	printf( "test_Symbol %d 0x%X \"%s\"(%d)\n", symbol.id, symbol.flags, symbol.name, symbol.length);
}

TESTAPI void test_Buffer( struct Buffer buffer) {
	printf( "test_Buffer %d \"%.16s\"\n", buffer.length, buffer.bytes);
}

TESTAPI struct Point result_Point( int x, int y) {
	struct Point point = { .x = x, .y = y };
	return point;
}

TESTAPI struct Symbol result_Symbol( int id, int flags, const char* name, int length) {
	struct Symbol symbol = { .id = id, .flags = flags, .name = name, .length = length };
	return symbol;
}

TESTAPI struct Buffer result_Buffer( int length, char* bytes) {
	struct Buffer buffer = { .length = length };
	memcpy( buffer.bytes, bytes, length);
	return buffer;
}