SDDSlib
Loading...
Searching...
No Matches
sddsselect.c
Go to the documentation of this file.
1/**
2 * @file sddsselect.c
3 * @brief Creates an SDDS data set from another data set based on matching data in a third data set.
4 *
5 * This program selects rows from <input1> that have (or do not have, if inverted)
6 * a matching entry in <input2>, based on specified matching or equating columns.
7 * The output is written to <output>, or <input1> is replaced if <output> is not provided.
8 *
9 * ## Usage
10 * ```
11 * sddsselect [OPTIONS] [<input1>] <input2> [<output>]
12 * ```
13 *
14 * ## Options
15 * - `-pipe[=input][,output]`
16 * Use pipe for input and/or output.
17 *
18 * - `-match=<column1>[=<column2>]`
19 * Specify columns to match between `input1` and `input2`.
20 *
21 * - `-equate=<column1>[=<column2>]`
22 * Specify columns to equate between `input1` and `input2`.
23 *
24 * - `-invert`
25 * Invert the selection to keep non-matching rows.
26 *
27 * - `-reuse[=rows][,page]`
28 * Allow reusing rows or specify page reuse.
29 *
30 * - `-majorOrder=row|column`
31 * Set the output file to row or column major order.
32 *
33 * - `-nowarnings`
34 * Suppress warning messages.
35 *
36 * @copyright
37 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
38 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
39 *
40 * @license
41 * This file is distributed under the terms of the Software License Agreement
42 * found in the file LICENSE included with this distribution.
43 *
44 * @author M. Borland, C. Saunders, R. Soliday, H. Shang
45 */
46
47#include "mdb.h"
48#include "SDDS.h"
49#include "scan.h"
50
51/* Enumeration for option types */
52enum option_type {
53 SET_MATCH_COLUMN,
54 SET_EQUATE_COLUMN,
55 SET_NOWARNINGS,
56 SET_INVERT,
57 SET_REUSE,
58 SET_PIPE,
59 SET_MAJOR_ORDER,
60 N_OPTIONS
61};
62
63char *option[N_OPTIONS] = {
64 "match",
65 "equate",
66 "nowarnings",
67 "invert",
68 "reuse",
69 "pipe",
70 "majorOrder",
71};
72
73char *USAGE = "Usage: sddsselect [OPTIONS] [<input1>] <input2> [<output>]\n\
74\n\
75Options:\n\
76 -pipe[=input][,output] Use pipe for input and/or output.\n\
77 -match=<column1>[=<column2>] Specify columns to match between input1 and input2.\n\
78 -equate=<column1>[=<column2>] Specify columns to equate between input1 and input2.\n\
79 -invert Invert the selection to keep non-matching rows.\n\
80 -reuse[=rows][,page] Allow reusing rows or specify page reuse.\n\
81 -majorOrder=row|column Set the output file to row or column major order.\n\
82 -nowarnings Suppress warning messages.\n\
83\n\
84Example:\n\
85 sddsselect -match=colA=colB input1.sdds input2.sdds output.sdds\n\
86\n\
87Program by Michael Borland. (" __DATE__ " " __TIME__ ", SVN revision: " SVN_VERSION ")\n";
88
89int main(int argc, char **argv) {
90 SDDS_DATASET SDDS_1, SDDS_2, SDDS_output;
91 long i, j, i_arg, reuse, reusePage;
92 int64_t rows1, rows2, i1, i2;
93 SCANNED_ARG *s_arg;
94 char s[200], *ptr;
95 char **match_column, **equate_column;
96 long match_columns, equate_columns;
97 char *input1, *input2, *output;
98 long tmpfile_used, retval1, retval2;
99 long warnings, invert;
100 unsigned long pipeFlags, majorOrderFlag;
101 KEYED_EQUIVALENT **keyGroup = NULL;
102 long keyGroups = 0;
103 short columnMajorOrder = -1;
104
106 argc = scanargs(&s_arg, argc, argv);
107 if (argc < 3)
108 bomb(NULL, USAGE);
109
110 input1 = input2 = output = NULL;
111 match_column = equate_column = NULL;
112 match_columns = equate_columns = reuse = reusePage = 0;
113 tmpfile_used = invert = 0;
114 warnings = 1;
115 pipeFlags = 0;
116
117 for (i_arg = 1; i_arg < argc; i_arg++) {
118 if (s_arg[i_arg].arg_type == OPTION) {
119 delete_chars(s_arg[i_arg].list[0], "_");
120 switch (match_string(s_arg[i_arg].list[0], option, N_OPTIONS, 0)) {
121 case SET_MAJOR_ORDER:
122 majorOrderFlag = 0;
123 s_arg[i_arg].n_items--;
124 if (s_arg[i_arg].n_items > 0 &&
125 (!scanItemList(&majorOrderFlag, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
126 "row", -1, NULL, 0, SDDS_ROW_MAJOR_ORDER,
127 "column", -1, NULL, 0, SDDS_COLUMN_MAJOR_ORDER, NULL)))
128 SDDS_Bomb("invalid -majorOrder syntax/values");
129 if (majorOrderFlag & SDDS_COLUMN_MAJOR_ORDER)
130 columnMajorOrder = 1;
131 else if (majorOrderFlag & SDDS_ROW_MAJOR_ORDER)
132 columnMajorOrder = 0;
133 break;
134 case SET_MATCH_COLUMN:
135 if (s_arg[i_arg].n_items != 2)
136 SDDS_Bomb("invalid -match syntax");
137 if (match_columns != 0)
138 SDDS_Bomb("only one -match option may be given");
139 match_column = tmalloc(sizeof(*match_column) * 2);
140 if ((ptr = strchr(s_arg[i_arg].list[1], '=')))
141 *ptr++ = 0;
142 else
143 ptr = s_arg[i_arg].list[1];
144 match_column[0] = s_arg[i_arg].list[1];
145 match_column[1] = ptr;
146 match_columns = 1;
147 break;
148 case SET_EQUATE_COLUMN:
149 if (s_arg[i_arg].n_items != 2)
150 SDDS_Bomb("invalid -equate syntax");
151 if (equate_columns != 0)
152 SDDS_Bomb("only one -equate option may be given");
153 equate_column = tmalloc(sizeof(*equate_column) * 2);
154 if ((ptr = strchr(s_arg[i_arg].list[1], '=')))
155 *ptr++ = 0;
156 else
157 ptr = s_arg[i_arg].list[1];
158 equate_column[0] = s_arg[i_arg].list[1];
159 equate_column[1] = ptr;
160 equate_columns = 1;
161 break;
162 case SET_REUSE:
163 if (s_arg[i_arg].n_items == 1)
164 reuse = 1;
165 else {
166 char *reuseOptions[2] = {"rows", "page"};
167 for (i = 1; i < s_arg[i_arg].n_items; i++) {
168 switch (match_string(s_arg[i_arg].list[i], reuseOptions, 2, 0)) {
169 case 0:
170 reuse = 1;
171 break;
172 case 1:
173 reusePage = 1;
174 break;
175 default:
176 SDDS_Bomb("unknown reuse keyword");
177 break;
178 }
179 }
180 }
181 break;
182 case SET_INVERT:
183 invert = 1;
184 break;
185 case SET_NOWARNINGS:
186 warnings = 0;
187 break;
188 case SET_PIPE:
189 if (!processPipeOption(s_arg[i_arg].list + 1, s_arg[i_arg].n_items - 1, &pipeFlags))
190 SDDS_Bomb("invalid -pipe syntax");
191 break;
192 default:
193 fprintf(stderr, "error: unknown switch: %s\n", s_arg[i_arg].list[0]);
194 SDDS_Bomb(NULL);
195 break;
196 }
197 } else {
198 if (input1 == NULL)
199 input1 = s_arg[i_arg].list[0];
200 else if (input2 == NULL)
201 input2 = s_arg[i_arg].list[0];
202 else if (output == NULL)
203 output = s_arg[i_arg].list[0];
204 else
205 SDDS_Bomb("too many filenames");
206 }
207 }
208
209 if (pipeFlags & USE_STDIN && input1) {
210 if (output)
211 SDDS_Bomb("too many filenames (sddsxref)");
212 output = input2;
213 input2 = input1;
214 input1 = NULL;
215 }
216 processFilenames("sddsselect", &input1, &output, pipeFlags, !warnings, &tmpfile_used);
217 if (!input2)
218 SDDS_Bomb("second input file not specified (sddsxref)");
219
220 if (equate_columns && match_columns)
221 SDDS_Bomb("only one of -equate or -match may be given");
222 if (!equate_columns && !match_columns)
223 SDDS_Bomb("one of -equate or -match must be given");
224
225 if (!SDDS_InitializeInput(&SDDS_1, input1)) {
226 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
227 exit(EXIT_FAILURE);
228 }
229 if (!SDDS_InitializeInput(&SDDS_2, input2)) {
230 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
231 exit(EXIT_FAILURE);
232 }
233
234 if (match_columns) {
235 if ((j = SDDS_GetColumnIndex(&SDDS_1, match_column[0])) < 0 ||
236 SDDS_GetColumnType(&SDDS_1, j) != SDDS_STRING) {
237 sprintf(s, "error: column %s not found or not string type in file %s", match_column[0], input1 ? input1 : "stdin");
238 SDDS_SetError(s);
239 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
240 }
241 if ((j = SDDS_GetColumnIndex(&SDDS_2, match_column[1])) < 0 ||
242 SDDS_GetColumnType(&SDDS_2, j) != SDDS_STRING) {
243 sprintf(s, "error: column %s not found or not string type in file %s", match_column[1], input2);
244 SDDS_SetError(s);
245 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
246 }
247 }
248 if (equate_columns) {
249 if ((j = SDDS_GetColumnIndex(&SDDS_1, equate_column[0])) < 0 ||
251 sprintf(s, "error: column %s not found or not numeric type in file %s", equate_column[0], input1 ? input1 : "stdin");
252 SDDS_SetError(s);
253 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
254 }
255 if ((j = SDDS_GetColumnIndex(&SDDS_2, equate_column[1])) < 0 ||
257 sprintf(s, "error: column %s not found or not numeric type in file %s", equate_column[1], input2);
258 SDDS_SetError(s);
259 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
260 }
261 }
262
263 if (output && pipeFlags & USE_STDOUT)
264 SDDS_Bomb("too many filenames with -pipe option");
265 if (!output && !(pipeFlags & USE_STDOUT)) {
266 if (warnings)
267 fprintf(stderr, "warning: existing file %s will be replaced (sddsselect)\n", input1 ? input1 : "stdin");
268 tmpfile_used = 1;
269 cp_str(&output, tmpname(NULL));
270 }
271 if (!SDDS_InitializeCopy(&SDDS_output, &SDDS_1, output, "w")) {
272 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
273 exit(EXIT_FAILURE);
274 }
275 if (columnMajorOrder != -1)
276 SDDS_output.layout.data_mode.column_major = columnMajorOrder;
277 else
278 SDDS_output.layout.data_mode.column_major = SDDS_1.layout.data_mode.column_major;
279 if (!SDDS_WriteLayout(&SDDS_output))
280 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
281
282 while ((retval1 = SDDS_ReadPage(&SDDS_1)) > 0) {
283 if (!reusePage) {
284 if ((retval2 = SDDS_ReadPage(&SDDS_2)) <= 0) {
285 if (warnings)
286 fprintf(stderr, "warning: <input2> ends before <input1>\n");
287 if (invert) {
288 /* nothing to match, so everything would normally be thrown out */
289 if (!SDDS_CopyPage(&SDDS_output, &SDDS_1) ||
290 !SDDS_WritePage(&SDDS_output))
291 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
292 continue;
293 } else
294 /* nothing to match, so everything thrown out */
295 break;
296 }
297 } else {
298 if (retval1 == 1 && (retval2 = SDDS_ReadPage(&SDDS_2)) <= 0)
299 SDDS_Bomb("<input2> has no data");
300 SDDS_SetRowFlags(&SDDS_2, 1);
301 }
302 rows1 = SDDS_CountRowsOfInterest(&SDDS_1);
303 rows2 = SDDS_CountRowsOfInterest(&SDDS_2);
304
305 if (!SDDS_StartPage(&SDDS_output, rows1)) {
306 SDDS_SetError("Problem starting output page");
307 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
308 }
309 if (!SDDS_CopyParameters(&SDDS_output, &SDDS_2) ||
310 !SDDS_CopyArrays(&SDDS_output, &SDDS_2)) {
311 SDDS_SetError("Problem copying parameter or array data from second input file");
312 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
313 }
314 if (!SDDS_CopyParameters(&SDDS_output, &SDDS_1) ||
315 !SDDS_CopyArrays(&SDDS_output, &SDDS_1)) {
316 SDDS_SetError("Problem copying parameter or array data from first input file");
317 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
318 }
319 if (rows1) {
320 if (match_columns) {
321 char **string1, **string2;
322 long matched;
323 string2 = NULL;
324 if (!(string1 = SDDS_GetColumn(&SDDS_1, match_column[0]))) {
325 fprintf(stderr, "Error: problem getting column %s from file %s\n", match_column[0], input1 ? input1 : "stdin");
326 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
327 }
328 if (rows2 && !(string2 = SDDS_GetColumn(&SDDS_2, match_column[1]))) {
329 fprintf(stderr, "Error: problem getting column %s from file %s\n", match_column[1], input2);
330 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
331 }
332 if (rows2)
333 keyGroup = MakeSortedKeyGroups(&keyGroups, SDDS_STRING, string2, rows2);
334 for (i1 = 0; i1 < rows1; i1++) {
335 if (!SDDS_CopyRowDirect(&SDDS_output, i1, &SDDS_1, i1)) {
336 sprintf(s, "Problem copying row %" PRId64 " of first data set", i1);
337 SDDS_SetError(s);
338 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
339 }
340 matched = 0;
341 if (rows2 && (i2 = FindMatchingKeyGroup(keyGroup, keyGroups, SDDS_STRING, string1 + i1, reuse)) >= 0) {
342 matched = 1;
343 }
344 if ((!matched && !invert) || (matched && invert)) {
345 if (!SDDS_AssertRowFlags(&SDDS_output, SDDS_INDEX_LIMITS, i1, i1, 0))
346 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
347 }
348 }
349 if (string1) {
350 for (i = 0; i < rows1; i++)
351 free(string1[i]);
352 free(string1);
353 string1 = NULL;
354 }
355 if (string2) {
356 for (i = 0; i < rows2; i++)
357 free(string2[i]);
358 free(string2);
359 string2 = NULL;
360 }
361 for (i = 0; i < keyGroups; i++) {
362 if (keyGroup[i]) {
363 if (keyGroup[i]->equivalent)
364 free(keyGroup[i]->equivalent);
365 free(keyGroup[i]);
366 keyGroup[i] = NULL;
367 }
368 }
369 if (keyGroups) {
370 free(keyGroup);
371 keyGroup = NULL;
372 keyGroups = 0;
373 }
374 } else if (equate_columns) {
375 double *value1, *value2;
376 long equated;
377 value2 = NULL;
378 if (!(value1 = SDDS_GetColumnInDoubles(&SDDS_1, equate_column[0]))) {
379 fprintf(stderr, "Error: problem getting column %s from file %s\n", equate_column[0], input1 ? input1 : "stdin");
380 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
381 }
382 if (rows2 && !(value2 = SDDS_GetColumnInDoubles(&SDDS_2, equate_column[1]))) {
383 fprintf(stderr, "Error: problem getting column %s from file %s\n", equate_column[1], input2);
384 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
385 }
386 if (rows2)
387 keyGroup = MakeSortedKeyGroups(&keyGroups, SDDS_DOUBLE, value2, rows2);
388 for (i1 = 0; i1 < rows1; i1++) {
389 if (!SDDS_CopyRowDirect(&SDDS_output, i1, &SDDS_1, i1)) {
390 sprintf(s, "Problem copying row %" PRId64 " of first data set", i1);
391 SDDS_SetError(s);
392 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
393 }
394 equated = 0;
395 if (rows2 &&
396 (i2 = FindMatchingKeyGroup(keyGroup, keyGroups, SDDS_DOUBLE, value1 + i1, reuse)) >= 0) {
397 equated = 1;
398 }
399 if ((!equated && !invert) || (equated && invert)) {
400 if (!SDDS_AssertRowFlags(&SDDS_output, SDDS_INDEX_LIMITS, i1, i1, 0))
401 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
402 }
403 }
404 if (value1)
405 free(value1);
406 value1 = NULL;
407 if (rows2 && value2)
408 free(value2);
409 value2 = NULL;
410 for (i = 0; i < keyGroups; i++) {
411 if (keyGroup[i]) {
412 if (keyGroup[i]->equivalent)
413 free(keyGroup[i]->equivalent);
414 free(keyGroup[i]);
415 keyGroup[i] = NULL;
416 }
417 }
418 if (keyGroups) {
419 free(keyGroup);
420 keyGroup = NULL;
421 keyGroups = 0;
422 }
423 }
424 }
425 if (!SDDS_WritePage(&SDDS_output)) {
426 SDDS_SetError("Problem writing data to output file");
427 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
428 }
429 }
430
431 if (!SDDS_Terminate(&SDDS_1) || !SDDS_Terminate(&SDDS_2) || !SDDS_Terminate(&SDDS_output)) {
432 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
433 exit(EXIT_FAILURE);
434 }
435 if (tmpfile_used && !replaceFileAndBackUp(input1, output))
436 exit(EXIT_FAILURE);
437 free_scanargs(&s_arg, argc);
438 if (match_columns)
439 free(match_column);
440 return EXIT_SUCCESS;
441}
SDDS (Self Describing Data Set) Data Types Definitions and Function Prototypes.
int32_t SDDS_CopyParameters(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source)
Definition SDDS_copy.c:286
int32_t SDDS_InitializeCopy(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source, char *filename, char *filemode)
Definition SDDS_copy.c:40
int32_t SDDS_CopyRowDirect(SDDS_DATASET *SDDS_target, int64_t target_row, SDDS_DATASET *SDDS_source, int64_t source_row)
Definition SDDS_copy.c:834
int32_t SDDS_CopyPage(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source)
Definition SDDS_copy.c:578
int32_t SDDS_CopyArrays(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source)
Definition SDDS_copy.c:334
int32_t SDDS_StartPage(SDDS_DATASET *SDDS_dataset, int64_t expected_n_rows)
int32_t SDDS_AssertRowFlags(SDDS_DATASET *SDDS_dataset, uint32_t mode,...)
Sets acceptance flags for rows based on specified criteria.
void * SDDS_GetColumn(SDDS_DATASET *SDDS_dataset, char *column_name)
Retrieves a copy of the data for a specified column, including only rows marked as "of interest".
int64_t SDDS_CountRowsOfInterest(SDDS_DATASET *SDDS_dataset)
Counts the number of rows marked as "of interest" in the current data table.
int32_t SDDS_SetRowFlags(SDDS_DATASET *SDDS_dataset, int32_t row_flag_value)
Sets the acceptance flags for all rows in the current data table of a data set.
double * SDDS_GetColumnInDoubles(SDDS_DATASET *SDDS_dataset, char *column_name)
Retrieves the data of a specified numerical column as an array of doubles, considering only rows mark...
int32_t SDDS_InitializeInput(SDDS_DATASET *SDDS_dataset, char *filename)
Definition SDDS_input.c:49
int32_t SDDS_Terminate(SDDS_DATASET *SDDS_dataset)
int32_t SDDS_ReadPage(SDDS_DATASET *SDDS_dataset)
int32_t SDDS_WritePage(SDDS_DATASET *SDDS_dataset)
Writes the current data table to the output file.
int32_t SDDS_WriteLayout(SDDS_DATASET *SDDS_dataset)
Writes the SDDS layout header to the output file.
void SDDS_SetError(char *error_text)
Records an error message in the SDDS error stack.
Definition SDDS_utils.c:379
int32_t SDDS_GetColumnIndex(SDDS_DATASET *SDDS_dataset, char *name)
Retrieves the index of a named column in the SDDS dataset.
void SDDS_PrintErrors(FILE *fp, int32_t mode)
Prints recorded error messages to a specified file stream.
Definition SDDS_utils.c:432
void SDDS_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
Definition SDDS_utils.c:288
int32_t SDDS_GetColumnType(SDDS_DATASET *SDDS_dataset, int32_t index)
Retrieves the data type of a column in the SDDS dataset by its index.
void SDDS_Bomb(char *message)
Terminates the program after printing an error message and recorded errors.
Definition SDDS_utils.c:342
#define SDDS_STRING
Identifier for the string data type.
Definition SDDStypes.h:85
#define SDDS_DOUBLE
Identifier for the double data type.
Definition SDDStypes.h:37
#define SDDS_NUMERIC_TYPE(type)
Checks if the given type identifier corresponds to any numeric type.
Definition SDDStypes.h:138
void * tmalloc(uint64_t size_of_block)
Allocates a memory block of the specified size with zero initialization.
Definition array.c:59
void bomb(char *error, char *usage)
Reports error messages to the terminal and aborts the program.
Definition bomb.c:26
char * cp_str(char **s, char *t)
Copies a string, allocating memory for storage.
Definition cp_str.c:28
char * delete_chars(char *s, char *t)
Removes all occurrences of characters found in string t from string s.
long match_string(char *string, char **option, long n_options, long mode)
Matches a given string against an array of option strings based on specified modes.
long replaceFileAndBackUp(char *file, char *replacement)
Replaces a file with a replacement file and creates a backup of the original.
Definition replacefile.c:75
int scanargs(SCANNED_ARG **scanned, int argc, char **argv)
Definition scanargs.c:36
long processPipeOption(char **item, long items, unsigned long *flags)
Definition scanargs.c:356
void processFilenames(char *programName, char **input, char **output, unsigned long pipeFlags, long noWarnings, long *tmpOutputUsed)
Definition scanargs.c:390
void free_scanargs(SCANNED_ARG **scanned, int argc)
Definition scanargs.c:584
long scanItemList(unsigned long *flags, char **item, long *items, unsigned long mode,...)
Scans a list of items and assigns values based on provided keywords and types.
KEYED_EQUIVALENT ** MakeSortedKeyGroups(long *keyGroups, long keyType, void *data, long points)
Create sorted key groups from data.
long FindMatchingKeyGroup(KEYED_EQUIVALENT **keyGroup, long keyGroups, long keyType, void *searchKeyData, long reuse)
Find a matching key group for a search key.
char * tmpname(char *s)
Supplies a unique temporary filename.
Definition tmpname.c:34