1

I don't know how to pass a variable into a callback to do some stuff (print json output) inside this function.

In sample code there is no other functions i need to pass but with sqlite3 I think I have to do this in the callback, tell me if i'm doing wrong.

The callback is called in sendhosts() function in my code.

I get this error :

In function ‘sendhosts’: sample.c:85:48: error: too few arguments to function ‘callback’ rc = sqlite3_exec(db, "SELECT * FROM hosts;", callback(req), 0, &zErrMsg);

Original code is :

#include <stdio.h>
#include <sqlite3.h>

static int callback(void *NotUsed, int argc, char **argv, char **azColName){
  int i;
  for(i=0; i<argc; i++){
    printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
  }
  printf("\n");
  return 0;
}  
int main(int argc, char **argv){
  sqlite3 *db;
  char *zErrMsg = 0;
  int rc;

  if( argc!=3 ){
    fprintf(stderr, "Usage: %s DATABASE SQL-STATEMENT\n", argv[0]);
    return(1);
  }
  rc = sqlite3_open(argv[1], &db);
  if( rc ){
    fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
    sqlite3_close(db);
    return(1);
  }
  rc = sqlite3_exec(db, argv[2], callback, 0, &zErrMsg);
  if( rc!=SQLITE_OK ){
    fprintf(stderr, "SQL error: %s\n", zErrMsg);
    sqlite3_free(zErrMsg);
  }
  sqlite3_close(db);
  return 0;
}

My code is :

#include <sys/types.h> /* size_t, ssize_t */
#include <stdarg.h> /* va_list */
#include <stddef.h> /* NULL */
#include <stdint.h> /* int64_t */
#include <stdlib.h>
#include <string.h> /* memset */
#include <stdio.h>

#include <kcgi.h>
#include <kcgihtml.h>
#include <sqlite3.h>
enum    page {
    PAGE_HOSTS,
    PAGE__MAX
};
enum    key {
    KEY_INTEGER, 
    KEY_FILE,
    KEY_PAGECOUNT,
    KEY_PAGESIZE,
    KEY__MAX
};
struct  tstrct {
    struct khtmlreq  req;
    struct kreq *r;
};
typedef void (*disp)(struct kreq *);
static void sendhosts(struct kreq *);

static const disp disps[PAGE__MAX] = {
    sendhosts, /* PAGE_SENDDATA */
};
static const struct kvalid keys[KEY__MAX] = {
    { kvalid_int, "integer" }, /* KEY_INTEGER */
    { NULL, "file" }, /* KEY_FILE */
    { kvalid_uint, "count" }, /* KEY_PAGECOUNT */
    { kvalid_uint, "size" }, /* KEY_PAGESIZE */
};
static const char *const pages[PAGE__MAX] = {
    "sendhosts" /* PAGE_SENDDATA */
};
static void
resp_open(struct kreq *req, enum khttp http)
{
    enum kmime   mime;
    if (KMIME__MAX == (mime = req->mime))
        mime = KMIME_APP_OCTET_STREAM;

    khttp_head(req, kresps[KRESP_STATUS], 
        "%s", khttps[http]);
    khttp_head(req, kresps[KRESP_CONTENT_TYPE], 
        "%s", kmimetypes[mime]);
    khttp_body(req);
}
static int callback(struct kreq *req, int argc, char **argv, char **azColName){
    char        *page;
    struct khtmlreq  r;
    resp_open(req, KHTTP_200);
    khtml_open(&r, req, 0);
  int i;
  for(i=0; i<argc; i++){
    printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
    struct khtmlreq r;
    khtml_puts(&r, "OK");
  }
    khtml_close(&r);
    free(page);
}
static void
sendhosts(struct kreq *req)
{
    sqlite3 *db;
    char *zErrMsg = 0;
    int rc;
    rc = sqlite3_open("/var/www/MaSSH/databases/massh.db", &db);
    if(rc){
        sqlite3_close(db);
    }
    rc = sqlite3_exec(db, "SELECT * FROM hosts;", callback(req), 0, &zErrMsg);
    if(rc!= SQLITE_OK){
        sqlite3_free(zErrMsg);
    }
    sqlite3_close(db);
}
int
main(void)
{
    struct kreq  r;
    enum kcgi_err    er;

    /* Set up our main HTTP context. */

    er = khttp_parse(&r, keys, KEY__MAX, 
        pages, PAGE__MAX, PAGE_HOSTS);

    if (KCGI_OK != er)
        return(EXIT_FAILURE);

    /* 
     * Accept only GET, POST, and OPTIONS.
     * Restrict to text/html and a valid page.
     * If all of our parameters are valid, use a dispatch array to
     * send us to the page handlers.
     */

    if (KMETHOD_OPTIONS == r.method) {
        khttp_head(&r, kresps[KRESP_ALLOW], 
            "OPTIONS GET POST");
        resp_open(&r, KHTTP_200);
    } else if (KMETHOD_GET != r.method && 
           KMETHOD_POST != r.method) {
        resp_open(&r, KHTTP_405);
    } else if (PAGE__MAX == r.page || 
           KMIME_TEXT_HTML != r.mime) {
        resp_open(&r, KHTTP_404);
    } else
        (*disps[r.page])(&r);

    khttp_free(&r);
    return(EXIT_SUCCESS);
}

1 Answers1

0

Your callback's signature

static int callback(struct kreq *req, int argc, char **argv, char **azColName)

is wrong. It should be

static int callback(void *ptr, int argc, char **argv, char **azColName) {
    struct kreq *req = (struct kreq *)ptr;

The callback's signature should exactly match the function pointer's format, which, for sqlite3_exec, is int (*callback)(void *, int, char **, char **).

And this

rc = sqlite3_exec(db, "SELECT * FROM hosts;", callback(req), 0, &zErrMsg);

should be

rc = sqlite3_exec(db, "SELECT * FROM hosts;", callback, req, &zErrMsg);

callback(req) calls callback, which is not what you want; you're trying to pass a function pointer to a function, which is done with just the function's name.

Chris Loonam
  • 5,735
  • 6
  • 41
  • 63
  • So how can i access the sql data outside the callback ? Creating new function with my var and call it from the callback ? – echkourine25 Mar 01 '20 at 19:20
  • @echkourine25 yes, that's up to you. also, see my edit. To get `req` in the callback, you've gotta pass it as the 4th arg. – Chris Loonam Mar 01 '20 at 19:23
  • I get a segmentation fault without compiling error with your code. I changed : static int callback(struct kreq *req, int argc, char **argv, char **azColName) to static int callback(void *ptr, int argc, char **argv, char **azColName) { struct kreq *req = (struct kreq *)ptr; and rc = sqlite3_exec(db, "SELECT * FROM hosts;", callback(req), 0, &zErrMsg); to rc = sqlite3_exec(db, "SELECT * FROM hosts;", callback, req, &zErrMsg); – echkourine25 Mar 01 '20 at 19:48
  • I cannot add a new function and pass req through callback because req do not exist in callback – echkourine25 Mar 01 '20 at 19:53
  • `req` does exist in the callback if you pass it as the 4th argument to `sqlite3_exec` and cast the `ptr` to `struct kreq *`. – Chris Loonam Mar 01 '20 at 20:50
  • OK i used 4th argument this time looking if this works. – echkourine25 Mar 01 '20 at 21:12