SDDS ToolKit Programs and Libraries for C and Python
Loading...
Searching...
No Matches
sddsselect.c File Reference

Detailed Description

Creates an SDDS data set from another data set based on matching data in a third data set.

This program selects rows from <input1> that have (or do not have, if inverted) a matching entry in <input2>, based on specified matching or equating columns. The output is written to <output>, or <input1> is replaced if <output> is not provided. It supports various options to customize the matching behavior, data processing, and output format.

Usage

sddsselect [<input1>] <input2> [<output>]
[-pipe[=input][,output]]
[-match=<column-name>[=<column-name>]]
[-equate=<column-name>[=<column-name>]]
[-hashLookup]
[-invert]
[-reuse[=rows][,page]]
[-majorOrder=row|column]
[-nowarnings]

Options

Optional Description
-pipe Use pipe for input and/or output.
-match Specify columns to match between <input1> and <input2>.
-equate Specify columns to equate between <input1> and <input2>.
-hashLookup Use a hash table for matching instead of sorted key lists.
-invert Invert the selection to keep non-matching rows.
-reuse Allow reusing rows or specify page reuse.
-majorOrder Set the output file to row or column major order.
-nowarnings Suppress warning messages.

Incompatibilities

  • Only one of -match or -equate may be specified.
License
This file is distributed under the terms of the Software License Agreement found in the file LICENSE included with this distribution.
Author
M. Borland, C. Saunders, R. Soliday, H. Shang

Definition in file sddsselect.c.

#include "mdb.h"
#include "SDDS.h"
#include "SDDSaps.h"
#include "scan.h"

Go to the source code of this file.

Functions

int main (int argc, char **argv)
 

Function Documentation

◆ main()

int main ( int argc,
char ** argv )

Definition at line 105 of file sddsselect.c.

