67#include "match_string.h"
84 CLO_NO_OLDCOLUMNNAMES,
89char *commandline_option[N_OPTIONS] = {
104static char *OLD_STRING_COLUMN_NAMES =
"OldStringColumnNames";
107 "sddstranspose [<inputfile>] [<outputfile>]\n"
108 " [-pipe=[input][,output]]\n"
109 " [-oldColumnNames=<string>] \n"
110 " [-root=<string>]\n"
111 " [-digits=<integer>]\n"
112 " [-newColumnNames=<column>}] \n"
113 " [-matchColumn=<string>[,<string>,...]]\n"
115 " [-noOldColumnNames] \n"
116 " [-symbol=<string>] \n"
119 " [-majorOrder=row|column]\n"
121 " -pipe=[input][,output] Reads input from and/or writes output to a pipe.\n"
122 " -oldColumnNames=<string> Specifies the name for the output file string column created for the input file column names.\n"
123 " -root=<string> Uses the specified string to generate column names of the output file.\n"
124 " Default column names are the first string column in <inputfile>.\n"
125 " If no string column exists, column names are formed with the root \"Column\".\n"
126 " -digits=<integer> Sets the minimum number of digits appended to the root part of the column names.\n"
128 " -newColumnNames=<column> Uses the specified column as the source for new column names.\n"
129 " -symbol=<string> Uses the specified string for the symbol field in all column definitions.\n"
130 " -ascii Outputs the file in ASCII format. Default is binary.\n"
131 " -matchColumn=<string>[,<string>,...] Only transposes the columns that match the specified names.\n"
132 " -indexColumn Adds an index column to the output file.\n"
133 " -noOldColumnNames Does not create a new column for old column names.\n"
134 " -majorOrder=row|column Specifies the output file's major order (row-major or column-major).\n"
135 " -verbose Prints incidental information to stderr.\n\n"
136 "Link date: " __DATE__
" " __TIME__
", SVN revision: " SVN_VERSION
"\n";
138char **TokenizeString(
char *source,
long n_items);
139char *JoinStrings(
char **source,
long n_items,
long buflen_increment);
141int main(
int argc,
char **argv) {
145 char *inputfile, *outputfile;
146 char **inputColumnName, **inputStringColumnName, **inputDoubleColumnName;
147 char **outputStringColumnName, **outputDoubleColumnName, **matchColumn = NULL;
148 long inputDoubleColumns, inputStringColumns, indexColumn = 0, noOldColumnNamesColumn = 0;
150 int32_t matchColumns = 0;
151 long outputRows, outputDoubleColumns, outputStringColumns;
152 char **inputParameterName;
153 int32_t inputParameters;
154 int32_t inputColumns;
155 char *inputDescription, *inputContents;
156 char *outputDescription;
159 char **columnOfStrings;
161#define BUFFER_SIZE_INCREMENT 16384
163 long OldStringColumnsDefined;
164 char *inputStringRows, *outputStringRows;
165 char **stringArray, *stringParameter;
171 void *parameterPointer;
173 unsigned long pipeFlags, majorOrderFlag;
174 long tmpfile_used, noWarnings;
175 long ipage = 0, columnType;
176 char *oldColumnNames, *newColumnNamesColumn;
177 short columnMajorOrder = -1;
179 inputColumnName = outputStringColumnName = outputDoubleColumnName = inputParameterName = NULL;
180 outputRows = outputDoubleColumns = outputStringColumns = OldStringColumnsDefined = 0;
184 argc =
scanargs(&s_arg, argc, argv);
188 inputfile = outputfile = NULL;
190 Symbol = Root = NULL;
196 oldColumnNames = NULL;
197 newColumnNamesColumn = NULL;
199 for (i_arg = 1; i_arg < argc; i_arg++) {
200 if (s_arg[i_arg].arg_type == OPTION) {
201 switch (
match_string(s_arg[i_arg].list[0], commandline_option, N_OPTIONS, UNIQUE_MATCH)) {
202 case CLO_MAJOR_ORDER:
204 s_arg[i_arg].n_items--;
205 if (s_arg[i_arg].n_items > 0 &&
206 (!
scanItemList(&majorOrderFlag, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
207 "row", -1, NULL, 0, SDDS_ROW_MAJOR_ORDER,
208 "column", -1, NULL, 0, SDDS_COLUMN_MAJOR_ORDER, NULL)))
209 SDDS_Bomb(
"invalid -majorOrder syntax/values");
210 if (majorOrderFlag & SDDS_COLUMN_MAJOR_ORDER)
211 columnMajorOrder = 1;
212 else if (majorOrderFlag & SDDS_ROW_MAJOR_ORDER)
213 columnMajorOrder = 0;
215 case CLO_MATCH_COLUMN:
216 matchColumns = s_arg[i_arg].n_items - 1;
217 matchColumn = s_arg[i_arg].list + 1;
219 case CLO_INDEX_COLUMN:
222 case CLO_NO_OLDCOLUMNNAMES:
223 noOldColumnNamesColumn = 1;
232 if (!(
get_long(&digits, s_arg[i_arg].list[1])))
233 bomb(
"No integer provided for option -digits", USAGE);
236 if (!(Root = s_arg[i_arg].list[1]))
237 SDDS_Bomb(
"No root string provided with -root option");
240 if (!(Symbol = s_arg[i_arg].list[1]))
241 SDDS_Bomb(
"No symbol string provided with -symbol option");
244 if (!
processPipeOption(s_arg[i_arg].list + 1, s_arg[i_arg].n_items - 1, &pipeFlags))
247 case CLO_OLDCOLUMNNAMES:
248 if (!(oldColumnNames = s_arg[i_arg].list[1]))
249 SDDS_Bomb(
"No string provided for -oldColumnNames option");
251 case CLO_NEWCOLUMNNAMES:
252 if (s_arg[i_arg].n_items != 2 ||
SDDS_StringIsBlank(newColumnNamesColumn = s_arg[i_arg].list[1]))
253 SDDS_Bomb(
"Invalid syntax or value for -newColumnNames option");
256 bomb(
"Unrecognized option provided", USAGE);
260 inputfile = s_arg[i_arg].list[0];
261 else if (!outputfile)
262 outputfile = s_arg[i_arg].list[0];
264 bomb(
"Too many filenames provided", USAGE);
268 processFilenames(
"sddstranspose", &inputfile, &outputfile, pipeFlags, noWarnings, &tmpfile_used);
269 if (newColumnNamesColumn && Root)
270 SDDS_Bomb(
"-root and -newColumnNames options are incompatible");
278 inputColumnName =
getMatchingSDDSNames(&inputPage, matchColumn, matchColumns, &inputColumns, SDDS_MATCH_COLUMN);
284 inputDoubleColumns = 0;
285 inputStringColumns = 0;
286 inputDoubleColumnName = (
char **)malloc(inputColumns *
sizeof(
char *));
287 inputStringColumnName = (
char **)malloc(inputColumns *
sizeof(
char *));
293 while (0 < SDDS_ReadTable(&inputPage)) {
296 fprintf(stderr,
"Working on page %ld\n", ipage);
303 for (i = 0; i < inputColumns; i++) {
305 inputDoubleColumnName[inputDoubleColumns] = inputColumnName[i];
306 inputDoubleColumns++;
309 for (i = 0; i < inputPage.layout.n_columns; i++) {
310 if (inputPage.layout.column_definition[i].type ==
SDDS_STRING) {
311 inputStringColumnName[inputStringColumns] = inputPage.layout.column_definition[i].name;
312 inputStringColumns++;
320 SDDS_Bomb(
"Datasets have differing number of rows. Processing stopped before reaching end of input file.");
324 if (inputRows > INT32_MAX) {
329 fprintf(stderr,
"Row flags set\n");
331 if (inputDoubleColumns == 0)
332 SDDS_Bomb(
"No numerical columns in file.");
334 if ((ipage == 1) && verbose) {
335 fprintf(stderr,
"Number of numerical columns: %ld.\n", inputDoubleColumns);
336 fprintf(stderr,
"Number of string columns: %ld.\n", inputStringColumns);
337 fprintf(stderr,
"Number of rows: %" PRId64
".\n", inputRows);
343 if (inputDoubleColumns) {
345 m_alloc(&RInv, inputRows, inputDoubleColumns);
346 m_alloc(&R, inputDoubleColumns, inputRows);
348 for (col = 0; col < inputDoubleColumns; col++) {
354 m_show(R,
"%9.6le ",
"Transpose of input matrix:\n", stdout);
364 OldStringColumnsDefined = 0;
366 case SDDS_CHECK_OKAY:
367 OldStringColumnsDefined = 1;
369 case SDDS_CHECK_NONEXISTENT:
371 case SDDS_CHECK_WRONGTYPE:
372 case SDDS_CHECK_WRONGUNITS:
373 fprintf(stderr,
"Error: Parameter OldStringColumns has incorrect type or units.\n");
378 if (OldStringColumnsDefined) {
384 fprintf(stderr,
"Parameter OldStringColumns: %s.\n", inputStringRows);
387 outputStringColumnName = (
char **)malloc(
sizeof(
char *));
388 outputStringColumns = 0;
389 buffer_size = BUFFER_SIZE_INCREMENT;
390 buffer = (
char *)malloc(
sizeof(
char) * buffer_size);
391 while (0 <= (token_length =
SDDS_GetToken(inputStringRows, buffer, BUFFER_SIZE_INCREMENT))) {
393 SDDS_Bomb(
"A null string was detected in parameter OldStringColumns.");
395 if (!
SDDS_CopyString(&outputStringColumnName[outputStringColumns], buffer))
399 fprintf(stderr,
"Output string column: %s\n", outputStringColumnName[outputStringColumns]);
401 outputStringColumns++;
410 outputRows = inputDoubleColumns;
411 outputDoubleColumns = inputRows;
413 if (inputDescription) {
414 outputDescription = (
char *)malloc(
sizeof(
char) * (strlen(
"Transpose of ") + strlen(inputDescription) + 1));
415 strcpy(outputDescription,
"Transpose of ");
416 strcat(outputDescription, inputDescription);
417 if (!
SDDS_InitializeOutput(&outputPage, ascii ? SDDS_ASCII : SDDS_BINARY, 1, outputDescription, inputContents, outputfile))
419 free(outputDescription);
421 if (!
SDDS_InitializeOutput(&outputPage, ascii ? SDDS_ASCII : SDDS_BINARY, 1, NULL, NULL, outputfile))
427 if (columnMajorOrder != -1)
428 outputPage.layout.data_mode.column_major = columnMajorOrder;
430 outputPage.layout.data_mode.column_major = inputPage.layout.data_mode.column_major;
435 if (!Root && inputStringColumns) {
437 if (!newColumnNamesColumn)
439 outputDoubleColumnName = (
char **)
SDDS_GetColumn(&inputPage, inputStringColumnName[0]);
443 SDDS_Bomb(
"Column specified with -newColumnNames does not exist in input file.");
444 outputDoubleColumnName = (
char **)
SDDS_GetColumn(&inputPage, newColumnNamesColumn);
447 for (i = 1; i < inputRows; i++) {
448 if (
match_string(outputDoubleColumnName[i - 1], outputDoubleColumnName + i, inputRows - i, EXACT_MATCH) >= 0) {
449 fprintf(stderr,
"Error: Duplicate column name '%s' found in input file string column '%s'. Cannot be used as output column names.\n",
450 outputDoubleColumnName[i - 1], newColumnNamesColumn ? newColumnNamesColumn : inputStringColumnName[0]);
456 outputDoubleColumnName = (
char **)malloc(outputDoubleColumns *
sizeof(
char *));
457 digits = MAX(digits, (
long)(log10(inputRows) + 1));
459 Root = (
char *)malloc(
sizeof(
char) * (strlen(
"Column") + 1));
460 strcpy(Root,
"Column");
462 if (outputDoubleColumns != 1) {
463 for (i = 0; i < outputDoubleColumns; i++) {
464 outputDoubleColumnName[i] = (
char *)malloc(
sizeof(
char) * (strlen(Root) + digits + 1));
465 sprintf(format,
"%s%%0%ldld", Root, digits);
466 sprintf(outputDoubleColumnName[i], format, i);
469 outputDoubleColumnName[0] = (
char *)malloc(
sizeof(
char) * (strlen(Root) + 1));
470 strcpy(outputDoubleColumnName[0], Root);
477 if (OldStringColumnsDefined) {
482 if (!noOldColumnNamesColumn) {
483 outputStringColumns = 1;
484 outputStringColumnName = (
char **)malloc(
sizeof(
char *));
485 if (oldColumnNames) {
487 outputStringColumnName[0] = oldColumnNames;
489 outputStringColumnName[0] = (
char *)malloc(
sizeof(
char) * (strlen(
"OldColumnNames") + 1));
490 strcpy(outputStringColumnName[0],
"OldColumnNames");
503 for (i = 0; i < outputDoubleColumns; i++) {
517 if (inputStringColumns > 1) {
520 for (i = 0; i < inputStringColumns; i++) {
529 if (inputParameters) {
530 for (i = 0; i < inputParameters; i++) {
531 if ((0 >
match_string(inputParameterName[i], outputStringColumnName, outputStringColumns, 0) &&
532 strcasecmp(inputParameterName[i], OLD_STRING_COLUMN_NAMES))) {
546 case SDDS_CHECK_NONEXISTENT:
559 fprintf(stderr,
"Table layout defined\n");
562 if (!SDDS_StartTable(&outputPage, outputRows))
565 if (!
SDDS_SetParameters(&outputPage, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE,
"InputFile", inputfile ? inputfile :
"pipe", NULL))
573 if (inputStringColumns > 1) {
574 for (i = 0; i < inputStringColumns; i++) {
575 columnOfStrings = (
char **)
SDDS_GetColumn(&inputPage, inputStringColumnName[i]);
576 stringParameter = JoinStrings(columnOfStrings, inputRows, BUFFER_SIZE_INCREMENT);
577 if (!
SDDS_SetParameters(&outputPage, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE, inputStringColumnName[i], stringParameter, NULL))
579 free(columnOfStrings);
580 free(stringParameter);
582 outputStringRows = JoinStrings(inputStringColumnName, inputStringColumns, BUFFER_SIZE_INCREMENT);
583 if (!
SDDS_SetParameters(&outputPage, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE, OLD_STRING_COLUMN_NAMES, outputStringRows, NULL))
588 fprintf(stderr,
"String parameters assigned\n");
591 if (inputParameters) {
592 for (i = 0; i < inputParameters; i++) {
593 if ((0 >
match_string(inputParameterName[i], outputStringColumnName, outputStringColumns, 0) &&
594 strcasecmp(inputParameterName[i], OLD_STRING_COLUMN_NAMES))) {
595 parameterPointer = (
void *)
SDDS_GetParameter(&inputPage, inputParameterName[i], NULL);
596 if (!
SDDS_SetParameters(&outputPage, SDDS_SET_BY_NAME | SDDS_PASS_BY_REFERENCE, inputParameterName[i], parameterPointer, NULL))
598 free(parameterPointer);
604 fprintf(stderr,
"Input parameters assigned\n");
615 if (OldStringColumnsDefined) {
616 for (i = 0; i < outputStringColumns; i++) {
619 stringArray = TokenizeString(stringParameter, outputRows);
620 if (!
SDDS_SetColumn(&outputPage, SDDS_SET_BY_NAME | SDDS_PASS_BY_REFERENCE, stringArray, outputRows, outputStringColumnName[i]))
625 if (!noOldColumnNamesColumn &&
626 !
SDDS_SetColumn(&outputPage, SDDS_SET_BY_NAME | SDDS_PASS_BY_REFERENCE, inputDoubleColumnName, outputRows, outputStringColumnName[0]))
631 fprintf(stderr,
"String data columns assigned\n");
637 for (i = 0; i < outputDoubleColumns; i++)
638 if (!
SDDS_SetColumn(&outputPage, SDDS_SET_BY_NAME | SDDS_PASS_BY_REFERENCE, RInv->a[i], outputRows, outputDoubleColumnName[i]))
642 for (i = 0; i < outputRows; i++)
643 if (!
SDDS_SetRowValues(&outputPage, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE, i,
"Index", i, NULL))
648 fprintf(stderr,
"Numerical data columns assigned\n");
653 fprintf(stderr,
"Data assigned\n");
656 if (!SDDS_WriteTable(&outputPage))
660 fprintf(stderr,
"Data written out\n");
664 if (inputDoubleColumns) {
668 if (inputColumnName) {
670 free(inputColumnName);
672 if (inputStringColumns)
673 free(inputStringColumnName);
674 if (inputDescription)
675 free(inputDescription);
676 if (inputParameterName) {
678 free(inputParameterName);
680 if (outputDoubleColumns) {
682 free(outputDoubleColumnName);
697char **TokenizeString(
char *source,
long n_items) {
707 string_array = (
char **)malloc(
sizeof(
char *) * n_items);
708 buflen = strlen(source) + 1;
709 buffer = (
char *)malloc(
sizeof(
char) * buflen);
710 for (i = 0; i < n_items; i++) {
720char *JoinStrings(
char **source,
long n_items,
long buflen_increment) {
723 long buffer_size, bufferLeft, bufferUsed;
727 buffer_size = buflen_increment;
728 buffer = (
char *)malloc(
sizeof(
char) * buffer_size);
731 bufferLeft = buffer_size - 2;
733 for (i = 0; i < n_items; i++) {
736 while ((slen + 5) > bufferLeft) {
737 buffer =
trealloc(buffer,
sizeof(
char) * (buffer_size += buflen_increment));
738 bufferLeft += buflen_increment;
739 ptr = buffer + bufferUsed;
750 bufferLeft -= slen + 2;
751 bufferUsed += slen + 2;
SDDS (Self Describing Data Set) Data Types Definitions and Function Prototypes.
void SDDS_DeferSavingLayout(SDDS_DATASET *SDDS_dataset, int32_t mode)
int32_t SDDS_SetRowValues(SDDS_DATASET *SDDS_dataset, int32_t mode, int64_t row,...)
int32_t SDDS_SetParameters(SDDS_DATASET *SDDS_dataset, int32_t mode,...)
int32_t SDDS_SetColumn(SDDS_DATASET *SDDS_dataset, int32_t mode, void *data, int64_t rows,...)
Sets the values for one data column in the current data table of an SDDS dataset.
int32_t SDDS_InitializeOutput(SDDS_DATASET *SDDS_dataset, int32_t data_mode, int32_t lines_per_row, const char *description, const char *contents, const char *filename)
Initializes the SDDS output dataset.
int32_t SDDS_DefineSimpleColumn(SDDS_DATASET *SDDS_dataset, const char *name, const char *unit, int32_t type)
Defines a simple data column within the SDDS dataset.
int32_t SDDS_DefineSimpleColumns(SDDS_DATASET *SDDS_dataset, int32_t number, char **name, char **unit, int32_t type)
Defines multiple simple data columns of the same data type within the SDDS dataset.
int32_t SDDS_DefineColumn(SDDS_DATASET *SDDS_dataset, const char *name, const char *symbol, const char *units, const char *description, const char *format_string, int32_t type, int32_t field_length)
Defines a data column within the SDDS dataset.
int32_t SDDS_WriteLayout(SDDS_DATASET *SDDS_dataset)
Writes the SDDS layout header to the output file.
int32_t SDDS_DefineParameter(SDDS_DATASET *SDDS_dataset, const char *name, const char *symbol, const char *units, const char *description, const char *format_string, int32_t type, char *fixed_value)
Defines a data parameter with a fixed string value.
int32_t SDDS_TransferParameterDefinition(SDDS_DATASET *target, SDDS_DATASET *source, char *name, char *newName)
Transfers a parameter definition from a source dataset to a target dataset.
int32_t SDDS_FreeStringArray(char **string, int64_t strings)
Frees an array of strings by deallocating each individual string.
char ** getMatchingSDDSNames(SDDS_DATASET *dataset, char **matchName, int32_t matches, int32_t *names, short type)
Retrieves an array of matching SDDS entity names based on specified criteria.
char ** SDDS_GetParameterNames(SDDS_DATASET *SDDS_dataset, int32_t *number)
Retrieves the names of all parameters in the SDDS dataset.
int32_t SDDS_CheckColumn(SDDS_DATASET *SDDS_dataset, char *name, char *units, int32_t type, FILE *fp_message)
Checks if a column exists in the SDDS dataset with the specified name, units, and type.
char ** SDDS_GetColumnNames(SDDS_DATASET *SDDS_dataset, int32_t *number)
Retrieves the names of all columns in the SDDS dataset.
void SDDS_PrintErrors(FILE *fp, int32_t mode)
Prints recorded error messages to a specified file stream.
void SDDS_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
int32_t SDDS_StringIsBlank(char *s)
Checks if a string is blank (contains only whitespace characters).
int32_t SDDS_GetToken(char *s, char *buffer, int32_t buflen)
Extracts the next token from a string, handling quoted substrings and escape characters.
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.
int32_t SDDS_CheckParameter(SDDS_DATASET *SDDS_dataset, char *name, char *units, int32_t type, FILE *fp_message)
Checks if a parameter exists in the SDDS dataset with the specified name, units, and type.
int32_t SDDS_CopyString(char **target, const char *source)
Copies a source string to a target string with memory allocation.
#define SDDS_STRING
Identifier for the string data type.
#define SDDS_LONG
Identifier for the signed 32-bit integer data type.
#define SDDS_DOUBLE
Identifier for the double data type.
#define SDDS_NUMERIC_TYPE(type)
Checks if the given type identifier corresponds to any numeric type.
Utility functions for SDDS dataset manipulation and string array operations.
void * trealloc(void *old_ptr, uint64_t size_of_block)
Reallocates a memory block to a new size.
void bomb(char *error, char *usage)
Reports error messages to the terminal and aborts the program.
int get_long(long *iptr, char *s)
Parses a long integer value from the given string.
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.
int scanargs(SCANNED_ARG **scanned, int argc, char **argv)
long processPipeOption(char **item, long items, unsigned long *flags)
void processFilenames(char *programName, char **input, char **output, unsigned long pipeFlags, long noWarnings, long *tmpOutputUsed)
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.