set a bunch of svn:executable properties
[couchdbimport.git] / CouchProjects / CouchDb / couch_port_driver.c
blob3de6779350a127f2fae1aa012c8266b9905e52ef
1 /*
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"
28 #ifndef WIN32
29 #include <strings.h> // for memcpy
30 #endif
32 #define CMD_COLLATE 0
33 #define CMD_COLLATE_INSENSITIVE 1
36 typedef struct {
37 ErlDrvPort port;
38 UCollator* collCaseInsensitive;
39 UCollator* collCaseSensitive;
40 } couch_drv_data;
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));
57 if (pData == NULL) {
58 return ERL_DRV_ERROR_GENERAL;
61 pData->port = port;
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) {
78 return -1;
81 memcpy(*ppRetBuf, pLocalResult, localLen);
82 return 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)
89 int strLen;
91 if (*pBufLen < sizeof(int)) {
92 return -1;
94 memcpy(&strLen, *ppBuf, sizeof(int));
95 *ppBuf += sizeof(int);
96 *pBufLen -= sizeof(int);
98 if (*pBufLen < strLen) {
99 return -1;
102 uiter_setUTF8(pItor, *ppBuf, strLen);
104 *ppBuf += strLen;
105 *pBufLen -= strLen;
107 return 0;
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;
116 switch(command) {
117 case CMD_COLLATE: //case collate
118 case CMD_COLLATE_INSENSITIVE: //case collate, case insensitive
120 UErrorCode status = U_ZERO_ERROR;
121 int collResult;
122 char response;
123 UCharIterator iterA;
124 UCharIterator iterB;
126 if (get_string(&pBuf, &bufLen, &iterA) == -1) {
127 return -1;
129 if (get_string(&pBuf, &bufLen, &iterB) == -1) {
130 return -1;
133 if (command == CMD_COLLATE) {
134 if (pData->collCaseSensitive == NULL) {
135 pData->collCaseSensitive = ucol_open("", &status);
136 if (U_FAILURE(status)) {
137 return -1;
140 collResult = ucol_strcollIter(pData->collCaseSensitive, &iterA, &iterB, &status);
142 else {
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)) {
147 return -1;
150 collResult = ucol_strcollIter(pData->collCaseInsensitive, &iterA, &iterB, &status);
152 if (collResult < 0) {
153 response = 0; //lt
155 else if (collResult > 0) {
156 response = 1; //gt
158 else {
159 response = 2; //eq
161 return return_control_result(&response, sizeof(response), rbuf, rlen);
164 default:
165 return -1;
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 */
178 NULL, /* Not used */
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;