static int iMatrixExUndoDataSwap(ImatExData* matex_data, IundoData* undo_data)
{
  char* id = iupTableFirst(undo_data->data_table);
  while (id)
  {
    char *value, *old_value;
    int lin=1, col=1;
    iupStrToIntInt(id, &lin, &col, ':');

    value = (char*)iupTableGetCurr(undo_data->data_table);

    old_value = iupStrDup(iupMatrixExGetCellValue(matex_data->ih, lin, col, 0));  /* get internal value */

    iupMatrixExSetCellValue(matex_data->ih, lin, col, value);

    if (!old_value)
      iupTableSetCurr(undo_data->data_table, (void*)"", IUPTABLE_POINTER);
    else
    {
      iupTableSetCurr(undo_data->data_table, (void*)old_value, IUPTABLE_STRING);
      free(old_value);
    }

    if (!iupMatrixExBusyInc(matex_data))
      return 0;

    id = iupTableNext(undo_data->data_table);
  }

  return 1;
}
static void iMatrixExPasteSetData(Ihandle *ih, const char* data, int data_num_lin, int data_num_col, char sep, int start_lin, int start_col, int num_lin, int num_col, const char* busyname)
{
  ImatExData* matex_data = (ImatExData*)iupAttribGet(ih, "_IUP_MATEX_DATA");
  int lin, col, len, l, c;
  char* value = NULL;
  int value_max_size = 0, value_len;

  iupMatrixExBusyStart(matex_data, data_num_lin*data_num_col, busyname);

  lin = start_lin;
  l = 0;
  while (lin <= num_lin && l<data_num_lin)
  {
    if (iupMatrixExIsLineVisible(ih, lin))
    {
      const char* next_line = iupStrNextLine(data, &len); l++;

      col = start_col;
      c = 0;
      while (col <= num_col && c<data_num_col)
      {
        if (iupMatrixExIsColumnVisible(ih, col))
        {
          const char* next_value = iupStrNextValue(data, len, &value_len, sep);  c++;

          value = iMatrixExStrCopyValue(value, &value_max_size, data, value_len);
          iupMatrixExSetCellValue(matex_data->ih, lin, col, value);

          data = next_value;
          len -= value_len+1;

          if (!iupMatrixExBusyInc(matex_data))
          {
            if (value) 
              free(value);
            return;
          }
        }

        col++;
      }

      data = next_line;
    }

    lin++;
  }

  iupMatrixExBusyEnd(matex_data);

  if (value)
    free(value);

  iupBaseCallValueChangedCb(matex_data->ih);
}