2 Fabric formula engine server. For use with Erlang and CouchDb
3 Copyright (C) 2006 Damien Katz
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 // This file is the C port driver for Erlang. It provides a low overhead
22 // means of calling into C code, however unlike the Fabric engine, coding
23 // errors in this module can crash the entire Erlang server.
25 #include "erl_driver.h"
26 #include "unicode/ucol.h"
27 #include "unicode/ucasemap.h"
29 #include <strings.h> // for memcpy
33 #define CMD_COLLATE_INSENSITIVE 1
38 UCollator
* collCaseInsensitive
;
39 UCollator
* collCaseSensitive
;
42 static void free_drv_data(couch_drv_data
* pData
)
44 if (pData
->collCaseSensitive
) {
45 ucol_close(pData
->collCaseSensitive
);
47 if (pData
->collCaseInsensitive
) {
48 ucol_close(pData
->collCaseInsensitive
);
50 driver_free((char*)pData
);
53 static ErlDrvData
couch_drv_start(ErlDrvPort port
, char *buff
)
55 UErrorCode status
= U_ZERO_ERROR
;
56 couch_drv_data
* pData
= (couch_drv_data
*)driver_alloc(sizeof(couch_drv_data
));
58 return ERL_DRV_ERROR_GENERAL
;
62 pData
->collCaseSensitive
= NULL
;
63 pData
->collCaseInsensitive
= NULL
;
65 return (ErlDrvData
)pData
;
68 static void couch_drv_stop(ErlDrvData handle
)
70 driver_free((char*)handle
);
73 static int return_control_result(void* pLocalResult
, int localLen
, char **ppRetBuf
, int returnLen
)
75 if (*ppRetBuf
== NULL
|| localLen
> returnLen
) {
76 *ppRetBuf
= (char*)driver_alloc_binary(localLen
);
77 if(*ppRetBuf
== NULL
) {
81 memcpy(*ppRetBuf
, pLocalResult
, localLen
);
85 // this populates the pItor with the data at *ppBuf and increments
86 // the values at ppBuf and pBufLen to "consume" the buffer.
87 static int get_string(const char ** ppBuf
, int* pBufLen
, UCharIterator
* pItor
)
91 if (*pBufLen
< sizeof(int)) {
94 memcpy(&strLen
, *ppBuf
, sizeof(int));
95 *ppBuf
+= sizeof(int);
96 *pBufLen
-= sizeof(int);
98 if (*pBufLen
< strLen
) {
102 uiter_setUTF8(pItor
, *ppBuf
, strLen
);
111 static int couch_drv_control(ErlDrvData drv_data
, unsigned int command
, const char *pBuf
,
112 int bufLen
, char **rbuf
, int rlen
)
114 couch_drv_data
* pData
= (couch_drv_data
*)drv_data
;
117 case CMD_COLLATE
: //case collate
118 case CMD_COLLATE_INSENSITIVE
: //case collate, case insensitive
120 UErrorCode status
= U_ZERO_ERROR
;
126 if (get_string(&pBuf
, &bufLen
, &iterA
) == -1) {
129 if (get_string(&pBuf
, &bufLen
, &iterB
) == -1) {
133 if (command
== CMD_COLLATE
) {
134 if (pData
->collCaseSensitive
== NULL
) {
135 pData
->collCaseSensitive
= ucol_open("", &status
);
136 if (U_FAILURE(status
)) {
140 collResult
= ucol_strcollIter(pData
->collCaseSensitive
, &iterA
, &iterB
, &status
);
143 if (pData
->collCaseSensitive
== NULL
) {
144 pData
->collCaseInsensitive
= ucol_open("", &status
);
145 ucol_setAttribute(pData
->collCaseInsensitive
, UCOL_STRENGTH
, UCOL_PRIMARY
, &status
);
146 if (U_FAILURE(status
)) {
150 collResult
= ucol_strcollIter(pData
->collCaseInsensitive
, &iterA
, &iterB
, &status
);
152 if (collResult
< 0) {
155 else if (collResult
> 0) {
161 return return_control_result(&response
, sizeof(response
), rbuf
, rlen
);
169 ErlDrvEntry couch_driver_entry
= {
170 NULL
, /* F_PTR init, N/A */
171 couch_drv_start
, /* L_PTR start, called when port is opened */
172 couch_drv_stop
, /* F_PTR stop, called when port is closed */
173 NULL
, /* F_PTR output, called when erlang has sent */
174 NULL
, /* F_PTR ready_input, called when input descriptor ready */
175 NULL
, /* F_PTR ready_output, called when output descriptor ready */
176 "couch_erl_driver", /* char *driver_name, the argument to open_port */
177 NULL
, /* F_PTR finish, called when unloaded */
179 couch_drv_control
, /* F_PTR control, port_command callback */
180 NULL
, /* F_PTR timeout, reserved */
181 NULL
/* F_PTR outputv, reserved */
184 DRIVER_INIT(couch_erl_driver
) /* must match name in driver_entry */
186 return &couch_driver_entry
;