105 {
106 SDDS_DATASET SDDS_1, SDDS_2, SDDS_output;
107 long i, j, i_arg, reuse, reusePage;
108 int64_t rows1, rows2, i1, i2;
109 SCANNED_ARG *s_arg;
110 char s[200], *ptr;
111 char **match_column, **equate_column;
112 long match_columns, equate_columns;
113 char *input1, *input2, *output;
114 long tmpfile_used, retval1, retval2;
115 long warnings, invert;
116 unsigned long pipeFlags, majorOrderFlag;
117 KEYED_EQUIVALENT **keyGroup = NULL;
118 long keyGroups = 0;
119 short columnMajorOrder = -1;
120 long useHashLookup = 0;
121
123 argc = scanargs(&s_arg, argc, argv);
124 if (argc < 3)
125 bomb(NULL, USAGE);
126
127 input1 = input2 = output = NULL;
128 match_column = equate_column = NULL;
129 match_columns = equate_columns = reuse = reusePage = 0;
130 tmpfile_used = invert = 0;
131 warnings = 1;
132 pipeFlags = 0;
133
134 for (i_arg = 1; i_arg < argc; i_arg++) {
135 if (s_arg[i_arg].arg_type == OPTION) {
136 delete_chars(s_arg[i_arg].list[0], "_");
137 switch (match_string(s_arg[i_arg].list[0], option, N_OPTIONS, 0)) {
138 case SET_MAJOR_ORDER:
139 majorOrderFlag = 0;
140 s_arg[i_arg].n_items--;
141 if (s_arg[i_arg].n_items > 0 &&
142 (!scanItemList(&majorOrderFlag, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
143 "row", -1, NULL, 0, SDDS_ROW_MAJOR_ORDER,
144 "column", -1, NULL, 0, SDDS_COLUMN_MAJOR_ORDER, NULL)))
145 SDDS_Bomb("invalid -majorOrder syntax/values");
146 if (majorOrderFlag & SDDS_COLUMN_MAJOR_ORDER)
147 columnMajorOrder = 1;
148 else if (majorOrderFlag & SDDS_ROW_MAJOR_ORDER)
149 columnMajorOrder = 0;
150 break;
151 case SET_MATCH_COLUMN:
152 if (s_arg[i_arg].n_items != 2)
153 SDDS_Bomb("invalid -match syntax");
154 if (match_columns != 0)
155 SDDS_Bomb("only one -match option may be given");
156 match_column = tmalloc(sizeof(*match_column) * 2);
157 if ((ptr = strchr(s_arg[i_arg].list[1], '=')))
158 *ptr++ = 0;
159 else
160 ptr = s_arg[i_arg].list[1];
161 match_column[0] = s_arg[i_arg].list[1];
162 match_column[1] = ptr;
163 match_columns = 1;
164 break;
165 case SET_EQUATE_COLUMN:
166 if (s_arg[i_arg].n_items != 2)
167 SDDS_Bomb("invalid -equate syntax");
168 if (equate_columns != 0)
169 SDDS_Bomb("only one -equate option may be given");
170 equate_column = tmalloc(sizeof(*equate_column) * 2);
171 if ((ptr = strchr(s_arg[i_arg].list[1], '=')))
172 *ptr++ = 0;
173 else
174 ptr = s_arg[i_arg].list[1];
175 equate_column[0] = s_arg[i_arg].list[1];
176 equate_column[1] = ptr;
177 equate_columns = 1;
178 break;
179 case SET_REUSE:
180 if (s_arg[i_arg].n_items == 1)
181 reuse = 1;
182 else {
183 char *reuseOptions[2] = {"rows", "page"};
184 for (i = 1; i < s_arg[i_arg].n_items; i++) {
185 switch (match_string(s_arg[i_arg].list[i], reuseOptions, 2, 0)) {
186 case 0:
187 reuse = 1;
188 break;
189 case 1:
190 reusePage = 1;
191 break;
192 default:
193 SDDS_Bomb("unknown reuse keyword");
194 break;
195 }
196 }
197 }
198 break;
199 case SET_INVERT:
200 invert = 1;
201 break;
202 case SET_NOWARNINGS:
203 warnings = 0;
204 break;
205 case SET_PIPE:
206 if (!processPipeOption(s_arg[i_arg].list + 1, s_arg[i_arg].n_items - 1, &pipeFlags))
207 SDDS_Bomb("invalid -pipe syntax");
208 break;
209 case SET_HASH_LOOKUP:
210 useHashLookup = 1;
211 break;
212 default:
213 fprintf(stderr, "error: unknown switch: %s\n", s_arg[i_arg].list[0]);
214 SDDS_Bomb(NULL);
215 break;
216 }
217 } else {
218 if (input1 == NULL)
219 input1 = s_arg[i_arg].list[0];
220 else if (input2 == NULL)
221 input2 = s_arg[i_arg].list[0];
222 else if (output == NULL)
223 output = s_arg[i_arg].list[0];
224 else
225 SDDS_Bomb("too many filenames");
226 }
227 }
228
229 if (pipeFlags & USE_STDIN && input1) {
230 if (output)
231 SDDS_Bomb("too many filenames (sddsxref)");
232 output = input2;
233 input2 = input1;
234 input1 = NULL;
235 }
236 processFilenames("sddsselect", &input1, &output, pipeFlags, !warnings, &tmpfile_used);
237 if (!input2)
238 SDDS_Bomb("second input file not specified (sddsxref)");
239
240 if (equate_columns && match_columns)
241 SDDS_Bomb("only one of -equate or -match may be given");
242 if (!equate_columns && !match_columns)
243 SDDS_Bomb("one of -equate or -match must be given");
244
245 if (!SDDS_InitializeInput(&SDDS_1, input1)) {
246 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
247 exit(EXIT_FAILURE);
248 }
249 if (!SDDS_InitializeInput(&SDDS_2, input2)) {
250 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
251 exit(EXIT_FAILURE);
252 }
253
254 if (match_columns) {
255 if ((j = SDDS_GetColumnIndex(&SDDS_1, match_column[0])) < 0 ||
256 SDDS_GetColumnType(&SDDS_1, j) != SDDS_STRING) {
257 sprintf(s, "error: column %s not found or not string type in file %s", match_column[0], input1 ? input1 : "stdin");
258 SDDS_SetError(s);
259 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
260 }
261 if ((j = SDDS_GetColumnIndex(&SDDS_2, match_column[1])) < 0 ||
262 SDDS_GetColumnType(&SDDS_2, j) != SDDS_STRING) {
263 sprintf(s, "error: column %s not found or not string type in file %s", match_column[1], input2);
264 SDDS_SetError(s);
265 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
266 }
267 }
268 if (equate_columns) {
269 if ((j = SDDS_GetColumnIndex(&SDDS_1, equate_column[0])) < 0 ||
271 sprintf(s, "error: column %s not found or not numeric type in file %s", equate_column[0], input1 ? input1 : "stdin");
272 SDDS_SetError(s);
273 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
274 }
275 if ((j = SDDS_GetColumnIndex(&SDDS_2, equate_column[1])) < 0 ||
277 sprintf(s, "error: column %s not found or not numeric type in file %s", equate_column[1], input2);
278 SDDS_SetError(s);
279 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
280 }
281 }
282
283 if (output && pipeFlags & USE_STDOUT)
284 SDDS_Bomb("too many filenames with -pipe option");
285 if (!output && !(pipeFlags & USE_STDOUT)) {
286 if (warnings)
287 fprintf(stderr, "warning: existing file %s will be replaced (sddsselect)\n", input1 ? input1 : "stdin");
288 tmpfile_used = 1;
289 cp_str(&output, tmpname(NULL));
290 }
291 if (!SDDS_InitializeCopy(&SDDS_output, &SDDS_1, output, "w")) {
292 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
293 exit(EXIT_FAILURE);
294 }
295 if (columnMajorOrder != -1)
296 SDDS_output.layout.data_mode.column_major = columnMajorOrder;
297 else
298 SDDS_output.layout.data_mode.column_major = SDDS_1.layout.data_mode.column_major;
299 if (!SDDS_WriteLayout(&SDDS_output))
300 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
301
302 while ((retval1 = SDDS_ReadPage(&SDDS_1)) > 0) {
303 if (!reusePage) {
304 if ((retval2 = SDDS_ReadPage(&SDDS_2)) <= 0) {
305 if (warnings)
306 fprintf(stderr, "warning: <input2> ends before <input1>\n");
307 if (invert) {
308 /* nothing to match, so everything would normally be thrown out */
309 if (!SDDS_CopyPage(&SDDS_output, &SDDS_1) ||
310 !SDDS_WritePage(&SDDS_output))
311 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
312 continue;
313 } else
314 /* nothing to match, so everything thrown out */
315 break;
316 }
317 } else {
318 if (retval1 == 1 && (retval2 = SDDS_ReadPage(&SDDS_2)) <= 0)
319 SDDS_Bomb("<input2> has no data");
320 SDDS_SetRowFlags(&SDDS_2, 1);
321 }
322 rows1 = SDDS_CountRowsOfInterest(&SDDS_1);
323 rows2 = SDDS_CountRowsOfInterest(&SDDS_2);
324
325 if (!SDDS_StartPage(&SDDS_output, rows1)) {
326 SDDS_SetError("Problem starting output page");
327 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
328 }
329 if (!SDDS_CopyParameters(&SDDS_output, &SDDS_2) ||
330 !SDDS_CopyArrays(&SDDS_output, &SDDS_2)) {
331 SDDS_SetError("Problem copying parameter or array data from second input file");
332 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
333 }
334 if (!SDDS_CopyParameters(&SDDS_output, &SDDS_1) ||
335 !SDDS_CopyArrays(&SDDS_output, &SDDS_1)) {
336 SDDS_SetError("Problem copying parameter or array data from first input file");
337 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
338 }
339 if (rows1) {
340 if (match_columns) {
341 char **string1, **string2;
342 long matched;
343 string2 = NULL;
344 if (!(string1 = SDDS_GetColumn(&SDDS_1, match_column[0]))) {
345 fprintf(stderr, "Error: problem getting column %s from file %s\n", match_column[0], input1 ? input1 : "stdin");
346 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
347 }
348 if (rows2 && !(string2 = SDDS_GetColumn(&SDDS_2, match_column[1]))) {
349 fprintf(stderr, "Error: problem getting column %s from file %s\n", match_column[1], input2);
350 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
351 }
352 StrHash *strHash = NULL;
353 if (rows2) {
354 if (useHashLookup)
355 strHash = SDDS_BuildStrHash(string2, rows2);
356 else
357 keyGroup = MakeSortedKeyGroups(&keyGroups, SDDS_STRING, string2, rows2);
358 }
359 for (i1 = 0; i1 < rows1; i1++) {
360 if (!SDDS_CopyRowDirect(&SDDS_output, i1, &SDDS_1, i1)) {
361 sprintf(s, "Problem copying row %" PRId64 " of first data set", i1);
362 SDDS_SetError(s);
363 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
364 }
365 matched = 0;
366 if (rows2) {
367 if (useHashLookup) {
368 if (SDDS_LookupStr(strHash, string1[i1], reuse) >= 0)
369 matched = 1;
370 } else {
371 if ((i2 = FindMatchingKeyGroup(keyGroup, keyGroups, SDDS_STRING, string1 + i1, reuse)) >= 0)
372 matched = 1;
373 }
374 }
375 if ((!matched && !invert) || (matched && invert)) {
376 if (!SDDS_AssertRowFlags(&SDDS_output, SDDS_INDEX_LIMITS, i1, i1, 0))
377 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
378 }
379 }
380 if (string1) {
381 for (i = 0; i < rows1; i++)
382 free(string1[i]);
383 free(string1);
384 string1 = NULL;
385 }
386 if (string2) {
387 for (i = 0; i < rows2; i++)
388 free(string2[i]);
389 free(string2);
390 string2 = NULL;
391 }
392 if (useHashLookup && strHash) {
393 SDDS_FreeStrHash(strHash);
394 strHash = NULL;
395 }
396 for (i = 0; i < keyGroups; i++) {
397 if (keyGroup[i]) {
398 if (keyGroup[i]->equivalent)
399 free(keyGroup[i]->equivalent);
400 free(keyGroup[i]);
401 keyGroup[i] = NULL;
402 }
403 }
404 if (keyGroups) {
405 free(keyGroup);
406 keyGroup = NULL;
407 keyGroups = 0;
408 }
409 } else if (equate_columns) {
410 double *value1, *value2;
411 long equated;
412 value2 = NULL;
413 if (!(value1 = SDDS_GetColumnInDoubles(&SDDS_1, equate_column[0]))) {
414 fprintf(stderr, "Error: problem getting column %s from file %s\n", equate_column[0], input1 ? input1 : "stdin");
415 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
416 }
417 if (rows2 && !(value2 = SDDS_GetColumnInDoubles(&SDDS_2, equate_column[1]))) {
418 fprintf(stderr, "Error: problem getting column %s from file %s\n", equate_column[1], input2);
419 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
420 }
421 NumHash *numHash = NULL;
422 if (rows2) {
423 if (useHashLookup)
424 numHash = SDDS_BuildNumHash(value2, rows2);
425 else
426 keyGroup = MakeSortedKeyGroups(&keyGroups, SDDS_DOUBLE, value2, rows2);
427 }
428 for (i1 = 0; i1 < rows1; i1++) {
429 if (!SDDS_CopyRowDirect(&SDDS_output, i1, &SDDS_1, i1)) {
430 sprintf(s, "Problem copying row %" PRId64 " of first data set", i1);
431 SDDS_SetError(s);
432 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
433 }
434 equated = 0;
435 if (rows2) {
436 if (useHashLookup) {
437 if (SDDS_LookupNum(numHash, value1[i1], reuse) >= 0)
438 equated = 1;
439 } else {
440 if ((i2 = FindMatchingKeyGroup(keyGroup, keyGroups, SDDS_DOUBLE, value1 + i1, reuse)) >= 0)
441 equated = 1;
442 }
443 }
444 if ((!equated && !invert) || (equated && invert)) {
445 if (!SDDS_AssertRowFlags(&SDDS_output, SDDS_INDEX_LIMITS, i1, i1, 0))
446 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
447 }
448 }
449 if (value1)
450 free(value1);
451 value1 = NULL;
452 if (rows2 && value2)
453 free(value2);
454 value2 = NULL;
455 if (useHashLookup && numHash) {
456 SDDS_FreeNumHash(numHash);
457 numHash = NULL;
458 }
459 for (i = 0; i < keyGroups; i++) {
460 if (keyGroup[i]) {
461 if (keyGroup[i]->equivalent)
462 free(keyGroup[i]->equivalent);
463 free(keyGroup[i]);
464 keyGroup[i] = NULL;
465 }
466 }
467 if (keyGroups) {
468 free(keyGroup);
469 keyGroup = NULL;
470 keyGroups = 0;
471 }
472 }
473 }
474 if (!SDDS_WritePage(&SDDS_output)) {
475 SDDS_SetError("Problem writing data to output file");
476 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
477 }
478 }
479
480 if (!SDDS_Terminate(&SDDS_1) || !SDDS_Terminate(&SDDS_2) || !SDDS_Terminate(&SDDS_output)) {
481 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
482 exit(EXIT_FAILURE);
483 }
484 if (tmpfile_used && !replaceFileAndBackUp(input1, output))
485 exit(EXIT_FAILURE);
486 free_scanargs(&s_arg, argc);
487 if (match_columns)
488 free(match_column);
489 return EXIT_SUCCESS;
490}
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:50
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:421
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:474
void SDDS_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
Definition SDDS_utils.c:318
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:380
#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:65
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:78
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:357
void processFilenames(char *programName, char **input, char **output, unsigned long pipeFlags, long noWarnings, long *tmpOutputUsed)
Definition scanargs.c:391
void free_scanargs(SCANNED_ARG **scanned, int argc)
Definition scanargs.c:588
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:37