utf-8fltkcharsetmysql++mysqlpp

mysql and FLTK - strange symbols in Fl_Table


I'm using FLTK and mysql++. I need to insert data from mysql DB to FLTK control Fl_Table. And I know how to do that. But, for example, when my data inserted, I see strange symbols in the FL_Table cells. This is my class, based on class Fl_Table:

struct TData {
  char *s;
  struct TData *next;
};

static void mm(char *dst, char *src) 
{
  for(int i = 0; i < MAX_STRLEN; i++) {
    if( !(src[i]) ) {
      dst[i] = '\0';
      break;
    }

    dst[i] = src[i];
  }
}

// Derive a class from Fl_Table
class MyTable : public Fl_Table {
  // Draw the row/col headings
  //    Make this a dark thin upbox with the text inside.
  //
  void DrawHeader(const char *s, int X, int Y, int W, int H) {
    fl_push_clip(X,Y,W,H);
      fl_draw_box(FL_THIN_UP_BOX, X,Y,W,H, row_header_color());
      fl_color(FL_BLACK);
      fl_draw(s, X,Y,W,H, FL_ALIGN_CENTER);
    fl_pop_clip();
  } 
  // Draw the cell data
  //    Dark gray text on white background with subtle border
  //
  void DrawData(const char *s, int X, int Y, int W, int H) {
    fl_push_clip(X,Y,W,H);
      // Draw cell bg
      fl_color(FL_WHITE); fl_rectf(X,Y,W,H);
      // Draw cell data
      fl_color(FL_GRAY0); fl_draw(s, X,Y,W,H, FL_ALIGN_CENTER);
      // Draw box border
      fl_color(color()); fl_rect(X,Y,W,H);
    fl_pop_clip();
  } 
  // Handle drawing table's cells
  //     Fl_Table calls this function to draw each visible cell in the table.
  //     It's up to us to use FLTK's drawing functions to draw the cells the way we want.
  //
  void draw_cell(TableContext context, int ROW=0, int COL=0, int X=0, int Y=0, int W=0, int H=0) {
    char *s = (char*)calloc(MAX_STRLEN, sizeof(char));
    struct TData *first = data;
    int i = 0;
    switch ( context ) {
      case CONTEXT_STARTPAGE:                   // before page is drawn..
        fl_font(FL_HELVETICA, 16);              // set the font for our drawing operations
        return; 
      case CONTEXT_COL_HEADER:                  // Draw column headers
        sprintf(s, "%c",'A'+COL);                // "A", "B", "C", etc.
        /*fl_utf8toa(s, MAX_STRLEN, char *dst, MAX_STRLEN)*/
        DrawHeader( s,X,Y,W,H);
        return; 
      case CONTEXT_ROW_HEADER:                  // Draw row headers
        sprintf(s, "%03d:",ROW);                 // "001:", "002:", etc
        DrawHeader(s,X,Y,W,H);
        return; 
      case CONTEXT_CELL:                        // Draw data in cells
        while(i < ROW) {
          data = data->next;
          i++;
        }
        mm(s, data->s);
        data = first;
        DrawData(s,X,Y,W,H);
        return;
      default:
        return;
    }
  }
public:

  struct TData *data = (struct TData*)calloc(1, sizeof(struct TData));
  // Constructor
  //     Make our data array, and initialize the table options.
  //
  MyTable(int X, int Y, int W, int H, const char *L=0) : Fl_Table(X,Y,W,H,L) {
    struct TData *first = data;
    struct TData *last = NULL;
    // Fill data array
    for ( int r=0; r<MAX_ROWS; r++ )
      for ( int c=0; c<MAX_COLS; c++ ) {
        if(!data) {
          data = (struct TData*)calloc(1, sizeof(struct TData));
          last->next = data;
        }
        data->s = (char*)calloc(1, sizeof(char));
        data->s = "АВЫыавп"; /*cyrillic symbols are ok in Fl_Table*/
        data->next = NULL;
        last = data;
        data = data->next;
      }
      data = first;
      
    // Rows
    rows(MAX_ROWS);             // how many rows
    row_header(1);              // enable row headers (along left)
    row_height_all(20);         // default height of rows
    row_resize(0);              // disable row resizing
    // Cols
    cols(MAX_COLS);             // how many columns
    col_header(1);              // enable column headers (along top)
    col_width_all(80);          // default width of columns
    col_resize(1);              // enable column resizing
    end();      // end the Fl_Table group
  }
  ~MyTable() { 
    struct TData *last = data;
    while(data) {
      if(data->s) {
        free(data->s);
      }
      last = data;
      data = data->next;
      free(last);
    }
  }
};

And this is mysql query for data:

mysqlpp::Connection conn(false);
if(!conn.connect(conn_settings[1], 
                   conn_settings[0], 
                   args->input_login->value(), 
                   args->input_pass->value(), 
                   3306))
{
    show_msg("Error", "Can't connect to mysql server" );
    return;
}
mysqlpp::Query q = conn.query("select MKBCode from mkb limit 10;");
mysqlpp::StoreQueryResult res = q.store();
    
if (res) {
      first = args->table->data;
      for (size_t i = 0; i < res.num_rows(); ++i) {
        args->table->data->s = ((char*)((res[i]["MKBCode"]).c_str()));
        printf(args->table->data->s); /*here I see data is ok in terminal*/
        printf("\n");
        args->table->data = args->table->data->next;
      }
      args->table->data = first;
      args->table->redraw();
}

And I see in Fl_Table this (but in terminal it's ok):


Solution

  • Thanks to mo_al_ who provided the answer in a comment on the question itself:

    StoreQueryResult res is most likely an RAII type and the std::string on which you call c_str() is also destroyed at the end of res scope. You might need to call strdup. args->table->data->s = strdup(res[i]["MKBCode"]).c_str());. Then handle cleaning in your mm function.

    I didn't know that the result of the c_str() function should be copied immediately before the data gets lost.