/* * %CopyrightBegin% * * Copyright Ericsson AB 2006-2016. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * %CopyrightEnd% */ /* * Purpose: A driver using libpq to connect to Postgres * from erlang, a sample for the driver documentation */ #include <erl_driver.h> #include <algorithm> #include <vector> using namespace std; #include <iostream> #define L cerr << __LINE__ << "\r\n"; /* Driver interface declarations */ static ErlDrvData start(ErlDrvPort port, char*); static void output(ErlDrvData drv_data, char *buf, int len); static void ready_async(ErlDrvData, ErlDrvThreadData); static ErlDrvEntry next_perm_driver_entry = { NULL, /* init */ start, NULL, /* stop */ output, NULL, /* ready_input */ NULL, /* ready_output */ "next_perm", /* the name of the driver */ NULL, /* finish */ NULL, /* handle */ NULL, /* control */ NULL, /* timeout */ NULL, /* outputv */ ready_async, NULL, /* flush */ NULL, /* call */ NULL /* event */ }; /* INITIALIZATION AFTER LOADING */ /* * This is the init function called after this driver has been loaded. * It must *not* be declared static. Must return the address to * the driver entry. */ #ifdef __cplusplus extern "C" { // shouldn't this be in the DRIVER_INIT macro? #endif DRIVER_INIT(next_perm) { return &next_perm_driver_entry; } #ifdef __cplusplus } #endif /* DRIVER INTERFACE */ static ErlDrvData start(ErlDrvPort port, char *) { if (port == NULL) return ERL_DRV_ERROR_GENERAL; return (ErlDrvData)port; } struct our_async_data { bool prev; vector<int> data; our_async_data(ErlDrvPort p, int command, const char* buf, int len); }; our_async_data::our_async_data(ErlDrvPort p, int command, const char* buf, int len) : prev(command == 2), data((int*)buf, (int*)buf + len / sizeof(int)) { } static void do_perm(void* async_data); static void output(ErlDrvData drv_data, char *buf, int len) { if (*buf < 1 || *buf > 2) return; ErlDrvPort port = reinterpret_cast<ErlDrvPort>(drv_data); void* async_data = new our_async_data(port, *buf, buf+1, len); driver_async(port, NULL, do_perm, async_data, NULL); } static void do_perm(void* async_data) { our_async_data* d = reinterpret_cast<our_async_data*>(async_data); if (d->prev) prev_permutation(d->data.begin(), d->data.end()); else next_permutation(d->data.begin(), d->data.end()); } static void ready_async(ErlDrvData drv_data, ErlDrvThreadData async_data) { ErlDrvPort port = reinterpret_cast<ErlDrvPort>(drv_data); our_async_data* d = reinterpret_cast<our_async_data*>(async_data); int n = d->data.size(), result_n = n*2 + 5; ErlDrvTermData *result = new ErlDrvTermData[result_n], *rp = result; *rp++ = ERL_DRV_PORT; *rp++ = driver_mk_port(port); for (vector<int>::iterator i = d->data.begin(); i != d->data.end(); ++i) { *rp++ = ERL_DRV_INT; *rp++ = *i; } *rp++ = ERL_DRV_NIL; *rp++ = ERL_DRV_LIST; *rp++ = n+2; driver_output_term(port, result, result_n); delete[] result; delete d; }