4 ==============================
6 ==============================
8 .. note:: 現在、本章の説明だけでは拡張機能の開発は困難です。
9 Ring のソースコード (include, src, visualsrc, stdlib フォルダ)、および拡張機能のソースコード (android, extensions, libdepwin フォルダ) のコードリーディングを強く推奨します。
12 プログラミング言語 C / C++ で記述した関数を新たに追加することにより Ring 仮想計算機 (Ring VM) の機能を拡張できます。 Ring VM には C により記述された様々な関数が付属しており Ring の関数として呼び出せます。
14 新しい関数を記述してから Ring VM のリビルドすることで Ring 言語の機能を拡張できます。
15 また、共有ライブラリ (.dll / .so) ファイルを作成することで Ring VM をリビルドせずに機能の拡張ができます。
17 Ring のソースコードには Ring VM へ新しいモジュールを追加するための二本のファイルが付属しています。
20 pair: 拡張機能; ring_ext.h
25 ファイル ring_ext.h にはビルド処理の間にモジュールの包含、または除外を変更できる定数があります。
32 #define RING_VM_LISTFUNCS 1
33 #define RING_VM_REFMETA 1
34 #define RING_VM_MATH 1
35 #define RING_VM_FILE 1
37 #define RING_VM_MYSQL 1
38 #define RING_VM_ODBC 1
39 #define RING_VM_OPENSSL 1
40 #define RING_VM_CURL 1
46 pair: 拡張機能; ring_ext.c
51 モジュールのスタートアップ関数を呼び出す前に、ファイル ring_ext.c は ring_ext.h で定義されている定数を確認します。
53 モジュールは Ring VM へモジュール関数を登録する関数があります。
59 void ring_vm_extension ( RingState *pRingState )
61 /* リフレクションとメタプログラミング */
63 ring_vm_refmeta_loadfunctions(pRingState);
67 ring_vm_listfuncs_loadfunctions(pRingState);
71 ring_vm_math_loadfunctions(pRingState);
75 ring_vm_file_loadfunctions(pRingState);
79 ring_vm_os_loadfunctions(pRingState);
83 ring_vm_mysql_loadfunctions(pRingState);
87 ring_vm_odbc_loadfunctions(pRingState);
91 ring_vm_openssl_loadfunctions(pRingState);
95 ring_vm_curl_loadfunctions(pRingState);
99 ring_vm_dll_loadfunctions(pRingState);
104 pair: 拡張機能; モジュールの組織化
109 モジュールごとに Ring ヘッダファイル (ring.h) をインクルードすることから始まります。
110 このファイルには Ring VM の拡張機能で用いる Ring API があります。
112 モジュールには Ring VM へモジュール関数を登録するための関数が付属しています。
113 ring_vm_funcregister() 関数で登録を完了します。
115 ring_vm_funcregister() 関数は二つの仮関数を扱います。
116 一番目の仮引数は Ring プログラムが関数を呼び出すために使用される関数名です。
117 二番目の仮引数は C プログラム側の関数ポインタです。
119 この用例では、モジュール関数の登録用コードが ring_vmmath.c モジュールにあります。
125 void ring_vm_math_loadfunctions ( RingState *pRingState )
127 ring_vm_funcregister("sin",ring_vm_math_sin);
128 ring_vm_funcregister("cos",ring_vm_math_cos);
129 ring_vm_funcregister("tan",ring_vm_math_tan);
130 ring_vm_funcregister("asin",ring_vm_math_asin);
131 ring_vm_funcregister("acos",ring_vm_math_acos);
132 ring_vm_funcregister("atan",ring_vm_math_atan);
133 ring_vm_funcregister("atan2",ring_vm_math_atan2);
134 ring_vm_funcregister("sinh",ring_vm_math_sinh);
135 ring_vm_funcregister("cosh",ring_vm_math_cosh);
136 ring_vm_funcregister("tanh",ring_vm_math_tanh);
137 ring_vm_funcregister("exp",ring_vm_math_exp);
138 ring_vm_funcregister("log",ring_vm_math_log);
139 ring_vm_funcregister("log10",ring_vm_math_log10);
140 ring_vm_funcregister("ceil",ring_vm_math_ceil);
141 ring_vm_funcregister("floor",ring_vm_math_floor);
142 ring_vm_funcregister("fabs",ring_vm_math_fabs);
143 ring_vm_funcregister("pow",ring_vm_math_pow);
144 ring_vm_funcregister("sqrt",ring_vm_math_sqrt);
145 ring_vm_funcregister("unsigned",ring_vm_math_unsigned);
146 ring_vm_funcregister("decimals",ring_vm_math_decimals);
147 ring_vm_funcregister("murmur3hash",ring_vm_math_murmur3hash);
150 .. tip:: ring_vm_math_loadfunctions() 関数は ring_vm_extension() 関数により、
151 呼び出されることを覚えておいてください (ring_ext.c ファイルで)。
159 このような手順がモジュール関数ごとにあります。
171 この構造は関数と非常に似ています (入力~処理~出力)。
172 ここでは Ring API の 1, 2, 3, および 5 の手順を使用しています。
176 pair: 拡張機能; 仮引数の個数を検査するには
179 ===========================
181 RING_API_PARACOUNT マクロで仮引数の個数を検査します。
183 RING_API_PARACOUNT は == または != 演算子により数値で比較します。
190 if ( RING_API_PARACOUNT != 1 ) {
199 if ( RING_API_PARACOUNT == 1 ) {
204 pair: 拡張機能; エラーメッセージの表示
207 =======================
209 RING_API_ERROR() 関数はエラーメッセージを表示します。
211 この関数はエラー、およびプログラム実行時に表示します。
213 .. note:: この関数の動作は Ring コードで Try/Catch/Done ステートメントにより変更できますので
214 C コードでは、この関数の後に retrun を記述してください。
221 RING_API_ERROR(const char *cErrorMsg);
224 Ring API には定義済みのエラーメッセージがあり、このように使うことができます。
228 #define RING_API_MISS1PARA "Bad parameters count, the function expect one parameter"
229 #define RING_API_MISS2PARA "Bad parameters count, the function expect two parameters"
230 #define RING_API_MISS3PARA "Bad parameters count, the function expect three parameters"
231 #define RING_API_MISS4PARA "Bad parameters count, the function expect four parameters"
232 #define RING_API_BADPARATYPE "Bad parameter type!"
233 #define RING_API_BADPARACOUNT "Bad parameters count!"
234 #define RING_API_BADPARARANGE "Bad parameters value, error in range!"
235 #define RING_API_NOTPOINTER "Error in parameter, not pointer!"
236 #define RING_API_NULLPOINTER "Error in parameter, NULL pointer!"
237 #define RING_API_EMPTYLIST "Bad parameter, empty list!"
240 pair: 拡張機能; 仮引数の型を検査するには
243 =========================
249 int RING_API_ISNUMBER(int nParameterNumber);
250 int RING_API_ISSTRING(int nParameterNumber);
251 int RING_API_ISLIST(int nParameterNumber);
252 int RING_API_ISPOINTER(int nParameterNumber);
254 これらの関数の実行結果は 1 (True) または 0 (False) です。
257 pair: 拡張機能; 仮引数の値を取得するには
260 =========================
266 double RING_API_GETNUMBER(int nParameterNumber);
267 const char *RING_API_GETSTRING(int nParameterNumber);
268 int RING_API_GETSTRINGSIZE(int nParameterNumber);
269 List *RING_API_GETLIST(int nParameterNumber);
270 void *RING_API_GETCPOINTER(int nParameterNumber, const char *cPoinerType);
271 int RING_API_GETPOINTERTYPE(int nParameterNumber);
284 RING_API_RETNUMBER(double nValue);
285 RING_API_RETSTRING(const char *cString);
286 RING_API_RETSTRING2(const char *cString,int nStringSize);
287 RING_API_RETLIST(List *pList);
288 RING_API_RETCPOINTER(void *pValue,const char *cPointerType);
289 RING_API_RETMANAGEDCPOINTER(void *pValue,const char *cPointerType,
290 void (* pFreeFunc)(void *,void *))
299 Ring VM の拡張機能用の新しい関数を定義するには、このプロトタイプを使用します。
303 void my_function_name( void *pPointer );
305 または RING_FUNC() マクロを使えます。
309 RING_FUNC(my_function_name);
313 pair: 拡張機能; Sin() 関数の実装
318 このコードは Ring API と C 関数 sin() による
324 void ring_vm_math_sin ( void *pPointer )
326 if ( RING_API_PARACOUNT != 1 ) {
327 RING_API_ERROR(RING_API_MISS1PARA);
330 if ( RING_API_ISNUMBER(1) ) {
331 RING_API_RETNUMBER(sin(RING_API_GETNUMBER(1)));
333 RING_API_ERROR(RING_API_BADPARATYPE);
339 pair: 拡張機能; Fopen() および Fclose() の実装
341 Fopen() および Fclose() の実装
342 ==============================
344 このコードは Ring API と C 関数 fopen() による
347 この関数は二つの仮引数を扱います。第一仮引数はファイル名を文字列で指定します。
350 ファイル ring_vmfile.h はポインタ型などの定数として使用するものがあります。
354 #define RING_VM_POINTER_FILE "file"
355 #define RING_VM_POINTER_FILEPOS "filepos"
357 ring_vmfile.c における関数の実装です。
361 void ring_vm_file_fopen ( void *pPointer )
364 if ( RING_API_PARACOUNT != 2 ) {
365 RING_API_ERROR(RING_API_MISS2PARA);
368 if ( RING_API_ISSTRING(1) && RING_API_ISSTRING(2) ) {
369 fp = fopen(RING_API_GETSTRING(1),RING_API_GETSTRING(2));
370 RING_API_RETCPOINTER(fp,RING_VM_POINTER_FILE);
372 RING_API_ERROR(RING_API_BADPARATYPE);
377 このコードは fclose() 関数の実装です。
381 void ring_vm_file_fclose ( void *pPointer )
384 if ( RING_API_PARACOUNT != 1 ) {
385 RING_API_ERROR(RING_API_MISS1PARA);
388 if ( RING_API_ISPOINTER(1) ) {
389 fp = (FILE *) RING_API_GETCPOINTER(1,RING_VM_POINTER_FILE) ;
391 RING_API_RETNUMBER(fclose(fp));
392 RING_API_SETNULLPOINTER(1);
395 RING_API_ERROR(RING_API_BADPARATYPE);
399 fopen() および fclose() から次の実装について学びました
401 1 - RING_API_RETCPOINTER() 関数で C ポインタを返す方法
403 2 - RING_API_ISPOINTER() 関数で仮引数がポインタの場合における検査方法
405 3 - RING_API_GETCPOINTER() 関数で C ポインタ値の取得方法
407 4 - RING_API_SETNULLPOINTER() 関数で C ポインタ変数 (Ring VM では) に NULL を設定する方法。
410 pair: 拡張機能; RING API - リスト関数
413 =====================
415 リストの新規作成とリスト項目操作用の Ring API リスト関数を学びます。
419 List * ring_list_new ( int nSize ) ;
420 void ring_list_newitem ( List *pList ) ;
421 Item * ring_list_getitem ( List *pList,int index ) ;
422 List * ring_list_delete ( List *pList ) ;
423 void ring_list_deleteitem ( List *pList,int index ) ;
424 void ring_list_print ( List *pList ) ;
425 int ring_list_gettype ( List *pList, int index ) ;
426 void ring_list_setint ( List *pList, int index ,int number ) ;
427 void ring_list_addint ( List *pList,int x ) ;
428 void ring_list_setpointer ( List *pList, int index ,void *pValue ) ;
429 void ring_list_addpointer ( List *pList,void *pValue ) ;
430 void ring_list_setfuncpointer ( List *pList, int index ,void (*pFunc)(void *) ) ;
431 void ring_list_addfuncpointer ( List *pList,void (*pFunc)(void *) ) ;
432 int ring_list_isfuncpointer ( List *pList, int index ) ;
433 void ring_list_setdouble ( List *pList, int index ,double number ) ;
434 void ring_list_adddouble ( List *pList,double x ) ;
435 void ring_list_setstring ( List *pList, int index ,const char *str ) ;
436 void ring_list_setstring2 ( List *pList, int index ,const char *str,int nStrSize ) ;
437 void ring_list_addstring ( List *pList,const char *str ) ;
438 void ring_list_addstring2 ( List *pList,const char *str,int nStrSize ) ;
439 List * ring_list_newlist ( List *pList ) ;
440 List * ring_list_getlist ( List *pList, int index ) ;
441 void ring_list_setlist ( List *pList, int index ) ;
442 void ring_list_setactiveitem ( List *pList, Items *pItems, int index ) ;
443 void ring_list_copy ( List *pNewList, List *pList ) ;
444 int ring_list_isnumber ( List *pList, int index ) ;
445 int ring_list_isstring ( List *pList, int index ) ;
446 int ring_list_islist ( List *pList, int index ) ;
447 int ring_list_ispointer ( List *pList, int index ) ;
448 void ring_list_deleteallitems ( List *pList ) ;
449 void ring_list_insertitem ( List *pList,int x ) ;
450 void ring_list_insertint ( List *pList,int nPos,int x ) ;
451 void ring_list_insertdouble ( List *pList,int nPos,double x ) ;
452 void ring_list_insertpointer ( List *pList,int nPos,void *pValue ) ;
453 void ring_list_insertstring ( List *pList,int nPos,const char *str ) ;
454 void ring_list_insertstring2 ( List *pList,int nPos,const char *str,int nStrSize ) ;
455 void ring_list_insertfuncpointer ( List *pList,int nPos,void (*pFunc)(void *) ) ;
456 List * ring_list_insertlist ( List *pList,int nPos ) ;
457 int ring_list_isiteminsidelist ( List *pList,Item *pItem ) ;
458 int ring_list_findstring ( List *pList,const char *str,int nColumn ) ;
459 int ring_list_finddouble ( List *pList,double nNum1,int nColumn ) ;
460 void ring_list_sortnum ( List *pList,int left,int right,int nColumn ) ;
461 void ring_list_sortstr ( List *pList,int left,int right,int nColumn ) ;
462 int ring_list_binarysearchnum ( List *pList,double nNum1,int nColumn ) ;
463 int ring_list_binarysearchstr ( List *pList,const char *cFind,int nColumn ) ;
464 void ring_list_swap ( List *pList,int x,int y ) ;
465 double ring_list_getdoublecolumn ( List *pList,int nIndex,int nColumn ) ;
466 char * ring_list_getstringcolumn ( List *pList,int nIndex,int nColumn ) ;
467 void ring_list_genarray ( List *pList ) ;
468 void ring_list_deletearray ( List *pList ) ;
469 void ring_list_genhashtable ( List *pList ) ;
470 void ring_list_genhashtable2 ( List *pList ) ;
471 void ring_list_refcopy ( List *pNewList, List *pList ) ;
472 void ring_list_clear ( List *pList ) ;
474 ring_list_isdouble(pList,index)
475 ring_list_isint(pList,index)
476 ring_list_deletelastitem(x)
477 ring_list_gethashtable(x)
478 ring_list_getint(pList,index)
479 ring_list_getpointer(pList,index)
480 ring_list_getfuncpointer(pList,index)
481 ring_list_callfuncpointer(pList,index,x)
482 ring_list_getdouble(pList,index)
483 ring_list_getstring(pList,index)
484 ring_list_getstringobject(pList,index)
485 ring_list_getstringsize(pList,index)
486 ring_list_getsize(x) (x->nSize)
489 pair: 拡張機能; RING API - 文字列関数
492 =====================
494 文字列の新規作成と文字列内容操作用の Ring API 文字列関数を学びます。
498 String * ring_string_new ( const char *str ) ;
499 String * ring_string_new2 ( const char *str,int nStrSize ) ;
500 String * ring_string_delete ( String *pString ) ;
501 int ring_string_size ( String *pString ) ;
502 void ring_string_set ( String *pString,const char *str ) ;
503 void ring_string_set2 ( String *pString,const char *str,int nStrSize ) ;
504 void ring_string_add ( String *pString,const char *str ) ;
505 void ring_string_add2 ( String *pString,const char *str,int nStrSize ) ;
506 void ring_string_print ( String *pString ) ;
507 void ring_string_setfromint ( String *pString,int x ) ;
508 char * ring_string_lower ( char *cStr ) ;
509 char * ring_string_upper ( char *cStr ) ;
510 char * ring_string_lower2 ( char *cStr,int nStrSize ) ;
511 char * ring_string_upper2 ( char *cStr,int nStrSize ) ;
512 char * ring_string_find ( char *cStr1,char *cStr2 ) ;
513 char * ring_string_find2 ( char *cStr1,int nStrSize1,char *cStr2,int nStrSize2 ) ;
515 ring_string_tolower(x)
516 ring_string_toupper(x)
521 pair: 拡張機能; MySQL_Columns() 関数の実装
523 MySQL_Columns() 関数の実装
524 =======================================
526 このコードは MySQL_Columns() 関数の実装です。
532 void ring_vm_mysql_columns ( void *pPointer )
539 List *pList, *pList2 ;
540 if ( RING_API_PARACOUNT != 1 ) {
541 RING_API_ERROR(RING_API_MISS1PARA);
544 if ( RING_API_ISPOINTER(1) ) {
545 con = (MYSQL *) RING_API_GETCPOINTER(1,RING_VM_POINTER_MYSQL) ;
549 result = mysql_store_result(con);
550 if ( result == NULL ) {
551 RING_API_RETNUMBER(0);
554 pList = RING_API_NEWLIST ;
555 nColumns = mysql_num_fields(result);
556 if ( row = mysql_fetch_row(result) ) {
557 while ( field = mysql_fetch_field(result) ) {
558 pList2 = ring_list_newlist(pList);
559 ring_list_addstring(pList2,field->name);
560 ring_list_adddouble(pList2,field->length);
561 ring_list_adddouble(pList2,field->type);
562 ring_list_adddouble(pList2,field->flags);
565 mysql_free_result(result);
566 RING_API_RETLIST(pList);
568 RING_API_ERROR(RING_API_BADPARATYPE);
573 List はリスト型であり、以前の関数でリスト型のポインタ
574 \*pList, \*pList2; の二つ使用して宣言されています。
577 .. note:: この関数は RING_API_NEWLIST で新しいリストを作成するために使用しますが
578 ring_list_new() の代わりに一時作業用のリストを作成します。関数のスコープはメモリと関連付けられています。
579 このように関数からリストを返せます。また Ring コードにより保存された格納済みの変数ならば、
580 リストの削除を行いません。それ以外ならば Ring VM により自動削除されます。
583 リストは部分リストを有することができ、部分リストは ring_list_newlist() 関数で作成します。
585 ring_list_addstring() 関数は部分リストへ文字列の項目を追加します。
587 ring_list_adddouble() 関数は部分リストへ数値の項目を追加します。
589 .. note:: Ring VM 拡張機能の関数から返されたリストにある数値の項目は倍精度実数型 (double) であるため
590 ring_list_adddouble() 関数でリストへ追加してください。
593 RING_API_RETLIST() 関数は拡張機能の関数からリストを返します。
598 動的 / 共有ライブラリ (DLL/So/Dylib) および LoadLib() 関数
599 ==============================================================
601 新しい関数を C/C++ と Ring API で記述後に Ring VM のリビルドをするのではなく、 DLL /So / Dylib
602 ファイルの作成を行い、このファイルを実行時に LoadLib() 関数へ指定することで動的に関数を使えます。
611 RING_FUNC(ring_ringlib_dlfunc)
613 printf("Message from dlfunc");
616 RING_API void ringlib_init(RingState *pRingState)
618 ring_vm_funcregister("dlfunc",ring_ringlib_dlfunc);
621 考えかたとしては ringlib_init() 関数を作成することであり、この関数は生成された DLL ファイルを
622 LoadLib() 関数で読み込んで使用する時に Ring VM から呼び出されます。
624 ringlib_init() 関数内でモジュール関数の登録、またはモジュール関数を全て登録処理するための関数を呼び出せます。
626 この Ring コードは実行時に DLL ライブラリの用法です。
630 See "Dynamic DLL" + NL
631 LoadLib("ringlib.dll")
642 pair: 拡張機能; Using RING_API_RETMANAGEDCPOINTER() の用法
645 RING_API_RETMANAGEDCPOINTER() の用法
646 ====================================
648 RING_API_RETMANAGEDCPOINTER() は C/C++ 言語で記述された Ring 拡張機能でマネージドポインタを Ring へ返します。このポインタは参照カウンタを使用している Ring VM により制御可能です。
650 これは RingQt の QPixMap オブジェクトなどのアンマネージドのリソース解放用コードを書く必要性を回避するには重要です。
652 また、コード生成器は必要に応じて拡張機能を RING_API_RETMANAGEDCPOINTER() に対応したものへ自動更新します。
658 RING_API_RETMANAGEDCPOINTER(void *pValue,const char *cPointerType,
659 void (* pFreeFunc)(void *,void *))
663 この用例は ring_qt.cpp の QPixMap クラスにある Scaled() メソッドからの引用です。
667 RING_FUNC(ring_QPixmap_scaled)
670 if ( RING_API_PARACOUNT != 5 ) {
671 RING_API_ERROR(RING_API_BADPARACOUNT);
674 RING_API_IGNORECPOINTERTYPE ;
675 if ( ! RING_API_ISPOINTER(1) ) {
676 RING_API_ERROR(RING_API_BADPARATYPE);
679 pObject = (QPixmap *) RING_API_GETCPOINTER(1,"QPixmap");
680 if ( ! RING_API_ISNUMBER(2) ) {
681 RING_API_ERROR(RING_API_BADPARATYPE);
684 if ( ! RING_API_ISNUMBER(3) ) {
685 RING_API_ERROR(RING_API_BADPARATYPE);
688 if ( ! RING_API_ISNUMBER(4) ) {
689 RING_API_ERROR(RING_API_BADPARATYPE);
692 if ( ! RING_API_ISNUMBER(5) ) {
693 RING_API_ERROR(RING_API_BADPARATYPE);
698 pValue = new QPixmap() ;
699 *pValue = pObject->scaled( (int ) RING_API_GETNUMBER(2),
700 (int ) RING_API_GETNUMBER(3),
701 (Qt::AspectRatioMode ) (int) RING_API_GETNUMBER(4),
702 (Qt::TransformationMode ) (int) RING_API_GETNUMBER(5));
703 RING_API_RETMANAGEDCPOINTER(pValue,"QPixmap",ring_QPixmap_freefunc);
707 この関数は二種類の仮引数 (Ring のステートと確保されたメモリのポインタ) の指定によりメモリを解放します。
713 void ring_QPixmap_freefunc(void *pState,void *pPointer)
716 pObject = (QPixmap *) pPointer;