예제 #1
0
wtap_open_return_val stanag4607_open(wtap *wth, int *err, gchar **err_info)
{
  guint16 version_id;
  stanag4607_t *stanag4607;

  if (!wtap_read_bytes(wth->fh, &version_id, sizeof version_id, err, err_info))
    return (*err != WTAP_ERR_SHORT_READ) ? WTAP_OPEN_ERROR : WTAP_OPEN_NOT_MINE;

  if (!is_valid_id(GUINT16_TO_BE(version_id)))
     /* Not a stanag4607 file */
     return WTAP_OPEN_NOT_MINE;

  /* seek back to the start of the file  */
  if (file_seek(wth->fh, 0, SEEK_SET, err) == -1)
    return WTAP_OPEN_ERROR;

  wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_STANAG_4607;
  wth->file_encap = WTAP_ENCAP_STANAG_4607;
  wth->snapshot_length = 0; /* not known */

  stanag4607 = (stanag4607_t *)g_malloc(sizeof(stanag4607_t));
  wth->priv = (void *)stanag4607;
  stanag4607->base_secs = 0; /* unknown as of yet */

  wth->subtype_read = stanag4607_read;
  wth->subtype_seek_read = stanag4607_seek_read;
  wth->file_tsprec = WTAP_TSPREC_MSEC;

  return WTAP_OPEN_MINE;
}
예제 #2
0
int stanag4607_open(wtap *wth, int *err, gchar **err_info)
{
    int bytes_read;
    guint16 version_id;
    stanag4607_t *stanag4607;

    bytes_read = file_read(&version_id, sizeof version_id, wth->fh);
    if (bytes_read != sizeof version_id) {
        *err = file_error(wth->fh, err_info);
        return (*err != 0) ? -1 : 0;
    }

    if (!is_valid_id(GUINT16_TO_BE(version_id)))
        /* Not a stanag4607 file */
        return 0;

    /* seek back to the start of the file  */
    if (file_seek(wth->fh, 0, SEEK_SET, err) == -1)
        return -1;

    wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_STANAG_4607;
    wth->file_encap = WTAP_ENCAP_STANAG_4607;
    wth->snapshot_length = 0; /* not known */

    stanag4607 = (stanag4607_t *)g_malloc(sizeof(stanag4607_t));
    wth->priv = (void *)stanag4607;
    stanag4607->base_secs = 0; /* unknown as of yet */

    wth->subtype_read = stanag4607_read;
    wth->subtype_seek_read = stanag4607_seek_read;
    wth->tsprecision = WTAP_FILE_TSPREC_MSEC;

    return 1;
}
/**
 * @brief Changes the id of a dialog.
 *
 * The index of multiple dialogs may change, since they are sorted alphabetically.
 * In this case, emits rowsAboutToBeRemoved(), removes the dialog,
 * emits rowsRemoved() and rowsAboutToBeInserted(), adds the new dialog
 * and then emits rowsInserted(), as required by QAbstractItemModel.
 *
 * Then, emits dialog_id_changed(), no matter if the index has also changed.
 *
 * The selection is preserved, though the index of many dialogs can change.
 * The selection is cleared before the operations and restored after,
 * updated with the new indexes.
 *
 * @param id Id of an existing dialog.
 * @param new_id The new id to set.
 * @return The new id of the dialog.
 * @throws EditorException in case of error.
 */
