Example #1
0
// ----------------------------------------------------------------
static void mapper_step_free(void* pvstate) {
	mapper_step_state_t* pstate = pvstate;
	slls_free(pstate->pstepper_names);
	slls_free(pstate->pvalue_field_names);
	slls_free(pstate->pgroup_by_field_names);
	// xxx free the level-2's 1st
	lhmslv_free(pstate->groups);
}
Example #2
0
static lrec_t* lrec_reader_csvex_process(void* pvhandle, void* pvstate, context_t* pctx) {
	lrec_reader_csvex_state_t* pstate = pvstate;

//	xxx byte-reader open ...
//	if (pstate->pfr == NULL) {
//		pstate->pfr = pfr_alloc((FILE*)pvhandle, pstate->peek_buf_len);
//	}

	if (pstate->expect_header_line_next) {
		slls_t* pheader_fields = lrec_reader_csvex_get_fields(pstate);
		if (pheader_fields == NULL)
			return NULL;
		pstate->ilno++;
		pstate->expect_header_line_next = FALSE;

		pstate->pheader_keeper = lhmslv_get(pstate->pheader_keepers, pheader_fields);
		if (pstate->pheader_keeper == NULL) {
			pstate->pheader_keeper = header_keeper_alloc(NULL, pheader_fields);
			lhmslv_put(pstate->pheader_keepers, pheader_fields, pstate->pheader_keeper);
		} else { // Re-use the header-keeper in the header cache
			slls_free(pheader_fields);
		}
	}
	pstate->ilno++;

	slls_t* pdata_fields = lrec_reader_csvex_get_fields(pstate);
	return paste_header_and_data(pstate, pdata_fields);
}
static lrec_t* lrec_reader_mmap_csvlite_process_multi_seps(void* pvstate, void* pvhandle, context_t* pctx) {
	file_reader_mmap_state_t* phandle = pvhandle;
	lrec_reader_mmap_csvlite_state_t* pstate = pvstate;

	while (TRUE) {
		if (pstate->expect_header_line_next) {

			slls_t* pheader_fields = lrec_reader_mmap_csvlite_get_header_multi_seps(phandle, pstate);
			if (pheader_fields == NULL) // EOF
				return NULL;

			pstate->expect_header_line_next = FALSE;

			pstate->pheader_keeper = lhmslv_get(pstate->pheader_keepers, pheader_fields);
			if (pstate->pheader_keeper == NULL) {
				pstate->pheader_keeper = header_keeper_alloc(NULL, pheader_fields);
				lhmslv_put(pstate->pheader_keepers, pheader_fields, pstate->pheader_keeper);
			} else { // Re-use the header-keeper in the header cache
				slls_free(pheader_fields);
			}
		}

		int end_of_stanza = FALSE;
		lrec_t* prec = lrec_reader_mmap_csvlite_get_record_multi_seps(phandle, pstate, pstate->pheader_keeper,
			&end_of_stanza);
		if (end_of_stanza) {
			pstate->expect_header_line_next = TRUE;
		} else if (prec == NULL) { // EOF
			return NULL;
		} else {
			return prec;
		}
	}
}
Example #4
0
// ----------------------------------------------------------------
static void lrec_writer_pprint_process(FILE* output_stream, lrec_t* prec, void* pvstate) {
	lrec_writer_pprint_state_t* pstate = pvstate;

	int drain = FALSE;

	if (prec == NULL) {
		drain = TRUE;
	} else {
		if (pstate->pprev_keys != NULL && !lrec_keys_equal_list(prec, pstate->pprev_keys)) {
			drain = TRUE;
		}
	}

	if (drain) {
		if (pstate->num_blocks_written > 0LL) // separate blocks with empty line
			fputs(pstate->ors, output_stream);
		print_and_free_record_list(pstate->precords, output_stream, pstate->ors, pstate->ofs, pstate->left_align);
		if (pstate->pprev_keys != NULL) {
			slls_free(pstate->pprev_keys);
			pstate->pprev_keys = NULL;
		}
		pstate->precords = sllv_alloc();
		pstate->num_blocks_written++;
	}
	if (prec != NULL) {
		sllv_append(pstate->precords, prec);
		if (pstate->pprev_keys == NULL)
			pstate->pprev_keys = mlr_copy_keys_from_record(prec);
	}
}
Example #5
0
static void lrec_writer_csv_free(void* pvstate) {
    lrec_writer_csv_state_t* pstate = pvstate;
    if (pstate->plast_header_output != NULL) {
        slls_free(pstate->plast_header_output);
        pstate->plast_header_output = NULL;
    }
}
Example #6
0
// ----------------------------------------------------------------
static void mapper_tail_free(void* pvstate) {
    mapper_tail_state_t* pstate = pvstate;
    if (pstate->pgroup_by_field_names != NULL)
        slls_free(pstate->pgroup_by_field_names);
    if (pstate->precord_lists_by_group != NULL)
        // xxx free the void-star payloads 1st
        lhmslv_free(pstate->precord_lists_by_group);
}
Example #7
0
// ----------------------------------------------------------------
static void mapper_head_free(void* pvstate) {
	mapper_head_state_t* pstate = (mapper_head_state_t*)pvstate;
	if (pstate->pgroup_by_field_names != NULL)
		slls_free(pstate->pgroup_by_field_names);

	// xxx recursively free void-stars ... here & elsewhere.
	lhmslv_free(pstate->precord_lists_by_group);
}
static lrec_t* lrec_reader_stdio_csv_process(void* pvhandle, void* pvstate, context_t* pctx) {
	FILE* input_stream = pvhandle;
	lrec_reader_stdio_csv_state_t* pstate = pvstate;

	while (TRUE) {
		if (pstate->expect_header_line_next) {
			// xxx cmt
			while (TRUE) {
				char* hline = mlr_get_line(input_stream, pstate->irs);
				if (hline == NULL) // EOF
					return NULL;
				pstate->ilno++;

				slls_t* pheader_fields = split_csv_header_line(hline, pstate->ifs, pstate->allow_repeat_ifs);
				if (pheader_fields->length == 0) {
					pstate->expect_header_line_next = TRUE;
					if (pstate->pheader_keeper != NULL) {
						pstate->pheader_keeper = NULL;
					}
				} else {
					pstate->expect_header_line_next = FALSE;

					pstate->pheader_keeper = lhmslv_get(pstate->pheader_keepers, pheader_fields);
					if (pstate->pheader_keeper == NULL) {
						pstate->pheader_keeper = header_keeper_alloc(hline, pheader_fields);
						lhmslv_put(pstate->pheader_keepers, pheader_fields, pstate->pheader_keeper);
					} else { // Re-use the header-keeper in the header cache
						slls_free(pheader_fields);
						free(hline);
					}
					break;
				}
			}
		}

		char* line = mlr_get_line(input_stream, pstate->irs);
		if (line == NULL) // EOF
			return NULL;

		// xxx empty-line check ... make a lib func is_empty_modulo_whitespace().
		if (!*line) {
			if (pstate->pheader_keeper != NULL) {
				pstate->pheader_keeper = NULL;
				pstate->expect_header_line_next = TRUE;
				free(line);
				continue;
			}
		} else {
			pstate->ifnr++;
			return lrec_parse_stdio_csv_data_line(pstate->pheader_keeper, line, pstate->ifs, pstate->allow_repeat_ifs);
		}
	}
}
Example #9
0
static void lrec_writer_pprint_free(lrec_writer_t* pwriter) {
	lrec_writer_pprint_state_t* pstate = pwriter->pvstate;
	if (pstate->precords != NULL) {
		sllv_free(pstate->precords);
		pstate->precords = NULL;
	}
	if (pstate->pprev_keys != NULL) {
		slls_free(pstate->pprev_keys);
		pstate->pprev_keys = NULL;
	}
	free(pstate);
	free(pwriter);
}
Example #10
0
// ----------------------------------------------------------------
static lrec_t* lrec_reader_mmap_csv_process(void* pvstate, void* pvhandle, context_t* pctx) {
	lrec_reader_mmap_csv_state_t* pstate = pvstate;
	file_reader_mmap_state_t* phandle = pvhandle;

	if (pstate->expect_header_line_next) {
		if (!lrec_reader_mmap_csv_get_fields(pstate, pstate->pfields, phandle))
			return NULL;
		pstate->ilno++;

		slls_t* pheader_fields = slls_alloc();
		int i = 0;
		for (rsllse_t* pe = pstate->pfields->phead; i < pstate->pfields->length && pe != NULL; pe = pe->pnext, i++) {
			if (*pe->value == 0) {
				fprintf(stderr, "%s: unacceptable empty CSV key at file \"%s\" line %lld.\n",
					MLR_GLOBALS.argv0, pctx->filename, pstate->ilno);
				exit(1);
			}
			// Transfer pointer-free responsibility from the rslls to the
			// header fields in the header keeper
			slls_append(pheader_fields, pe->value, pe->free_flag);
			pe->free_flag = 0;
		}
		rslls_reset(pstate->pfields);

		pstate->pheader_keeper = lhmslv_get(pstate->pheader_keepers, pheader_fields);
		if (pstate->pheader_keeper == NULL) {
			pstate->pheader_keeper = header_keeper_alloc(NULL, pheader_fields);
			lhmslv_put(pstate->pheader_keepers, pheader_fields, pstate->pheader_keeper,
				NO_FREE); // freed by header-keeper
		} else { // Re-use the header-keeper in the header cache
			slls_free(pheader_fields);
		}

		pstate->expect_header_line_next = FALSE;
	}
	int rc = lrec_reader_mmap_csv_get_fields(pstate, pstate->pfields, phandle);
	pstate->ilno++;
	if (rc == FALSE) // EOF
		return NULL;
	else {
		lrec_t* prec = pstate->use_implicit_header
			? paste_indices_and_data(pstate, pstate->pfields, pctx)
			: paste_header_and_data(pstate, pstate->pfields, pctx);
		rslls_reset(pstate->pfields);
		return prec;
	}
}
Example #11
0
// ----------------------------------------------------------------
static void lrec_writer_csv_process(FILE* output_stream, lrec_t* prec, void* pvstate) {
	if (prec == NULL)
		return;
	lrec_writer_csv_state_t* pstate = pvstate;
	char *ors = pstate->ors;
	char *ofs = pstate->ofs;

	if (pstate->plast_header_output != NULL) {
		if (!lrec_keys_equal_list(prec, pstate->plast_header_output)) {
			slls_free(pstate->plast_header_output);
			pstate->plast_header_output = NULL;
			if (pstate->num_header_lines_output > 0LL)
				fputs(ors, output_stream);
		}
	}

	if (pstate->plast_header_output == NULL) {
		int nf = 0;
		if (!pstate->headerless_csv_output) {
			for (lrece_t* pe = prec->phead; pe != NULL; pe = pe->pnext) {
				if (nf > 0)
					fputs(ofs, output_stream);
				pstate->pquoted_output_func(output_stream, pe->key, pstate->ors, pstate->ofs,
					pstate->orslen, pstate->ofslen);
				nf++;
			}
			fputs(ors, output_stream);
		}
		pstate->plast_header_output = mlr_copy_keys_from_record(prec);
		pstate->num_header_lines_output++;
	}

	int nf = 0;
	for (lrece_t* pe = prec->phead; pe != NULL; pe = pe->pnext) {
		if (nf > 0)
			fputs(ofs, output_stream);
		pstate->pquoted_output_func(output_stream, pe->value, pstate->ors, pstate->ofs,
			pstate->orslen, pstate->ofslen);
		nf++;
	}
	fputs(ors, output_stream);
	pstate->onr++;

	// See ../README.md for memory-management conventions
	lrec_free(prec);
}
Example #12
0
void ap_free(ap_state_t* pstate) {
	if (pstate == NULL)
		return;

	for (sllve_t* pe = pstate->pflag_defs->phead; pe != NULL; pe = pe->pnext) {
		ap_flag_def_t* pdef = pe->pvdata;
		if (pdef->type == AP_STRING_LIST_FLAG && pdef->pval != NULL) {
			slls_t** pplist = pdef->pval;
			if (*pplist != NULL)
				slls_free(*pplist);
		}
		free(pdef);
	}
	sllv_free(pstate->pflag_defs);

	free(pstate);
}
Example #13
0
static void lrec_writer_csv_process(FILE* output_stream, lrec_t* prec, void* pvstate) {
    if (prec == NULL)
        return;
    lrec_writer_csv_state_t* pstate = pvstate;
    char ors = pstate->ors;
    char ofs = pstate->ofs;

    if (pstate->plast_header_output != NULL) {
        // xxx make a fcn to compare these w/o copy: put it in mixutil.
        if (!lrec_keys_equal_list(prec, pstate->plast_header_output)) {
            slls_free(pstate->plast_header_output);
            pstate->plast_header_output = NULL;
            if (pstate->num_header_lines_output > 0LL)
                fputc(ors, output_stream);
        }
    }

    if (pstate->plast_header_output == NULL) {
        int nf = 0;
        for (lrece_t* pe = prec->phead; pe != NULL; pe = pe->pnext) {
            if (nf > 0)
                fputc(ofs, output_stream);
            fputs(pe->key, output_stream);
            nf++;
        }
        fputc(ors, output_stream);
        pstate->plast_header_output = mlr_copy_keys_from_record(prec);
        pstate->num_header_lines_output++;
    }

    int nf = 0;
    for (lrece_t* pe = prec->phead; pe != NULL; pe = pe->pnext) {
        if (nf > 0)
            fputc(ofs, output_stream);
        fputs(pe->value, output_stream);
        nf++;
    }
    fputc(ors, output_stream);
    pstate->onr++;

    lrec_free(prec); // xxx cmt mem-mgmt
}
// ----------------------------------------------------------------
static lrec_t* lrec_reader_stdio_xtab_process(void* pvstate, void* pvhandle, context_t* pctx) {
	FILE* input_stream = pvhandle;
	lrec_reader_stdio_xtab_state_t* pstate = pvstate;

	if (pstate->at_eof)
		return NULL;

	slls_t* pxtab_lines = slls_alloc();

	while (TRUE) {
		char* line = (pstate->ifslen == 1)
			? mlr_get_cline(input_stream, pstate->ifs[0])
			: mlr_get_sline(input_stream, pstate->ifs, pstate->ifslen);
		if (line == NULL) { // EOF
			// EOF or blank line terminates the stanza.
			pstate->at_eof = TRUE;
			if (pxtab_lines->length == 0) {
				slls_free(pxtab_lines);
				return NULL;
			} else {
				return (pstate->ipslen == 1)
					? lrec_parse_stdio_xtab_single_ips(pxtab_lines, pstate->ips[0], pstate->allow_repeat_ips)
					: lrec_parse_stdio_xtab_multi_ips(pxtab_lines, pstate->ips, pstate->ipslen, pstate->allow_repeat_ips);
			}
		} else if (*line == '\0') {
			free(line);
			if (pxtab_lines->length > 0) {
				return (pstate->ipslen == 1)
					? lrec_parse_stdio_xtab_single_ips(pxtab_lines, pstate->ips[0], pstate->allow_repeat_ips)
					: lrec_parse_stdio_xtab_multi_ips(pxtab_lines, pstate->ips, pstate->ipslen, pstate->allow_repeat_ips);
			}
		} else {
			slls_add_with_free(pxtab_lines, line);
		}
	}
}
Example #15
0
static void lrec_free_multiline_backing(lrec_t* prec) {
	slls_free(prec->pxtab_lines);
}
Example #16
0
static void lrec_writer_csv_free(lrec_writer_t* pwriter) {
	lrec_writer_csv_state_t* pstate = pwriter->pvstate;
	slls_free(pstate->plast_header_output);
	free(pstate);
	free(pwriter);
}
// ----------------------------------------------------------------
static lrec_t* lrec_reader_stdio_csvlite_process(void* pvstate, void* pvhandle, context_t* pctx) {
	FILE* input_stream = pvhandle;
	lrec_reader_stdio_csvlite_state_t* pstate = pvstate;

	while (TRUE) {
		if (pstate->expect_header_line_next) {
			while (TRUE) {
				char* hline = (pstate->irslen == 1)
					? mlr_get_cline(input_stream, pstate->irs[0])
					: mlr_get_sline(input_stream, pstate->irs, pstate->irslen);
				if (hline == NULL) // EOF
					return NULL;
				pstate->ilno++;

				slls_t* pheader_fields = (pstate->ifslen == 1)
					? split_csvlite_header_line_single_ifs(hline, pstate->ifs[0], pstate->allow_repeat_ifs)
					: split_csvlite_header_line_multi_ifs(hline, pstate->ifs, pstate->ifslen, pstate->allow_repeat_ifs);
				if (pheader_fields->length == 0) {
					pstate->expect_header_line_next = TRUE;
					if (pstate->pheader_keeper != NULL) {
						pstate->pheader_keeper = NULL;
					}
				} else {
					for (sllse_t* pe = pheader_fields->phead; pe != NULL; pe = pe->pnext) {
						if (*pe->value == 0) {
							fprintf(stderr, "%s: unacceptable empty CSV key at file \"%s\" line %lld.\n",
								MLR_GLOBALS.argv0, pctx->filename, pstate->ilno);
							exit(1);
						}
					}

					pstate->expect_header_line_next = FALSE;

					pstate->pheader_keeper = lhmslv_get(pstate->pheader_keepers, pheader_fields);
					if (pstate->pheader_keeper == NULL) {
						pstate->pheader_keeper = header_keeper_alloc(hline, pheader_fields);
						lhmslv_put(pstate->pheader_keepers, pheader_fields, pstate->pheader_keeper,
							NO_FREE); // freed by header-keeper
					} else { // Re-use the header-keeper in the header cache
						slls_free(pheader_fields);
						free(hline);
					}
					break;
				}
			}
		}

		char* line = (pstate->irslen == 1)
			? mlr_get_cline(input_stream, pstate->irs[0])
			: mlr_get_sline(input_stream, pstate->irs, pstate->irslen);
		if (line == NULL) // EOF
			return NULL;
		pstate->ilno++;

		if (!*line) {
			if (pstate->pheader_keeper != NULL) {
				pstate->pheader_keeper = NULL;
				pstate->expect_header_line_next = TRUE;
				free(line);
				continue;
			}
		} else {
			pstate->ifnr++;
			if (pstate->ifslen == 1) {
				return pstate->use_implicit_header
					? lrec_parse_stdio_csvlite_data_line_single_ifs_implicit_header(
						pstate->pheader_keeper, pctx->filename, pstate->ilno, line,
						pstate->ifs[0], pstate->allow_repeat_ifs)
					:  lrec_parse_stdio_csvlite_data_line_single_ifs(pstate->pheader_keeper, pctx->filename, pstate->ilno, line,
						pstate->ifs[0], pstate->allow_repeat_ifs);
			} else {
				return pstate->use_implicit_header
					? lrec_parse_stdio_csvlite_data_line_multi_ifs_implicit_header(
						pstate->pheader_keeper, pctx->filename, pstate->ilno, line,
						pstate->ifs, pstate->ifslen, pstate->allow_repeat_ifs)
					: lrec_parse_stdio_csvlite_data_line_multi_ifs(pstate->pheader_keeper, pctx->filename, pstate->ilno, line,
						pstate->ifs, pstate->ifslen, pstate->allow_repeat_ifs);
			}
		}
	}
}
Example #18
0
// ----------------------------------------------------------------
static lrec_t* lrec_reader_stdio_csv_process(void* pvstate, void* pvhandle, context_t* pctx) {
	lrec_reader_stdio_csv_state_t* pstate = pvstate;

	// Ingest the next header line, if expected
	if (pstate->expect_header_line_next) {
		while (TRUE) {
			if (!lrec_reader_stdio_csv_get_fields(pstate, pstate->pfields, pctx, TRUE))
				return NULL;
			pstate->ilno++;

			// We check for comments here rather than within the parser since it's important
			// for users to be able to comment out lines containing double-quoted newlines.
			if (pstate->comment_string != NULL && pstate->pfields->phead != NULL) {
				if (streqn(pstate->pfields->phead->value, pstate->comment_string, pstate->comment_string_length)) {
					if (pstate->comment_handling == PASS_COMMENTS) {
						int i = 0;
						for (
							rsllse_t* pe = pstate->pfields->phead;
							i < pstate->pfields->length && pe != NULL;
							pe = pe->pnext, i++)
						{
							if (i > 0)
								fputs(pstate->ifs, stdout);
							fputs(pe->value, stdout);
						}
						if (pstate->do_auto_line_term) {
							fputs(pctx->auto_line_term, stdout);
						} else {
							fputs(pstate->irs, stdout);
						}
					}
					rslls_reset(pstate->pfields);
					continue;
				}
			}

			slls_t* pheader_fields = slls_alloc();
			int i = 0;
			for (rsllse_t* pe = pstate->pfields->phead; i < pstate->pfields->length && pe != NULL; pe = pe->pnext) {
				if (*pe->value == 0) {
					fprintf(stderr, "%s: unacceptable empty CSV key at file \"%s\" line %lld.\n",
						MLR_GLOBALS.bargv0, pctx->filename, pstate->ilno);
					exit(1);
				}
				// Transfer pointer-free responsibility from the rslls to the
				// header fields in the header keeper
				slls_append(pheader_fields, pe->value, pe->free_flag);
				pe->free_flag = 0;
			}
			rslls_reset(pstate->pfields);

			pstate->pheader_keeper = lhmslv_get(pstate->pheader_keepers, pheader_fields);
			if (pstate->pheader_keeper == NULL) {
				pstate->pheader_keeper = header_keeper_alloc(NULL, pheader_fields);
				lhmslv_put(pstate->pheader_keepers, pheader_fields, pstate->pheader_keeper,
					NO_FREE); // freed by header-keeper
			} else { // Re-use the header-keeper in the header cache
				slls_free(pheader_fields);
			}

			pstate->expect_header_line_next = FALSE;
			break;
		}
	}

	// Ingest the next data line, if expected
	while (TRUE) {
		int rc = lrec_reader_stdio_csv_get_fields(pstate, pstate->pfields, pctx, FALSE);
		pstate->ilno++;
		if (rc == FALSE) // EOF
			return NULL;

		// We check for comments here rather than within the parser since it's important
		// for users to be able to comment out lines containing double-quoted newlines.
		if (pstate->comment_string != NULL && pstate->pfields->phead != NULL) {
			if (streqn(pstate->pfields->phead->value, pstate->comment_string, pstate->comment_string_length)) {
				if (pstate->comment_handling == PASS_COMMENTS) {
					int i = 0;
					for (
						rsllse_t* pe = pstate->pfields->phead;
						i < pstate->pfields->length && pe != NULL;
						pe = pe->pnext, i++)
					{
						if (i > 0)
							fputs(pstate->ifs, stdout);
						fputs(pe->value, stdout);
					}
					if (pstate->do_auto_line_term) {
						fputs(pctx->auto_line_term, stdout);
					} else {
						fputs(pstate->irs, stdout);
					}
				}
				rslls_reset(pstate->pfields);
				continue;
			}
		}

		lrec_t* prec =  pstate->use_implicit_header
			? paste_indices_and_data(pstate, pstate->pfields, pctx)
			: paste_header_and_data(pstate, pstate->pfields, pctx);
		rslls_reset(pstate->pfields);
		return prec;
	}
}
Example #19
0
// ----------------------------------------------------------------
static void mapper_reorder_free(void* pvstate) {
	mapper_reorder_state_t* pstate = (mapper_reorder_state_t*)pvstate;
	if (pstate->pfield_name_list != NULL)
		slls_free(pstate->pfield_name_list);
}
Example #20
0
// ----------------------------------------------------------------
int ap_parse(ap_state_t* pstate, char* verb, int* pargi, int argc, char** argv) {

	int argi = *pargi;
	int ok = TRUE;

	while (argi < argc) {
		if (argv[argi][0] != '-') {
			break;
		}
		if (streq(argv[argi], "-h") || streq(argv[argi], "--help")) {
			ok = FALSE;
			break;
		}

		ap_flag_def_t* pdef = ap_find(pstate, argv[argi]);
		if (pdef == NULL) {
			ok = FALSE;
			break;
		}

		if ((argc-argi) < pdef->count) {
			fprintf(stderr, "%s %s: option %s requires an argument.\n",
				argv[0], verb, argv[argi]);
			fprintf(stderr, "\n");
			ok = FALSE;
			break;
		}

		if (pdef->type == AP_INT_VALUE_FLAG) {
			*(int *)pdef->pval = pdef->intval;
		} else if (pdef->type == AP_CHAR_FLAG) {
			if (!try_sep_from_arg(argv[argi+1], (char *)pdef->pval)) {
				fprintf(stderr, "%s %s: couldn't parse \"%s\" after \"%s\" as character.\n",
					argv[0], verb, argv[argi+1], argv[argi]);
				fprintf(stderr, "\n");
			}

		} else if (pdef->type == AP_INT_FLAG) {
			if (sscanf(argv[argi+1], "%d", (int *)pdef->pval) != 1) {
				fprintf(stderr, "%s %s: couldn't parse \"%s\" after \"%s\" as integer.\n",
					argv[0], verb, argv[argi+1], argv[argi]);
				fprintf(stderr, "\n");
			}

		} else if (pdef->type == AP_DOUBLE_FLAG) {
			if (!mlr_try_double_from_string(argv[argi+1], (double *)pdef->pval)) {
				fprintf(stderr, "%s %s: couldn't parse \"%s\" after \"%s\" as double.\n",
					argv[0], verb, argv[argi+1], argv[argi]);
				fprintf(stderr, "\n");
			}
		} else if (pdef->type == AP_STRING_FLAG) {
			char** pstring = pdef->pval;
			*pstring = argv[argi+1];
			pdef->pval = pstring;
		} else if (pdef->type == AP_STRING_LIST_FLAG) {
			slls_t** pplist = pdef->pval;

			if (*pplist != NULL)
				slls_free(*pplist);
			*pplist = slls_from_line(argv[argi+1], ',', FALSE);

			pdef->pval = pplist;
		} else {
			ok = FALSE;
			fprintf(stderr, "argparse.c: coding error: flag-def type %x not recognized.\n", pdef->type);
			fprintf(stderr, "\n");
			break;
		}

		argi += pdef->count;
	}

	*pargi = argi;
	return ok;
}