47#include "match_string.h"
64 CLO_NO_OLDCOLUMNNAMES,
69char *commandline_option[N_OPTIONS] = {
84static char *OLD_STRING_COLUMN_NAMES =
"OldStringColumnNames";
87 "Usage: sddstranspose <inputfile> <outputfile> [OPTIONS]\n\n"
89 " -pipe=[input][,output] Reads input from and/or writes output to a pipe.\n"
90 " -oldColumnNames=<string> Specifies the name for the output file string column created for the input file column names.\n"
91 " -root=<string> Uses the specified string to generate column names of the output file.\n"
92 " Default column names are the first string column in <inputfile>.\n"
93 " If no string column exists, column names are formed with the root \"Column\".\n"
94 " -digits=<integer> Sets the minimum number of digits appended to the root part of the column names.\n"
96 " -newColumnNames=<column> Uses the specified column as the source for new column names.\n"
97 " -symbol=<string> Uses the specified string for the symbol field in all column definitions.\n"
98 " -ascii Outputs the file in ASCII format. Default is binary.\n"
99 " -matchColumn=<string>[,<string>,...] Only transposes the columns that match the specified names.\n"
100 " -indexColumn Adds an index column to the output file.\n"
101 " -noOldColumnNames Does not create a new column for old column names.\n"
102 " -majorOrder=row|column Specifies the output file's major order (row-major or column-major).\n"
103 " -verbose Prints incidental information to stderr.\n\n"
104 "Link date: " __DATE__
" " __TIME__
", SVN revision: " SVN_VERSION
"\n";
106char **TokenizeString(
char *source,
long n_items);
107char *JoinStrings(
char **source,
long n_items,
long buflen_increment);
109int main(
int argc,
char **argv) {
113 char *inputfile, *outputfile;
114 char **inputColumnName, **inputStringColumnName, **inputDoubleColumnName;
115 char **outputStringColumnName, **outputDoubleColumnName, **matchColumn = NULL;
116 long inputDoubleColumns, inputStringColumns, indexColumn = 0, noOldColumnNamesColumn = 0;
118 int32_t matchColumns = 0;
119 long outputRows, outputDoubleColumns, outputStringColumns;
120 char **inputParameterName;
121 int32_t inputParameters;
122 int32_t inputColumns;
123 char *inputDescription, *inputContents;
124 char *outputDescription;
127 char **columnOfStrings;
129#define BUFFER_SIZE_INCREMENT 16384
131 long OldStringColumnsDefined;
132 char *inputStringRows, *outputStringRows;
133 char **stringArray, *stringParameter;
139 void *parameterPointer;
141 unsigned long pipeFlags, majorOrderFlag;
142 long tmpfile_used, noWarnings;
143 long ipage = 0, columnType;
144 char *oldColumnNames, *newColumnNamesColumn;
145 short columnMajorOrder = -1;
147 inputColumnName = outputStringColumnName = outputDoubleColumnName = inputParameterName = NULL;
148 outputRows = outputDoubleColumns = outputStringColumns = OldStringColumnsDefined = 0;
152 argc =
scanargs(&s_arg, argc, argv);
156 inputfile = outputfile = NULL;
158 Symbol = Root = NULL;
164 oldColumnNames = NULL;
165 newColumnNamesColumn = NULL;
167 for (i_arg = 1; i_arg < argc; i_arg++) {
168 if (s_arg[i_arg].arg_type == OPTION) {
169 switch (
match_string(s_arg[i_arg].list[0], commandline_option, N_OPTIONS, UNIQUE_MATCH)) {
170 case CLO_MAJOR_ORDER:
172 s_arg[i_arg].n_items--;
173 if (s_arg[i_arg].n_items > 0 &&
174 (!
scanItemList(&majorOrderFlag, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
175 "row", -1, NULL, 0, SDDS_ROW_MAJOR_ORDER,
176 "column", -1, NULL, 0, SDDS_COLUMN_MAJOR_ORDER, NULL)))
177 SDDS_Bomb(
"invalid -majorOrder syntax/values");
178 if (majorOrderFlag & SDDS_COLUMN_MAJOR_ORDER)
179 columnMajorOrder = 1;
180 else if (majorOrderFlag & SDDS_ROW_MAJOR_ORDER)
181 columnMajorOrder = 0;
183 case CLO_MATCH_COLUMN:
184 matchColumns = s_arg[i_arg].n_items - 1;
185 matchColumn = s_arg[i_arg].list + 1;
187 case CLO_INDEX_COLUMN:
190 case CLO_NO_OLDCOLUMNNAMES:
191 noOldColumnNamesColumn = 1;
200 if (!(
get_long(&digits, s_arg[i_arg].list[1])))
201 bomb(
"No integer provided for option -digits", USAGE);
204 if (!(Root = s_arg[i_arg].list[1]))
205 SDDS_Bomb(
"No root string provided with -root option");
208 if (!(Symbol = s_arg[i_arg].list[1]))
209 SDDS_Bomb(
"No symbol string provided with -symbol option");
212 if (!
processPipeOption(s_arg[i_arg].list + 1, s_arg[i_arg].n_items - 1, &pipeFlags))
215 case CLO_OLDCOLUMNNAMES:
216 if (!(oldColumnNames = s_arg[i_arg].list[1]))
217 SDDS_Bomb(
"No string provided for -oldColumnNames option");
219 case CLO_NEWCOLUMNNAMES:
220 if (s_arg[i_arg].n_items != 2 ||
SDDS_StringIsBlank(newColumnNamesColumn = s_arg[i_arg].list[1]))
221 SDDS_Bomb(
"Invalid syntax or value for -newColumnNames option");
224 bomb(
"Unrecognized option provided", USAGE);
228 inputfile = s_arg[i_arg].list[0];
229 else if (!outputfile)
230 outputfile = s_arg[i_arg].list[0];
232 bomb(
"Too many filenames provided", USAGE);
236 processFilenames(
"sddstranspose", &inputfile, &outputfile, pipeFlags, noWarnings, &tmpfile_used);
237 if (newColumnNamesColumn && Root)
238 SDDS_Bomb(
"-root and -newColumnNames options are incompatible");
246 inputColumnName =
getMatchingSDDSNames(&inputPage, matchColumn, matchColumns, &inputColumns, SDDS_MATCH_COLUMN);
252 inputDoubleColumns = 0;
253 inputStringColumns = 0;
254 inputDoubleColumnName = (
char **)malloc(inputColumns *
sizeof(
char *));
255 inputStringColumnName = (
char **)malloc(inputColumns *
sizeof(
char *));
261 while (0 < SDDS_ReadTable(&inputPage)) {
264 fprintf(stderr,
"Working on page %ld\n", ipage);
271 for (i = 0; i < inputColumns; i++) {
273 inputDoubleColumnName[inputDoubleColumns] = inputColumnName[i];
274 inputDoubleColumns++;
277 for (i = 0; i < inputPage.layout.n_columns; i++) {
278 if (inputPage.layout.column_definition[i].type ==
SDDS_STRING) {
279 inputStringColumnName[inputStringColumns] = inputPage.layout.column_definition[i].name;
280 inputStringColumns++;
288 SDDS_Bomb(
"Datasets have differing number of rows. Processing stopped before reaching end of input file.");
292 if (inputRows > INT32_MAX) {
297 fprintf(stderr,
"Row flags set\n");
299 if (inputDoubleColumns == 0)
300 SDDS_Bomb(
"No numerical columns in file.");
302 if ((ipage == 1) && verbose) {
303 fprintf(stderr,
"Number of numerical columns: %ld.\n", inputDoubleColumns);
304 fprintf(stderr,
"Number of string columns: %ld.\n", inputStringColumns);
305 fprintf(stderr,
"Number of rows: %" PRId64
".\n", inputRows);
311 if (inputDoubleColumns) {
313 m_alloc(&RInv, inputRows, inputDoubleColumns);
314 m_alloc(&R, inputDoubleColumns, inputRows);
316 for (col = 0; col < inputDoubleColumns; col++) {
322 m_show(R,
"%9.6le ",
"Transpose of input matrix:\n", stdout);
332 OldStringColumnsDefined = 0;
334 case SDDS_CHECK_OKAY:
335 OldStringColumnsDefined = 1;
337 case SDDS_CHECK_NONEXISTENT:
339 case SDDS_CHECK_WRONGTYPE:
340 case SDDS_CHECK_WRONGUNITS:
341 fprintf(stderr,
"Error: Parameter OldStringColumns has incorrect type or units.\n");
346 if (OldStringColumnsDefined) {
352 fprintf(stderr,
"Parameter OldStringColumns: %s.\n", inputStringRows);
355 outputStringColumnName = (
char **)malloc(
sizeof(
char *));
356 outputStringColumns = 0;
357 buffer_size = BUFFER_SIZE_INCREMENT;
358 buffer = (
char *)malloc(
sizeof(
char) * buffer_size);
359 while (0 <= (token_length =
SDDS_GetToken(inputStringRows, buffer, BUFFER_SIZE_INCREMENT))) {
361 SDDS_Bomb(
"A null string was detected in parameter OldStringColumns.");
363 if (!
SDDS_CopyString(&outputStringColumnName[outputStringColumns], buffer))
367 fprintf(stderr,
"Output string column: %s\n", outputStringColumnName[outputStringColumns]);
369 outputStringColumns++;
378 outputRows = inputDoubleColumns;
379 outputDoubleColumns = inputRows;
381 if (inputDescription) {
382 outputDescription = (
char *)malloc(
sizeof(
char) * (strlen(
"Transpose of ") + strlen(inputDescription) + 1));
383 strcpy(outputDescription,
"Transpose of ");
384 strcat(outputDescription, inputDescription);
385 if (!
SDDS_InitializeOutput(&outputPage, ascii ? SDDS_ASCII : SDDS_BINARY, 1, outputDescription, inputContents, outputfile))
387 free(outputDescription);
389 if (!
SDDS_InitializeOutput(&outputPage, ascii ? SDDS_ASCII : SDDS_BINARY, 1, NULL, NULL, outputfile))
395 if (columnMajorOrder != -1)
396 outputPage.layout.data_mode.column_major = columnMajorOrder;
398 outputPage.layout.data_mode.column_major = inputPage.layout.data_mode.column_major;
403 if (!Root && inputStringColumns) {
405 if (!newColumnNamesColumn)
407 outputDoubleColumnName = (
char **)
SDDS_GetColumn(&inputPage, inputStringColumnName[0]);
411 SDDS_Bomb(
"Column specified with -newColumnNames does not exist in input file.");
412 outputDoubleColumnName = (
char **)
SDDS_GetColumn(&inputPage, newColumnNamesColumn);
415 for (i = 1; i < inputRows; i++) {
416 if (
match_string(outputDoubleColumnName[i - 1], outputDoubleColumnName + i, inputRows - i, EXACT_MATCH) >= 0) {
417 fprintf(stderr,
"Error: Duplicate column name '%s' found in input file string column '%s'. Cannot be used as output column names.\n",
418 outputDoubleColumnName[i - 1], newColumnNamesColumn ? newColumnNamesColumn : inputStringColumnName[0]);
424 outputDoubleColumnName = (
char **)malloc(outputDoubleColumns *
sizeof(
char *));
425 digits = MAX(digits, (
long)(log10(inputRows) + 1));
427 Root = (
char *)malloc(
sizeof(
char) * (strlen(
"Column") + 1));
428 strcpy(Root,
"Column");
430 if (outputDoubleColumns != 1) {
431 for (i = 0; i < outputDoubleColumns; i++) {
432 outputDoubleColumnName[i] = (
char *)malloc(
sizeof(
char) * (strlen(Root) + digits + 1));
433 sprintf(format,
"%s%%0%ldld", Root, digits);
434 sprintf(outputDoubleColumnName[i], format, i);
437 outputDoubleColumnName[0] = (
char *)malloc(
sizeof(
char) * (strlen(Root) + 1));
438 strcpy(outputDoubleColumnName[0], Root);
445 if (OldStringColumnsDefined) {
450 if (!noOldColumnNamesColumn) {
451 outputStringColumns = 1;
452 outputStringColumnName = (
char **)malloc(
sizeof(
char *));
453 if (oldColumnNames) {
455 outputStringColumnName[0] = oldColumnNames;
457 outputStringColumnName[0] = (
char *)malloc(
sizeof(
char) * (strlen(
"OldColumnNames") + 1));
458 strcpy(outputStringColumnName[0],
"OldColumnNames");
471 for (i = 0; i < outputDoubleColumns; i++) {
485 if (inputStringColumns > 1) {
488 for (i = 0; i < inputStringColumns; i++) {
497 if (inputParameters) {
498 for (i = 0; i < inputParameters; i++) {
499 if ((0 >
match_string(inputParameterName[i], outputStringColumnName, outputStringColumns, 0) &&
500 strcasecmp(inputParameterName[i], OLD_STRING_COLUMN_NAMES))) {
514 case SDDS_CHECK_NONEXISTENT:
527 fprintf(stderr,
"Table layout defined\n");
530 if (!SDDS_StartTable(&outputPage, outputRows))
533 if (!
SDDS_SetParameters(&outputPage, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE,
"InputFile", inputfile ? inputfile :
"pipe", NULL))
541 if (inputStringColumns > 1) {
542 for (i = 0; i < inputStringColumns; i++) {
543 columnOfStrings = (
char **)
SDDS_GetColumn(&inputPage, inputStringColumnName[i]);
544 stringParameter = JoinStrings(columnOfStrings, inputRows, BUFFER_SIZE_INCREMENT);
545 if (!
SDDS_SetParameters(&outputPage, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE, inputStringColumnName[i], stringParameter, NULL))
547 free(columnOfStrings);
548 free(stringParameter);
550 outputStringRows = JoinStrings(inputStringColumnName, inputStringColumns, BUFFER_SIZE_INCREMENT);
551 if (!
SDDS_SetParameters(&outputPage, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE, OLD_STRING_COLUMN_NAMES, outputStringRows, NULL))
556 fprintf(stderr,
"String parameters assigned\n");
559 if (inputParameters) {
560 for (i = 0; i < inputParameters; i++) {
561 if ((0 >
match_string(inputParameterName[i], outputStringColumnName, outputStringColumns, 0) &&
562 strcasecmp(inputParameterName[i], OLD_STRING_COLUMN_NAMES))) {
563 parameterPointer = (
void *)
SDDS_GetParameter(&inputPage, inputParameterName[i], NULL);
564 if (!
SDDS_SetParameters(&outputPage, SDDS_SET_BY_NAME | SDDS_PASS_BY_REFERENCE, inputParameterName[i], parameterPointer, NULL))
566 free(parameterPointer);
572 fprintf(stderr,
"Input parameters assigned\n");
583 if (OldStringColumnsDefined) {
584 for (i = 0; i < outputStringColumns; i++) {
587 stringArray = TokenizeString(stringParameter, outputRows);
588 if (!
SDDS_SetColumn(&outputPage, SDDS_SET_BY_NAME | SDDS_PASS_BY_REFERENCE, stringArray, outputRows, outputStringColumnName[i]))
593 if (!noOldColumnNamesColumn &&
594 !
SDDS_SetColumn(&outputPage, SDDS_SET_BY_NAME | SDDS_PASS_BY_REFERENCE, inputDoubleColumnName, outputRows, outputStringColumnName[0]))
599 fprintf(stderr,
"String data columns assigned\n");
605 for (i = 0; i < outputDoubleColumns; i++)
606 if (!
SDDS_SetColumn(&outputPage, SDDS_SET_BY_NAME | SDDS_PASS_BY_REFERENCE, RInv->a[i], outputRows, outputDoubleColumnName[i]))
610 for (i = 0; i < outputRows; i++)
611 if (!
SDDS_SetRowValues(&outputPage, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE, i,
"Index", i, NULL))
616 fprintf(stderr,
"Numerical data columns assigned\n");
621 fprintf(stderr,
"Data assigned\n");
624 if (!SDDS_WriteTable(&outputPage))
628 fprintf(stderr,
"Data written out\n");
632 if (inputDoubleColumns) {
636 if (inputColumnName) {
638 free(inputColumnName);
640 if (inputStringColumns)
641 free(inputStringColumnName);
642 if (inputDescription)
643 free(inputDescription);
644 if (inputParameterName) {
646 free(inputParameterName);
648 if (outputDoubleColumns) {
650 free(outputDoubleColumnName);
665char **TokenizeString(
char *source,
long n_items) {
675 string_array = (
char **)malloc(
sizeof(
char *) * n_items);
676 buflen = strlen(source) + 1;
677 buffer = (
char *)malloc(
sizeof(
char) * buflen);
678 for (i = 0; i < n_items; i++) {
688char *JoinStrings(
char **source,
long n_items,
long buflen_increment) {
691 long buffer_size, bufferLeft, bufferUsed;
695 buffer_size = buflen_increment;
696 buffer = (
char *)malloc(
sizeof(
char) * buffer_size);
699 bufferLeft = buffer_size - 2;
701 for (i = 0; i < n_items; i++) {
704 while ((slen + 5) > bufferLeft) {
705 buffer =
trealloc(buffer,
sizeof(
char) * (buffer_size += buflen_increment));
706 bufferLeft += buflen_increment;
707 ptr = buffer + bufferUsed;
718 bufferLeft -= slen + 2;
719 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.
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.