QString DialogsModel::set_dialog_id(const QString& id, const QString& new_id) {

  if (new_id == id) {
    // Nothing to do.
    return id;
  }

  // Make some checks first.
  if (!dialog_exists(id)) {
    throw EditorException(tr("Dialog '%1' no exists").arg(id));
  }

  if (dialog_exists(new_id)) {
    throw EditorException(tr("Dialog '%1' already exists").arg(new_id));
  }

  if (!is_valid_id(new_id)) {
    throw EditorException(tr("Invalid dialog id: %1").arg(new_id));
  }

  // Save and clear the selection since a lot of indexes may change.
  QString old_selection = get_selected_id();
  clear_selection();

  // Change in to the strings file.
  resources.set_dialog_id(id.toStdString(), new_id.toStdString());

  // Remove from the indexed tree.
  QString parent_id;
  int index;
  if (dialog_tree.can_remove_key(id, parent_id, index)) {

    // Call beginRemoveRows() as requested by QAbstractItemModel.
    beginRemoveRows(id_to_index(parent_id), index, index);
    dialog_tree.remove_key(id);
    endRemoveRows();
  } else if (dialog_tree.remove_key(id)) {
    QModelIndex model_index = id_to_index(id);
    dataChanged(model_index, model_index);
  }

  // Add to the indexed tree.
  if (dialog_tree.add_key(new_id, parent_id, index)) {

    // Call beginInsertRows() as requested by QAbstractItemModel.
    beginInsertRows(id_to_index(parent_id), index, index);
    endInsertRows();
  } else {
    QModelIndex model_index = id_to_index(id);
    dataChanged(model_index, model_index);
  }

  // Notify people.
  emit dialog_id_changed(id, new_id);

  // Restore the selection.
  set_selected_id(old_selection);
  return new_id;
}
예제 #4
0
파일: geometry.c 프로젝트: siritori/libgeom
bool vertex_scale(const vertex_id *vs, const unsigned len,
  const double x, const double y, const double z)
{
  for(unsigned i = 0; i < len; ++i) {
    if(!is_valid_id(vs[i])) return false;
    vertex_t *v = vp(vs[i]);
    v->x *= x;
    v->y *= y;
    v->z *= z;
  }
  return true;
}
예제 #5
0
파일: drew.c 프로젝트: bk2204/drew
int drew_loader_get_metadata(DrewLoader *ldr, int id, int item,
                             drew_metadata_t *meta)
{
    drew_metadata_t md;
    int retval = 0;

    if (!ldr)
        return -DREW_ERR_INVALID;

    g_rw_lock_reader_lock(&ldr->lock);

    if (!is_valid_id(ldr, id, 0)) {
        g_rw_lock_reader_unlock(&ldr->lock);
        return -DREW_ERR_NONEXISTENT;
    }

    if (item == -1) {
        retval = special_metadata(ldr, id,
                                  (item - ldr->plugin[id].nmetadata), NULL);

        g_rw_lock_reader_unlock(&ldr->lock);
        return ldr->plugin[id].nmetadata + (retval == 0);
    }

    if (item < 0)
        return -DREW_ERR_INVALID;

    if (item < ldr->plugin[id].nmetadata) {
        memcpy(meta, ldr->plugin[id].metadata + item, sizeof(*meta));
        meta->predicate = g_strdup(meta->predicate);
        meta->object = g_strdup(meta->object);
        g_rw_lock_reader_unlock(&ldr->lock);
        return 0;
    }
    else {
        memset(&md, 0, sizeof(md));
        retval = special_metadata(ldr, id,
                                  (item - ldr->plugin[id].nmetadata), &md);
        if (retval < 0) {
            g_free((void *)md.predicate);
            g_free((void *)md.object);
            g_rw_lock_reader_unlock(&ldr->lock);
            return -DREW_ERR_NONEXISTENT;
        }
        memcpy(meta, &md, sizeof(*meta));
        g_rw_lock_reader_unlock(&ldr->lock);
        return 0;
    }

    g_rw_lock_reader_unlock(&ldr->lock);

    return -DREW_ERR_NONEXISTENT;
}
예제 #6
0
파일: drew.c 프로젝트: bk2204/drew
int drew_loader_get_type(DrewLoader *ldr, int id)
{
    if (!ldr)
        return -DREW_ERR_INVALID;

    g_rw_lock_reader_lock(&ldr->lock);

    int retval = is_valid_id(ldr, id, 0) ? ldr->plugin[id].type :
                 -DREW_ERR_INVALID;

    g_rw_lock_reader_unlock(&ldr->lock);

    return retval;
}
예제 #7
0
파일: drew.c 프로젝트: bk2204/drew
/* This function queries the number of plugins in the library which contains the
 * plugin with ID id.  As a special case, if id is -1, return the total number
 * of plugins loaded.
 */
