2 * This is an example for using GCI. Enjoy, copy and paste!
3 * We have three different execution paths for Unix, Win32 and OS/2.
4 * For some interpreters, most notable the builtin interpreter of OS/2, you
5 * have to rename this file to gci-try.cmd
8 say "Your REXX interpreter is" version
10 /******************************************************************************
11 * Try to detect the system to show several things.
13 parse var version "REXX-"ipret
"_".
15 if ipret
= "Regina" then do
18 options NOEXT_COMMANDS_AS_FUNCS
21 parse source system
. source
23 system
= translate(system
)
24 if left(system
, 3) = "WIN" then do
29 else if system
= "OS/2" then do
37 "test `uname -s` = 'SunOS'"
43 if IsRegina
& Left(uname
, 6) = 'CYGWIN' then do
45 MathLib
= "cygwin1.dll"
56 * Check for a builtin RxFuncDefine. Call it with errorneous arguments and
57 * expect a simple error if installed and a syntax signal if unknown.
60 signal on syntax name NotInstalled
63 h
= RxFuncDefine
(x
,x
,x
,x
)
64 if h \
= 0 & h \
= 10005 & DataType(h
, "NUM") then
70 if \InternalGCI
then do
72 * The DLL may have been loaded already. Prevent bugs at this stage.
74 call RxFuncDrop RxFuncDefine
75 call RxFuncDrop GciPrefixChar
76 call RxFuncDrop GciFuncDrop
77 if RxFuncadd(RxFuncDefine
, "gci", "RxFuncDefine") \
= 0 then do
78 msg = "Can't load RxFuncDefine of" library
80 msg = msg || ":" RxFuncErrMsg
()
84 if RxFuncadd(GciFuncDrop
, "gci", "GciFuncDrop") \
= 0 then do
85 msg = "Can't load GciFuncDrop of" library
87 msg = msg || ":" RxFuncErrMsg
()
91 call RxFuncadd GciPrefixChar
, "gci", "GciPrefixChar"
92 say "Your interpreter has no internal support of GCI"
95 say "Your interpreter has internal support of GCI"
99 /******************************************************************************
100 * After the prelimnaries try to use the GCI.
102 if system
= "OS/2" then signal useOS2
104 say "Trying to copy string 'hello' to a string 'world' using the C library"
105 stem
.calltype
= cdecl
107 stem
.1.name = "Target"
108 stem
.1.type
= indirect string80
109 stem
.2.name = "Source"
110 stem
.2.type
= indirect string80
111 stem
.return.type
= "" /* We are not interested in the return value */
113 call funcDefine strcpy
, CLib
, "strcpy", stem
115 stem
.1.name = "Target"
116 stem
.1.value = "world"
117 stem
.2.name = "Source"
118 stem
.2.value = "hello"
120 say stem
.1.name"="stem
.1.value stem
.2.name"="stem
.2.value
124 /******************************************************************************
125 * Check if v1.1 GciPrefixChar works.
129 signal on syntax name v1
.0
130 say "Trying to detect and use v1.1 features (same result as above expected)"
131 oldChar
= GciPrefixChar
('!')
133 stem
.!calltype
= cdecl
135 stem
.1.!name = "Target"
136 stem
.1.!type
= indirect string80
137 stem
.2.!name = "Source"
138 stem
.2.!type
= indirect string80
139 stem
.!return.!type
= ""
141 call funcDefine strcpy
, CLib
, "strcpy", stem
143 stem
.1.!name = "Target"
144 stem
.1.!value = "world"
145 stem
.2.!name = "Source"
146 stem
.2.!value = "hello"
148 say stem
.1.!name"="stem
.1.!value stem
.2.name"="stem
.2.!value
152 call GciPrefixChar oldChar
156 /******************************************************************************
157 * Use the "as function" feature
159 say "Trying to find the last occurcance of '.' in 'James F. Cooper' using the C"
160 say "library using the 'as function' feature"
161 stem
.calltype
= cdecl as function
163 stem
.1.name = "String"
164 stem
.1.type
= indirect string80
165 stem
.2.name = "Character"
167 stem
.return.type
= indirect string80
169 call funcDefine strrchr
, CLib
, "strrchr", stem
171 stem
.1.name = "Target"
172 stem
.1.value = "James F. Cooper"
173 stem
.2.name = "Character"
175 say "The last dot starts at '" || strrchr
( stem
) || "'"
177 say "Trying to find the last occurcance of '.' in 'James Cooper' using the C lib"
178 say "We expect a NULL pointer which leads to a dropped value which becomes ''"
179 say "for a return value."
181 stem
.1.name = "Target"
182 stem
.1.value = "James Cooper"
183 say "The last dot starts at '" || strrchr
( stem
) || "'"
185 call funcDrop strrchr
187 /******************************************************************************
188 * Use the "with parameters as function" feature.
189 * Note that you must omit "as function" if the return value doesn't exist.
190 * We use separate functions for Windows and unix.
192 if system
= "WIN" then signal useWindows
194 say "Trying to use the math library to compute sqrt"
195 stem
.calltype
= cdecl
with parameters as function
198 stem
.1.type
= float64
199 stem
.return.type
= float64
200 call RxFuncDefine sqrt
, MathLib
, "sqrt", stem
201 if RESULT \
= 0 then do
202 if IsRegina
& InternalGCI
then
203 say "Error, code" RESULT || ":" RxFuncErrMsg
()
205 say "Error, code" RESULT || ":" GCI_RC
215 say 'Length:' i
'Height:' sqrt
( num
)
219 /*******************************/
220 say "Using a structure and checking the file system's size."
221 say "You may look into the source."
223 * This examples has removed all unnecessary stuff.
225 stem
.calltype
= cdecl as function
227 stem
.1.type
= indirect string256
228 stem
.2.type
= indirect container
229 stem
.2.0 = 10 /* statvfs64 */
230 stem
.2.1.type
= unsigned
/* bsize */
231 stem
.2.2.type
= unsigned
/* frsize */
232 stem
.2.3.type
= unsigned64
/* blocks */
233 stem
.2.4.type
= unsigned64
/* bfree */
234 stem
.2.5.type
= unsigned64
/* bavail */
235 stem
.2.6.type
= unsigned64
/* files */
236 stem
.2.7.type
= unsigned64
/* ffree */
237 stem
.2.8.type
= unsigned64
/* favail */
238 stem
.2.9.type
= unsigned
/* fsid */
239 stem
.2.10.type
= string256
/* indifferent between unices */
240 stem
.return.type
= integer
242 call funcDefine statvfs
, CLib
, "statvfs64", stem
245 args
.1.value = source
246 args
.2.value = 10 /* otherwise the argument becomes NULL */
247 if statvfs
( args
) \
= -1 then do
248 say "statvfs-info of" source
249 say "block size =" args
.2.1.value "byte"
250 size = trunc(args
.2.3.value * args
.2.1.value / (1024 * 1024))
251 avail
= trunc(args
.2.5.value * args
.2.1.value / (1024 * 1024))
252 say "file system size =" size"MB, available =" avail
"MB"
253 say "file nodes =" args
.2.6.value "available =" args
.2.8.value
254 say "sid =" args
.2.9.value
257 say "Sorry, '"source"' not found."
259 call funcDrop statvfs
261 /*******************************/
263 say "We use qsort of the C library for sorting some strings using arrays."
265 * This examples has removed all unnecessary stuff.
266 * We need a sorting routine. Without callbacks we have to use one of a
267 * library. "strcmp" is a good example. We have to play with the dynamic
270 * Load the loader functions (dlopen, dlsym, dlclose)
271 * Load the compare routine (strcmp) using the loader functions
272 * Load the sorting routine (qsort) and do the sort
273 * Additional sort operations may have to redefine qsort only.
275 stem
.calltype
= cdecl
with parameters as function
277 stem
.1.type
= indirect string256
278 stem
.2.type
= integer
279 stem
.return.type
= integer
/* handle, but who cares? */
280 call funcDefine dlopen
, "dl", "dlopen", stem
282 stem
.calltype
= cdecl
with parameters as function
284 stem
.1.type
= integer
/* handle */
285 stem
.2.type
= indirect string256
286 stem
.return.type
= integer
/* entry point address, but who cares? */
287 call funcDefine dlsym
, "dl", "dlsym", stem
289 stem
.calltype
= cdecl
with parameters as function
291 stem
.1.type
= integer
/* handle */
292 stem
.return.type
= integer
293 call funcDefine dlclose
, "dl", "dlclose", stem
295 CLibHandle
= dlopen
( CLib
, 1 /* RTLD_LAZY */ )
296 if CLibHandle
= 0 then do
297 say "dlopen() can't load" CLib
301 strcmp
= dlsym
( CLibHandle
, "strcmp" )
302 if strcmp
= 0 then do
303 say "dlsym() can't relocate strcmp()"
307 stem
.calltype
= cdecl
309 stem
.1.type
= indirect
array
311 stem
.1.1.type
= string95
312 stem
.2.type
= integer
313 stem
.3.type
= integer
314 stem
.4.type
= integer
315 stem
.return.type
= ""
316 call funcDefine qsort10
, CLib
, "qsort", stem
320 args
.1.1.value = "Ann"
321 args
.1.2.value = "Charles"
322 args
.1.3.value = "Betty"
325 args
.4.value = strcmp
326 say "Sorting (" args
.1.1.value args
.1.2.value args
.1.3.value ") ..."
328 say "Sorted values are (" args
.1.1.value args
.1.2.value args
.1.3.value ")"
330 call dlclose CLibHandle
332 call funcDrop dlclose
340 /***************************************************/
342 stem
.calltype
= stdcall
with parameters as function
345 stem
.1.type
= unsigned
347 stem
.2.type
= indirect string1024
348 stem
.3.name = "Caption"
349 stem
.3.type
= indirect string1024
351 stem
.4.type
= unsigned
352 stem
.return.type
= integer
354 call funcDefine messagebox
, "user32", "MessageBoxA", stem
356 MB_YESNO_INFO
= x2d(44)
357 if messagebox
( 0, "Do you love this rocking GCI?", "GCI", MB_YESNO_INFO
) = 6 then
358 say "Yes, you're right, GCI is cool."
360 say "No, you're kidding! GCI is cool."
362 call funcDrop messagebox
364 /*******************************/
365 say "We operate on containers and check this file's date."
366 say "You may look into the source."
368 * This examples has removed all unnecessary stuff.
370 stem
.calltype
= stdcall as function
372 stem
.1.type
= indirect string256
373 stem
.2.type
= indirect container
374 stem
.2.0 = 8 /* WIN32_FIND_DATA */
375 stem
.2.1.type
= unsigned
/* FileAttributes */
376 stem
.2.2.type
= unsigned64
/* Creation */
377 stem
.2.3.type
= unsigned64
/* Access */
378 stem
.2.4.type
= unsigned64
/* Write */
379 stem
.2.5.type
= unsigned64
/* Size */
380 stem
.2.6.type
= unsigned64
/* Reserved */
381 stem
.2.7.type
= string259
/* FileName */
382 stem
.2.8.type
= string13
/* AlternateFileName */
383 stem
.return.type
= integer
385 stem2
.calltype
= stdcall
with parameters
387 stem2
.1
.type
= integer
388 stem2
.return.type
= ""
390 call funcDefine findfirstfile
, "kernel32", "FindFirstFileA", stem
392 call funcDefine findclose
, "kernel32", "FindClose", stem2
395 args
.1.value = source
396 args
.2.value = 8 /* otherwise the argument becomes NULL */
397 handle = findfirstfile
( args
)
398 if handle \
= -1 then do
399 say "argument's name="source
400 say "filename="args
.2.7.value
401 say "8.3-name="args
.2.8.value
403 filetime
= args
.2.4.value
404 d
= /*second*/ 1000*1000*10 * /*seconds per day*/ 60*60*24
405 daypart
= trunc(filetime
/ d
)
406 date = date( 'N', daypart
+ date('B', 16010101, 'S'), 'B')
407 ns
= filetime
- daypart
* d
408 secs
= ns
% (10*1000*1000)
409 fract
= ns
// (10*1000*1000)
410 time = time('N', secs
, 'S') || "." || right(fract
, 7, '0')
411 say "ns from 1.1.1601="filetime
"= GMT," date || "," time
413 call findclose
handle
416 say "Sorry, '"source"' not found."
418 call funcDrop findfirstfile
419 call funcDrop findclose
425 /***************************************************/
426 accessStructTm: procedure expose IsRegina InternalGCI CLib
version
427 if version < 1.1 then
429 say "Finally, we use the LIKE keyword and check the number of the week."
430 say "You may look into the source, we use a PROCEDURE and v1.1 specific code."
432 * This examples has removed all unnecessary stuff.
435 tm
.1.type
= integer
/* tm_sec */
436 tm
.2.type
= integer
/* tm_min */
437 tm
.3.type
= integer
/* tm_hour */
438 tm
.4.type
= integer
/* tm_mday */
439 tm
.5.type
= integer
/* tm_mon */
440 tm
.6.type
= integer
/* tm_year */
441 tm
.7.type
= integer
/* tm_wday */
442 tm
.8.type
= integer
/* tm_yday */
443 tm
.9.type
= integer
/* tm_isdst */
444 tm
.10.type
= string
32 /* reserved stuff sometimes used by the OS */
447 time_t
.1.type
= integer64
/* SURPRISE! some systems may use 64 bit data types
448 * already. We don't have problems with this,
449 * because we use double buffering.
452 stem
.calltype
= cdecl
454 stem
.1.type
= indirect container like time_t
455 stem
.return.type
= ""
456 call funcDefine _time
, CLib
, "time", stem
458 stem
.calltype
= cdecl
460 stem
.1.type
= indirect container like time_t
461 stem
.return.type
= indirect container like tm
462 call funcDefine localtime
, CLib
, "localtime", stem
464 stem
.calltype
= cdecl
466 stem
.1.type
= indirect string256
/* dest */
467 stem
.2.type
= unsigned
/* size(dest) */
468 stem
.3.type
= indirect string256
/* template */
469 stem
.4.type
= indirect container like tm
470 stem
.return.type
= unsigned
471 call funcDefine strftime
, CLib
, "strftime", stem
474 time_val
.1.1.value = 1
478 lct
.1.1.value = time_val
.1.1.value
484 strf
.4.value = lct
.return.value
486 strf
.4.i
.value = lct
.return.i
.value
489 dayname
= strf
.1.value
493 monthname
= strf
.1.value
497 week
!Sun
= strf
.1.value
501 week
!Mon
= strf
.1.value
503 if week
!Mon
= week
!Sun
then
506 add
= " if you count Monday as the first day of the week. Otherwise it " ||,
507 "is the" week
!Sun
|| ". week."
508 say "Today is a" dayname
"in" monthname
|| ". We have the" week
!Mon
|| ". week" || add
510 call funcDrop strftime
511 call funcDrop localtime
516 /***************************************************/
518 say "Checking the high precision system timer."
519 stem
.calltype
= stdcall
521 stem
.1.name = "Frequency"
522 stem
.1.type
= indirect unsigned
523 stem
.return.type
= "unsigned"
525 call funcDefine DosTmrQueryFreq
, "doscalls", "#362", stem
527 stem
.1.name = "Frequency"
528 stem
.1.value = 0 /* don't raise NOVALUE */
530 call DosTmrQueryFreq stem
531 if stem
.return.value \
= 0 then
532 say "Error" stem
.return.value "while using DosTmrQueryFreq."
534 say "The timer has a frequency of" stem
.1.value "Hz"
536 call funcDrop DosTmrQueryFreq
538 /*******************************/
539 say "You should hear your beeper."
541 * Use the "with parameters" feature.
543 stem
.calltype
= stdcall
with parameters
545 stem
.1.name = "Frequency"
546 stem
.1.type
= unsigned
547 stem
.2.name = "Duration"
548 stem
.2.type
= unsigned
549 stem
.return.type
= "" /* We are not interested in the return value */
551 call funcDefine DosBeep
, "doscalls", "#286", stem
553 do i
= 500 to 3000 by 100
557 call funcDrop DosBeep
559 /*******************************/
560 say "Checking the installed codepages."
562 * Use the "as function" feature.
564 stem
.calltype
= stdcall as function
567 stem
.1.type
= unsigned
569 stem
.2.type
= indirect
array
571 stem
.2.1.type
= unsigned
573 stem
.3.type
= indirect unsigned
574 stem
.return.type
= "unsigned"
576 call funcDefine DosQueryCp
, "doscalls", "#291", stem
579 stem
. = 0 /* NOVALUE should not happen */
586 if DosQueryCp
( stem
) = 0 then do
587 say "current codepage:" stem
.2.1.value
588 do i
= 2 to stem
.3.value / 4
589 say "prepared codepage:" stem
.2.i
.value
593 say "Error calling DosQueryCp."
595 call funcDrop DosQueryCp
597 /*******************************/
598 say "Examining the file system on" left( source, 2 )
600 * Use the "as function" feature.
602 stem
.calltype
= stdcall as function
604 stem
.1.name = "disknum"
605 stem
.1.type
= unsigned
606 stem
.2.name = "infolevel"
607 stem
.2.type
= unsigned
609 stem
.3.type
= indirect container
611 stem
.3.1.name = "idFileSystem"
612 stem
.3.1.type
= unsigned
613 stem
.3.2.name = "cSectorUnit"
614 stem
.3.2.type
= unsigned
615 stem
.3.3.name = "cUnit"
616 stem
.3.3.type
= unsigned
617 stem
.3.4.name = "cUnitAvail"
618 stem
.3.4.type
= unsigned
619 stem
.3.5.name = "cbSector"
620 stem
.3.5.type
= unsigned16
621 stem
.4.name = "cbBuf"
622 stem
.4.type
= unsigned
623 stem
.return.type
= "unsigned"
625 call funcDefine DosQueryFSInfo
, "doscalls", "#278", stem
628 stem
. = 0 /* NOVALUE should not happen */
630 stem
.1.name = "disknum"
631 stem
.1.value = c2d( translate( left( source, 1 ) ) ) - c2d( 'A' ) + 1
632 stem
.2.name = "infolevel"
636 stem
.4.name = "cbBuf"
638 if DosQueryFSInfo
( stem
) = 0 then do
639 cluster
= stem
.3.2.value * stem
.3.5.value
640 say "Total size:" showFileSize
( cluster
*stem
.3.3.value )
641 say "Free size:" showFileSize
( cluster
*stem
.3.4.value )
644 say "Error calling DosQueryFSInfo."
646 call funcDrop DosQueryFSInfo
651 showFileSize: procedure
654 suffixes
= "KB MB GB TB"
655 do i
= 1 to words( suffixes
)
658 suffix
= word( suffixes
, i
)
662 size = format( size, , 0 )
663 else if size >= 10 then
664 size = format( size, , 1 )
666 size = format( size, , 2 )
669 /*****************************************************************************/
672 * Not all interpreters are ANSI compatible.
677 if datatype( SIGL_FUNCDEFINE
, "W" ) then
678 SIGL = SIGL_FUNCDEFINE
679 say "Error" code
"in line" SIGL || ":" condition('D')
680 say "GCI_RC=" || GCI_RC
683 /*****************************************************************************/
686 * Drops one defined function depending on whether is is defined in the
687 * lightweight library or in the interpreter's kernel.
690 call RxFuncDrop arg(1)
692 call GciFuncDrop
arg(1)
695 /*****************************************************************************/
698 * Defines a new subroutine as RxFuncDefine does, additionally it undefines
699 * (drops) the subroutine in front and it shows the error messages.
700 * Finally it terminates the process is an error occurs.
702 _SIGL_FUNCDEFINE
= SIGL
705 SIGL_FUNCDEFINE
= _SIGL_FUNCDEFINE
706 call RxFuncDefine
arg(1), arg(2), arg(3), arg(4)
707 drop SIGL_FUNCDEFINE _SIGL_FUNCDEFINE
710 if IsRegina
& InternalGCI
then
711 errAdd
= ":" RxFuncErrMsg
()
713 if GCI_RC \
= "GCI_RC" then
718 say "Error defining '" || arg(1) || "', code" RESULT || errAdd