int drew_loader_get_nplugins(DrewLoader *ldr, int id)
{
    int retval = 0;

    if (!ldr)
        return -DREW_ERR_INVALID;

    g_rw_lock_reader_lock(&ldr->lock);

    if (id == -1) {
        retval = ldr->nplugins;
        goto out;
    }
    if (!is_valid_id(ldr, id, 0)) {
        retval = is_valid_id(ldr, id, 1) ? 0 : -DREW_ERR_INVALID;
        goto out;
    }

    retval = ldr->plugin[id].lib->nplugins;
out:
    g_rw_lock_reader_unlock(&ldr->lock);
    return retval;
}
예제 #8
0
static int
select_list(expression_type parent_type,
            struct selection *selection,
            const freesasa_structure *structure,
            const expression *expr)
{
    int resr, resl;
    expression *left, *right;

    if (expr == NULL)
        return fail_msg("NULL expression");

    left = expr->left;
    right = expr->right;

    switch(expr->type) {
    case E_PLUS:
        if (left == NULL || right == NULL)
            return fail_msg("NULL expression");
        resl = select_list(parent_type, selection, structure, left);
        resr = select_list(parent_type, selection, structure, right);
        if (resl == FREESASA_WARN || resr == FREESASA_WARN)
            return FREESASA_WARN;
        break;
    case E_RANGE:
        if (left == NULL || right == NULL)
            return fail_msg("NULL expression");
        return select_range(E_RANGE, parent_type, selection, structure, left, right);
    case E_RANGE_OPEN_L:
        if (left != NULL || right == NULL)
            return fail_msg("NULL expression");
        return select_range(E_RANGE_OPEN_L, parent_type, selection, structure, left, right);
    case E_RANGE_OPEN_R:
        if (left == NULL || right != NULL)
            return fail_msg("NULL expression");
        return select_range(E_RANGE_OPEN_R, parent_type, selection, structure, left, right);
    case E_ID:
    case E_NUMBER:
        if (is_valid_id(parent_type, expr) == FREESASA_SUCCESS)
            select_id(parent_type, selection, structure, expr->value);
        else return freesasa_warn("select: %s: '%s' invalid %s",
                                  e_str(parent_type), expr->value, e_str(expr->type));
        break;
    default:
        return freesasa_fail("select: parse error (expression: '%s %s')",
                             e_str(parent_type), e_str(expr->type));
    }
    return FREESASA_SUCCESS;
}
예제 #9
0
파일: solid.c 프로젝트: siritori/libgeom
vertex_id add_vertex(shape_t *s, const vertex_id v)
{
  if(!is_valid_id(v)) return false;
  if(s->num_vertices >= s->capacity_vertices) {
    s->capacity_vertices *= 2;
    s->vertices = realloc(s->vertices, s->capacity_vertices * sizeof(vertex_id));
    if(s->vertices == NULL) {
      error_printf("out of memory\n");
      FREE(s);
      exit(EXIT_FAILURE);
    }
  }
  s->vertices[s->num_vertices] = v;
  s->num_vertices++;
  return v;
}
예제 #10
0
파일: drew.c 프로젝트: bk2204/drew
int drew_loader_get_algo_name(DrewLoader *ldr, int id,
                              const char **namep)
{
    if (!ldr)
        return -DREW_ERR_INVALID;

    g_rw_lock_reader_lock(&ldr->lock);

    int retval = 0;

    if (!is_valid_id(ldr, id, 0))
        retval = -DREW_ERR_INVALID;
    else
        *namep = ldr->plugin[id].name;

    g_rw_lock_reader_unlock(&ldr->lock);

    return retval;
}
예제 #11
0
파일: drew.c 프로젝트: bk2204/drew
int drew_loader_get_functbl(DrewLoader *ldr, int id, const void **tbl)
{
    if (!ldr)
        return -DREW_ERR_INVALID;

    g_rw_lock_reader_lock(&ldr->lock);

    int retval;

    if (!is_valid_id(ldr, id, 0)) {
        retval = -DREW_ERR_INVALID;
        goto out;
    }

    if (tbl)
        *tbl = ldr->plugin[id].functbl;

    retval = ldr->plugin[id].functblsize;

out:
    g_rw_lock_reader_unlock(&ldr->lock);
    return retval;
}
/**
 * @brief Creates a new dialog.
 *
 * The index of the selection may change, since dialog are sorted
 * alphabetically.
 * Emits rowsAboutToBeInserted(), adds the new dialog
 * and then emits rowsInserted(), as required by QAbstractItemModel.
 *
 * Then, emits dialog_created().
 *
 * The newly created dialog is not initially selected.
 * The existing selection is preserved, though the index of many
 * dialogs can change.
 * The selection is cleared before the operations and restored after,
 * updated with the new index.
 *
 * @param id Id of the dialog to create.
 * @param data Data of the dialog to create.
 * @throws EditorException in case of error.
 */
void DialogsModel::create_dialog(const QString& id, const DialogData& data) {

  // Make some checks first.
  if (!is_valid_id(id)) {
      throw EditorException(tr("Invalid dialog id: %1").arg(id));
  }

  if (dialog_exists(id)) {
      throw EditorException(tr("Dialog '%1' already exists").arg(id));
  }

  // Save and clear the selection since a lot of indexes may change.
  QString old_selection = get_selected_id();
  clear_selection();

  // Add to the strings file.
  resources.add_dialog(id.toStdString(), data);

  // Update the indexed tree.
  QString parent_id;
  int index;
  if (dialog_tree.add_key(id, parent_id, index)) {
    // Notify people before restoring the selection, so that they have a
    // chance to know new indexes before receiving selection signals.
    beginInsertRows(id_to_index(parent_id), index, index);
    endInsertRows();
  } else {
    QModelIndex model_index = id_to_index(id);
    dataChanged(model_index, model_index);
  }

  // Notify people.
  emit dialog_created(id);

  // Restore the selection.
  set_selected_id(old_selection);
}
예제 #13
0
파일: drew.c 프로젝트: bk2204/drew
int drew_loader_lookup_by_type(DrewLoader *ldr, int type, int start,
                               int end)
{
    if (!ldr)
        return -DREW_ERR_INVALID;

    g_rw_lock_reader_lock(&ldr->lock);

    if (end == -1)
        end = ldr->nplugins;

    for (int i = start; i < end; i++) {
        if (!is_valid_id(ldr, i, 0))
            continue;
        if (ldr->plugin[i].type == type) {
            g_rw_lock_reader_unlock(&ldr->lock);
            return i;
        }
    }

    g_rw_lock_reader_unlock(&ldr->lock);

    return -DREW_ERR_NONEXISTENT;
}
예제 #14
0
파일: geometry.c 프로젝트: siritori/libgeom
bool vertex_rotate(const vertex_id *vs,
  const unsigned len, const double degree,
  const double nx, const double ny, const double nz)
{
  const double rad = M_PI_2 * degree / 180.0;
  const double x = nx * sin(rad);
  const double y = ny * sin(rad);
  const double z = nz * sin(rad);
  const double w = cos(rad);
  const double m[3][3] = {
    {1-2*(y*y+z*z), 2*(x*y-z*w)  , 2*(x*z+y*w)  },
    {2*(x*y+z*w)  , 1-2*(z*z+x*x), 2*(y*z-x*w)  },
    {2*(x*y-y*w)  , 2*(y*z+x*w)  , 1-2*(x*x+y*y)},
  };
  for(unsigned i = 0; i < len; ++i) {
    if(!is_valid_id(vs[i])) return false;
    vertex_t *v = vp(vs[i]);
    const vertex_t t = {v->x, v->y, v->z};
    v->x = t.x * m[0][0] + t.y * m[0][1] + t.z * m[0][2];
    v->y = t.x * m[1][0] + t.y * m[1][1] + t.z * m[1][2];
    v->z = t.x * m[2][0] + t.y * m[2][1] + t.z * m[2][2];
  }
  return true;
}
예제 #15
0
static gboolean stanag4607_read_file(wtap *wth, FILE_T fh, wtap_rec *rec,
                               Buffer *buf, int *err, gchar **err_info)
{
  stanag4607_t *stanag4607 = (stanag4607_t *)wth->priv;
  guint32 millisecs, secs, nsecs;
  gint64 offset = 0;
  guint8 stanag_pkt_hdr[PKT_HDR_SIZE+SEG_HDR_SIZE];
  guint32 packet_size;

  *err = 0;

  /* Combined packet header and segment header */
  if (!wtap_read_bytes_or_eof(fh, stanag_pkt_hdr, sizeof stanag_pkt_hdr, err, err_info))
    return FALSE;
  offset += sizeof stanag_pkt_hdr;

  if (!is_valid_id(pntoh16(&stanag_pkt_hdr[0]))) {
    *err = WTAP_ERR_BAD_FILE;
    *err_info = g_strdup("Bad version number");
    return FALSE;
  }

  rec->rec_type = REC_TYPE_PACKET;

  /* The next 4 bytes are the packet length */
  packet_size = pntoh32(&stanag_pkt_hdr[2]);
  if (packet_size > WTAP_MAX_PACKET_SIZE_STANDARD) {
    /*
     * Probably a corrupt capture file; don't blow up trying
     * to allocate space for an immensely-large packet.
     */
    *err = WTAP_ERR_BAD_FILE;
    *err_info = g_strdup_printf("stanag4607: File has %" G_GUINT32_FORMAT "d-byte packet, "
      "bigger than maximum of %u", packet_size, WTAP_MAX_PACKET_SIZE_STANDARD);
    return FALSE;
  }
  if (packet_size < PKT_HDR_SIZE+SEG_HDR_SIZE) {
    /*
     * Probably a corrupt capture file; don't, for example, loop
     * infinitely if the size is zero.
     */
    *err = WTAP_ERR_BAD_FILE;
    *err_info = g_strdup_printf("stanag4607: File has %" G_GUINT32_FORMAT "d-byte packet, "
      "smaller than minimum of %u", packet_size, PKT_HDR_SIZE+SEG_HDR_SIZE);
    return FALSE;
  }
  rec->rec_header.packet_header.caplen = packet_size;
  rec->rec_header.packet_header.len = packet_size;

  /* Sadly, the header doesn't contain times; but some segments do */
  /* So, get the segment header, which is just past the 32-byte header. */
  rec->presence_flags = WTAP_HAS_TS;

  /* If no time specified, it's the last baseline time */
  rec->ts.secs = stanag4607->base_secs;
  rec->ts.nsecs = 0;
  millisecs = 0;

#define MISSION_SEGMENT 1
#define DWELL_SEGMENT 2
#define JOB_DEFINITION_SEGMENT 5
#define PLATFORM_LOCATION_SEGMENT 13
  if (MISSION_SEGMENT == stanag_pkt_hdr[32]) {
    guint8 mseg[39];
    struct tm tm;

    if (!wtap_read_bytes(fh, &mseg, sizeof mseg, err, err_info))
      return FALSE;
    offset += sizeof mseg;

    tm.tm_year = pntoh16(&mseg[35]) - 1900;
    tm.tm_mon = mseg[37] - 1;
    tm.tm_mday = mseg[38];
    tm.tm_hour = 0;
    tm.tm_min = 0;
    tm.tm_sec = 0;
    tm.tm_isdst = -1;
    stanag4607->base_secs = mktime(&tm);
    rec->ts.secs = stanag4607->base_secs;
  }
  else if (PLATFORM_LOCATION_SEGMENT == stanag_pkt_hdr[32]) {
    if (!wtap_read_bytes(fh, &millisecs, sizeof millisecs, err, err_info))
      return FALSE;
    offset += sizeof millisecs;
    millisecs = g_ntohl(millisecs);
  }
  else if (DWELL_SEGMENT == stanag_pkt_hdr[32]) {
    guint8 dseg[19];
    if (!wtap_read_bytes(fh, &dseg, sizeof dseg, err, err_info))
      return FALSE;
    offset += sizeof dseg;
    millisecs = pntoh32(&dseg[15]);
  }
  if (0 != millisecs) {
    secs = millisecs/1000;
    nsecs = (millisecs - 1000 * secs) * 1000000;
    rec->ts.secs = stanag4607->base_secs + secs;
    rec->ts.nsecs = nsecs;
  }

  /* wind back to the start of the packet ... */
  if (file_seek(fh, - offset, SEEK_CUR, err) == -1)
    return FALSE;

  return wtap_read_packet_bytes(fh, buf, packet_size, err, err_info);
}
예제 #16
0
static gboolean stanag4607_read_file(wtap *wth, FILE_T fh, struct wtap_pkthdr *phdr,
                               Buffer *buf, int *err, gchar **err_info)
{
  stanag4607_t *stanag4607 = (stanag4607_t *)wth->priv;
  guint32 millisecs, secs, nsecs;
  gint64 offset = 0;
  guint8 stanag_pkt_hdr[37];
  guint32 packet_size;

  *err = 0;

  /* Combined packet header and segment header */
  if (!wtap_read_bytes_or_eof(fh, stanag_pkt_hdr, sizeof stanag_pkt_hdr, err, err_info))
    return FALSE;
  offset += sizeof stanag_pkt_hdr;

  if (!is_valid_id(pntoh16(&stanag_pkt_hdr[0]))) {
    *err = WTAP_ERR_BAD_FILE;
    *err_info = g_strdup("Bad version number");
    return FALSE;
  }

  phdr->rec_type = REC_TYPE_PACKET;

  /* The next 4 bytes are the packet length */
  packet_size = pntoh32(&stanag_pkt_hdr[2]);
  phdr->caplen = packet_size;
  phdr->len = packet_size;

  /* Sadly, the header doesn't contain times; but some segments do */
  /* So, get the segment header, which is just past the 32-byte header. */
  phdr->presence_flags = WTAP_HAS_TS;

  /* If no time specified, it's the last baseline time */
  phdr->ts.secs = stanag4607->base_secs;
  phdr->ts.nsecs = 0;
  millisecs = 0;

#define MISSION_SEGMENT 1
#define DWELL_SEGMENT 2
#define JOB_DEFINITION_SEGMENT 5
#define PLATFORM_LOCATION_SEGMENT 13
  if (MISSION_SEGMENT == stanag_pkt_hdr[32]) {
    guint8 mseg[39];
    struct tm tm;

    if (!wtap_read_bytes(fh, &mseg, sizeof mseg, err, err_info))
      return FALSE;
    offset += sizeof mseg;

    tm.tm_year = pntoh16(&mseg[35]) - 1900;
    tm.tm_mon = mseg[37] - 1;
    tm.tm_mday = mseg[38];
    tm.tm_hour = 0;
    tm.tm_min = 0;
    tm.tm_sec = 0;
    tm.tm_isdst = -1;
    stanag4607->base_secs = mktime(&tm);
    phdr->ts.secs = stanag4607->base_secs;
  }
  else if (PLATFORM_LOCATION_SEGMENT == stanag_pkt_hdr[32]) {
    if (!wtap_read_bytes(fh, &millisecs, sizeof millisecs, err, err_info))
      return FALSE;
    offset += sizeof millisecs;
    millisecs = g_ntohl(millisecs);
  }
  else if (DWELL_SEGMENT == stanag_pkt_hdr[32]) {
    guint8 dseg[19];
    if (!wtap_read_bytes(fh, &dseg, sizeof dseg, err, err_info))
      return FALSE;
    offset += sizeof dseg;
    millisecs = pntoh32(&dseg[15]);
  }
  if (0 != millisecs) {
    secs = millisecs/1000;
    nsecs = (millisecs - 1000 * secs) * 1000000;
    phdr->ts.secs = stanag4607->base_secs + secs;
    phdr->ts.nsecs = nsecs;
  }

  /* wind back to the start of the packet ... */
  if (file_seek(fh, - offset, SEEK_CUR, err) == -1)
    return FALSE;

  return wtap_read_packet_bytes(fh, buf, packet_size, err, err_info);
}
예제 #17
0
파일: geometry.c 프로젝트: siritori/libgeom
vertex_id copy_vertex(const vertex_id v)
{
  if(!is_valid_id(v)) return ERROR_VERTEX;
  return new_vertex(vertices[v].x, vertices[v].y, vertices[v].z);
}
예제 #18
0
void parse_config_internal(const config *help_cfg, const config *section_cfg,
						   section &sec, int level)
{
	if (level > max_section_level) {
		std::cerr << "Maximum section depth has been reached. Maybe circular dependency?"
				  << std::endl;
	}
	else if (section_cfg != NULL) {
		const std::vector<std::string> sections = utils::quoted_split((*section_cfg)["sections"]);
		sec.level = level;
		std::string id = level == 0 ? "toplevel" : (*section_cfg)["id"].str();
		if (level != 0) {
			if (!is_valid_id(id)) {
				std::stringstream ss;
				ss << "Invalid ID, used for internal purpose: '" << id << "'";
				throw help::parse_error(ss.str());
			}
		}
		t_string title = level == 0 ? "" : (*section_cfg)["title"].t_str();
		sec.id = id;
		sec.title = title;
		std::vector<std::string>::const_iterator it;
		// Find all child sections.
		for (it = sections.begin(); it != sections.end(); ++it) {
			if (const config &child_cfg = help_cfg->find_child("section", "id", *it))
			{
				section child_section;
				parse_config_internal(help_cfg, &child_cfg, child_section, level + 1);
				sec.add_section(child_section);
			}
			else {
				std::stringstream ss;
				ss << "Help-section '" << *it << "' referenced from '"
				   << id << "' but could not be found.";
				throw help::parse_error(ss.str());
			}
		}

		generate_sections(help_cfg, (*section_cfg)["sections_generator"], sec, level);
		//TODO: harmonize topics/sections sorting
		if ((*section_cfg)["sort_sections"] == "yes") {
			std::sort(sec.sections.begin(),sec.sections.end(), section_less());
		}

		bool sort_topics = false;
		bool sort_generated = true;

		if ((*section_cfg)["sort_topics"] == "yes") {
		  sort_topics = true;
		  sort_generated = false;
		} else if ((*section_cfg)["sort_topics"] == "no") {
		  sort_topics = false;
    	  sort_generated = false;
		} else if ((*section_cfg)["sort_topics"] == "generated") {
		  sort_topics = false;
		  sort_generated = true;
		} else if ((*section_cfg)["sort_topics"] != "") {
		  std::stringstream ss;
		  ss << "Invalid sort option: '" << (*section_cfg)["sort_topics"] << "'";
		  throw help::parse_error(ss.str());
		}

		std::vector<topic> generated_topics =
		generate_topics(sort_generated,(*section_cfg)["generator"]);

		const std::vector<std::string> topics_id = utils::quoted_split((*section_cfg)["topics"]);
		std::vector<topic> topics;

		// Find all topics in this section.
		for (it = topics_id.begin(); it != topics_id.end(); ++it) {
			if (const config &topic_cfg = help_cfg->find_child("topic", "id", *it))
			{
				t_string text = topic_cfg["text"].t_str();
				text += generate_topic_text(topic_cfg["generator"], help_cfg, sec, generated_topics);
				topic child_topic(topic_cfg["title"], topic_cfg["id"], text);
				if (!is_valid_id(child_topic.id)) {
					std::stringstream ss;
					ss << "Invalid ID, used for internal purpose: '" << id << "'";
					throw help::parse_error(ss.str());
				}
				topics.push_back(child_topic);
			}
			else {
				std::stringstream ss;
				ss << "Help-topic '" << *it << "' referenced from '" << id
				   << "' but could not be found." << std::endl;
				throw help::parse_error(ss.str());
			}
		}

		if (sort_topics) {
			std::sort(topics.begin(),topics.end(), title_less());
			std::sort(generated_topics.begin(),
			  generated_topics.end(), title_less());
			std::merge(generated_topics.begin(),
			  generated_topics.end(),topics.begin(),topics.end()
			  ,std::back_inserter(sec.topics),title_less());
		}
		else {
			std::copy(topics.begin(), topics.end(),
			  std::back_inserter(sec.topics));
			std::copy(generated_topics.begin(),
			  generated_topics.end(),
			  std::back_inserter(sec.topics));
		}
	}
}