/* Copyright (c) 2001-2010, Dirk Krause All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above opyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Dirk Krause nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @file ksort.c The ksort program. */ #include #include #include #include #include #include #include #if DK_HAVE_STDLIB_H #include #endif #include #include "dktools-version.h" #line 65 "ksort.ctr" /** System configuration directory. */ static char sysconfdir[] = { DK_SYSCONFDIR }; /** Program group name. */ static char packagename[] = { "dktools" }; /** Version number. */ static char the_version_number[] = { VERSNUMB } ; /** License terms. */ static char *license_terms[] = { "Redistribution and use in source and binary forms, with or without", "modification, are permitted provided that the following conditions are met:", "* Redistributions of source code must retain the above copyright notice, this", " list of conditions and the following disclaimer.", "* Redistributions in binary form must reproduce the above copyright notice,", " this list of conditions and the following disclaimer in the documentation", " and/or other materials provided with the distribution.", "* Neither the name of the Dirk Krause nor the names of other contributors may", " be used to endorse or promote products derived from this software without", " specific prior written permission.", "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"", "AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE", "IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE", "ARE DISCLAIMED.", "IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY", "DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES", "(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;", "LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND", "ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT", "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS", "SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.", NULL }; /** Print version information. */ static void print_version DK_P0() { char **ptr; printf("\n"); printf( "ksort (part of the dktools collection, version %s)\n", the_version_number ); printf("Copyright (C) 2002-2010 Dipl.-Ing. D. Krause\n"); printf("http://dktools.sourceforge.net/\n\n"); ptr = license_terms; while(*ptr) { printf("%s\n", *(ptr++)); } printf("\nLibraries used:\n\n"); ptr = dklic_get(); while(*ptr) { printf("%s\n", *(ptr++)); } printf("\n"); } /** Default help text, printed if help text file is not found. */ static char *help_text[] = { "ksort [-b] [-i] [-n | -f] [-r] [-m] [-o ] []", "", /* --blanks */ "-b Leading whitespaces are ignored.", /* --case-insensitive */ "-n Character-comparisons are case-insensitive.", /* --decimal */ "-d Lines are started by long decimal numbers.", /* --float */ "-f Lines are started by floating point numbers.", /* --reversed */ "-i Sort order is reversed.", /* --merge */ "-m Merge multiple occurances of equal lines.", "-o Output is written to the specified file.", "", "", /* --unconfigure */ "ksort -u Resets all preferences.", "", /* --configure */ "ksort -c Installs the given options as default preferences.", NULL }; /** Application */ static dk_app_t *app = NULL; /** Message issued by the program, filled using the string finder. */ static char *ksort_str[17]; /** String finder data. */ static dk_string_finder_t ksort_find[] = { { "/m/0", &(ksort_str[0]), "Not enough memory!" }, { "/m/1", &(ksort_str[1]), "Failed to read from \"" }, { "/m/2", &(ksort_str[2]), "\"!" }, { "/m/3", &(ksort_str[3]), "No file matching \"" }, { "/m/4", &(ksort_str[4]), "\"!" }, { "/m/5", &(ksort_str[5]), "Failed to correct filename \"" }, { "/m/6", &(ksort_str[6]), "\"!" }, { "/m/7", &(ksort_str[7]), "on" }, { "/m/8", &(ksort_str[8]), "off" }, { "/m/9", &(ksort_str[9]), "line length" }, { "/m/10", &(ksort_str[10]), "ignore leading spaces" }, { "/m/11", &(ksort_str[11]), "decimal numbers" }, { "/m/12", &(ksort_str[12]), "floating point numbers" }, { "/m/13", &(ksort_str[13]), "reversed sort order" }, { "/m/14", &(ksort_str[14]), "unique sorting" }, { "/m/15", &(ksort_str[15]), "case-insensitive" }, { "/m/16", &(ksort_str[16]), "Current configuration:" }, { NULL, NULL, NULL } }; /** Saved input lines sorted container. */ static dk_storage_t *lines = NULL; /** Saved input lines iterator. */ static dk_storage_iterator_t *linesit = NULL; /** Flag: Ignore leading blanks. */ #define FLAG_IGNORE_BLANKS 1 /** Flag: Case insensitive comparisons. */ #define FLAG_CASEINS 2 /** Flag: Sort by decimal values. */ #define FLAG_NUMERIC 4 /** Flag: Inverted sort order, */ #define FLAG_REVERSED 8 /** Flag: Merge equal lines. */ #define FLAG_UNIQUE 16 /** Flag: Sort by floating point numbers. */ #define FLAG_NUMFLOAT 32 /** Flag: Print help. */ #define FLAG_HELP 64 /** Flag: Print version information. */ #define FLAG_VERSION 128 /** Flag: Configure the application. */ #define FLAG_CONFIGURE 256 /** Flag: Show current configuration. */ #define FLAG_SHOWCONF 512 /** Flag: Unconfigure the application. */ #define FLAG_UNCONF 1024 /** Flag set. */ static int flags = 0; /** Input file names. */ static char **filenames; /** Number of names to use. */ int names_to_use; /** Output file name. */ static char *outputname = NULL; /** Output file. */ static FILE *outputfile = NULL; #ifndef LINELENGTH /** Maximum line length. */ #define LINELENGTH 512 #endif /** Line length. */ static int linelength = LINELENGTH ; /** Preference value: on. */ static char pv_on[] = { "on" }; /** Preference value: off. */ static char pv_off[] = { "off" }; /** Preference name for ignoring leading blanks. */ static char pn_blanks[] = { "/ignore-blanks" }; /** Preference name for folds. */ static char pn_fold[] = { "/fold" }; /** Preference name for sort by numeric values. */ static char pn_numeric[] = { "/numeric" }; /** Preference name for sort by floating point number. */ static char pn_float[] = { "/numeric-float" }; /** Preference name for inverted sort order. */ static char pn_reverse[] = { "/reverse" }; /** Preference name for merge option. */ static char pn_unique[] = { "/unique" }; /** Preference name for output. */ static char pn_output[] = { "/output" }; /** Preference name for line length. */ static char pn_ll[] = { "/line-length" }; /** Adjust the flags. @param ptr Boolean value as text. @param f Old flag set. @return Modified flag set. */ static void adjust_flags DK_P2(char *,ptr, int, f) { ptr++; if(*ptr) { if(*ptr == '-') { flags = flags & (~(f)); } else { if(*ptr == '+') { flags = flags | f; } else { if(dkstr_is_on(ptr)) { flags = flags | f; } else { flags = flags & (~(f)); } } } } else { flags = flags | f; } } /** Reset all options completely. */ static void reset_completely DK_P0() { flags = 0; linelength = LINELENGTH ; } /** Long options. */ static char *long_options[] = { /* 00 */ "r$eset", /* 01 */ "s$how-configuration", /* 02 */ "c$onfigure", /* 03 */ "l$inelength", /* 04 */ "u$nconfigure", /* 05 */ "h$elp", /* 06 */ "v$ersion", /* 07 */ "ig$nore-blanks", /* 08 */ "d$ecimal", /* 09 */ "f$loat", /* 10 */ "in$verted", /* 11 */ "m$erge", /* 12 */ "o$utput-file", /* 13 */ "n$ot-case-sensitive", NULL }; /** Process command line arguments. @param argc Number of command line arguments. @param argv Command line arguments array. @return Comparison result. */ static int process_args DK_P2(int, argc, char **, argv) { int back = 1; char buffer[64]; int i, x; char *cptr, *value, **lfd; char *logmsg[3]; int found; /* Reset to program defaults */ reset_completely(); /* Retrieve preferences */ if(dkapp_get_pref(app, pn_blanks, buffer, sizeof(buffer), 0)) { if(dkstr_is_on(buffer)) { flags |= FLAG_IGNORE_BLANKS; } else { flags &= (~(FLAG_IGNORE_BLANKS)); } } if(dkapp_get_pref(app, pn_numeric, buffer, sizeof(buffer), 0)) { if(dkstr_is_on(buffer)) { flags |= FLAG_NUMERIC; } else { flags &= (~(FLAG_NUMERIC)); } } if(dkapp_get_pref(app, pn_float, buffer, sizeof(buffer), 0)) { if(dkstr_is_on(buffer)) { flags |= FLAG_NUMFLOAT; } else { flags &= (~(FLAG_NUMFLOAT)); } } if(dkapp_get_pref(app, pn_reverse, buffer, sizeof(buffer), 0)) { if(dkstr_is_on(buffer)) { flags |= FLAG_REVERSED; } else { flags &= (~(FLAG_REVERSED)); } } if(dkapp_get_pref(app, pn_reverse, buffer, sizeof(buffer), 0)) { if(dkstr_is_on(buffer)) { flags |= FLAG_UNIQUE; } else { flags &= (~(FLAG_UNIQUE)); } } if(dkapp_get_pref(app, pn_ll, buffer, sizeof(buffer), 0)) { if(sscanf(buffer, "%d", &x) == 1) { linelength = x ; } } if(dkapp_get_pref(app, pn_output, buffer, sizeof(buffer), 0)) { outputname = dkstr_dup(buffer); if(!outputname) { back = 0; } } lfd = argv; lfd++; i = 1; while(i < argc) { cptr = *lfd; value = NULL; if(*cptr == '-') { cptr++; switch(*cptr) { case '-' : { /* long options alles neu */ char *optarg; cptr++; optarg = dkstr_chr(cptr, '='); if(optarg) { *(optarg++)='\0'; } found = dkstr_array_abbr(long_options, cptr, '$', 1); switch(found) { case 0: { if(optarg) { if(dkstr_is_on(optarg)) { reset_completely(); } } else { reset_completely(); } } break; case 1: { if(optarg) { if(dkstr_is_on(optarg)) { flags |= FLAG_SHOWCONF; } else { flags &= (~(FLAG_SHOWCONF)); } } else { flags |= FLAG_SHOWCONF; } } break; case 2: { if(optarg) { if(dkstr_is_on(optarg)) { flags |= FLAG_CONFIGURE; } else { flags &= (~(FLAG_CONFIGURE)); } } else { flags |= FLAG_CONFIGURE; } } break; case 3: { linelength = LINELENGTH; if(optarg) { if(sscanf(optarg, "%d", &x) == 1) { linelength = x; } } } break; case 4: { if(optarg) { if(dkstr_is_on(optarg)) { flags |= FLAG_CONFIGURE; flags |= FLAG_UNCONF; dkapp_unconfigure(app); } else { flags &= (~(FLAG_CONFIGURE)); flags &= (~(FLAG_UNCONF)); } } else { flags |= FLAG_CONFIGURE; flags |= FLAG_UNCONF; dkapp_unconfigure(app); } } break; case 5: { if(optarg) { if(dkstr_is_on(optarg)) { flags |= FLAG_HELP; } else { flags &= (~(FLAG_HELP)); } } else { flags |= FLAG_HELP; } } break; case 6: { if(optarg) { if(dkstr_is_on(optarg)) { flags |= FLAG_VERSION; } else { flags &= (~(FLAG_VERSION)); } } else { flags |= FLAG_VERSION; } } break; case 7: { if(optarg) { if(dkstr_is_on(optarg)) { flags |= FLAG_IGNORE_BLANKS; } else { flags &= (~(FLAG_IGNORE_BLANKS)); } } else { flags |= FLAG_IGNORE_BLANKS; } } break; case 8: { if(optarg) { if(dkstr_is_on(optarg)) { flags |= FLAG_NUMERIC; flags &= (~(FLAG_NUMFLOAT)); } else { flags &= (~(FLAG_NUMERIC)); } } else { flags |= FLAG_NUMERIC; flags &= (~(FLAG_NUMFLOAT)); } } break; case 9: { if(optarg) { if(dkstr_is_on(optarg)) { flags |= FLAG_NUMFLOAT; flags &= (~(FLAG_NUMERIC)); } else { flags &= (~(FLAG_NUMFLOAT)); } } else { flags |= FLAG_NUMFLOAT; flags &= (~(FLAG_NUMERIC)); } } break; case 10: { if(optarg) { if(dkstr_is_on(optarg)) { flags |= FLAG_REVERSED; } else { flags &= (~(FLAG_REVERSED)); } } else { flags |= FLAG_REVERSED; } } break; case 11: { if(optarg) { if(dkstr_is_on(optarg)) { flags |= FLAG_UNIQUE; } else { flags &= (~(FLAG_UNIQUE)); } } else { flags |= FLAG_UNIQUE; } } break; case 12: { if(optarg) { if(outputname) { dk_delete(outputname); } outputname = dkstr_dup(optarg); if(!outputname) { back = 0; logmsg[0] = ksort_str[0]; dkapp_log_msg(app, DK_LOG_LEVEL_ERROR, logmsg, 1); } } } break; case 13: { if(optarg) { if(dkstr_is_on(optarg)) { flags |= FLAG_CASEINS; } else { flags &= (~(FLAG_CASEINS)); } } else { flags |= FLAG_CASEINS; } } break; } } break; case 'C' : { flags |= FLAG_SHOWCONF; } break; case 'c' : { flags |= FLAG_CONFIGURE; } break; case 'l' : { cptr++; if(*cptr) { value = cptr; } else { i++; lfd++; if(i < argc) { value = *lfd; } } if(value) { if(sscanf(value, "%d", &x) == 1) { linelength = x ; } } } break; case 'u' : { flags |= FLAG_CONFIGURE; flags |= FLAG_UNCONF; dkapp_unconfigure(app); } break; case 'h' : { flags |= FLAG_HELP; } break; case 'v' : { flags |= FLAG_VERSION; } break; case 'b' : { adjust_flags(cptr, FLAG_IGNORE_BLANKS); } break; case 'i' : { /* adjust_flags(cptr, FLAG_CASEINS); */ adjust_flags(cptr, FLAG_REVERSED); } break; case 'n' : { adjust_flags(cptr, FLAG_CASEINS); } break; case 'd' : { adjust_flags(cptr, FLAG_NUMERIC); } break; case 'f' : { adjust_flags(cptr, FLAG_NUMFLOAT); } break; case 'r' : { /* adjust_flags(cptr, FLAG_REVERSED); */ reset_completely(); } break; case 'm' : { adjust_flags(cptr, FLAG_UNIQUE); } break; case 'o' : { cptr++; if(*cptr) { value = cptr; } else { lfd++; i++; if(i < argc) { value = *lfd; } } if(value) { if(outputname) { dk_delete(outputname); } outputname = dkstr_dup(value); if(!outputname) { back = 0; logmsg[0] = ksort_str[0]; dkapp_log_msg(app, DK_LOG_LEVEL_ERROR, logmsg, 1); } } } break; } } else { filenames[names_to_use++] = cptr; } i++; lfd++; } if(linelength < 256) { linelength = 256; } if(linelength > 0x7FFF) { linelength = 0x7FFF; } return back; } /** Input line record. */ typedef struct { char *line; /**< Line text. */ long lv; /**< Long numeric value. */ double dv; /**< Double numeric value. */ int vf; /**< Flag: Numeric value found at start of line. */ } LineInfo; /** Compare two strings. @param s1 Left string. @param s2 Right string. @param ci Flag: Case-insensitive. @return Comparison result. */ static int xxx_cmp DK_P3(char *, s1, char *, s2, int, ci) { int back = 0; char *p1, *p2; p1 = s1; p2 = s2; if(flags & FLAG_IGNORE_BLANKS) { p1 = dkstr_start(s1, NULL); p2 = dkstr_start(s2, NULL); } if(p1) { if(p2) { if(ci) { back = dkstr_casecmp(p1,p2); } else { back = strcmp(p1,p2); } } else { back = 1; } } else { if(p2) { back = -1; } } return back; } /** Compare two input lines. @param p1 Left line. @param p2 Right line. @param cr Comparison criteria. @return Comparison result. */ static int compare_data DK_P3(void *, p1, void *, p2, int, cr) { int back = 0; LineInfo *l1, *l2; char *s1, *s2; double d; long l; int v; if(p1) { if(p2) { switch(cr) { case 1: { if(flags & (FLAG_NUMERIC | FLAG_NUMFLOAT)) { v = 0; l = 0L; d = 0.0; l1 = (LineInfo *)p1; s2 = (char *)p2; if(flags & FLAG_NUMFLOAT) { if(sscanf(s2, "%lf", &d) == 1) { v = 1; } } else { if(sscanf(s2, "%ld", &l) == 1) { v = 1; } } if(l1->vf) { if(v) { if(flags & FLAG_NUMFLOAT) { if((l1->dv) > d) { back = 1; } else { if((l1->dv) < d) { back = -1; } } } else { if((l1->lv) > l) { back = 1; } else { if((l1->lv) < l) { back = -1; } } } } else { back = 1; } } else { if(v) { back = -1; } else { if(flags & FLAG_CASEINS) { back = xxx_cmp(l1->line, s2, 1); } else { back = xxx_cmp(l1->line, s2, 0); } } } } else { s1 = (char *)p1; s2 = (char *)p2; if(flags & FLAG_CASEINS) { back = xxx_cmp(s1,s2, 1); } else { back = xxx_cmp(s1,s2, 0); } } } break; default : { if(flags & (FLAG_NUMERIC | FLAG_NUMFLOAT)) { l1 = (LineInfo *)p1; l2 = (LineInfo *)p2; if(l1->vf) { if(l2->vf) { if(flags & FLAG_NUMFLOAT) { if((l1->dv) > (l2->dv)) { back = 1; } else { if((l1->dv) < (l2->dv)) { back = -1; } } } else { if((l1->lv) > (l2->lv)) { back = 1; } else { if((l1->lv) < (l2->lv)) { back = -1; } } } } else { back = 1; } } else { if(l2->vf) { back = -1; } else { if(flags & FLAG_CASEINS) { back = xxx_cmp(l1->line, l2->line, 1); } else { back = xxx_cmp(l1->line, l2->line, 0); } } } } else { s1 = (char *)p1; s2 = (char *)p2; if(flags & FLAG_CASEINS) { back = xxx_cmp(s1,s2, 1); } else { back = xxx_cmp(s1,s2, 0); } } } break; } } else { back = 1; } } else { if(p2) { back = -1; } } if(flags & FLAG_REVERSED) { back = 0 - back; } if(back < -1) back = -1; if(back > 1) back = 1; return back; } /** Save one input line in sorted container. @param line Input line. @return 1 on success, 0 on error. */ static int save_line DK_P1(char *, line) { int back = 0; LineInfo *li; long l; double d; if(flags & (FLAG_NUMERIC | FLAG_NUMFLOAT)) { if(flags & FLAG_UNIQUE) { if(dksto_it_find_like(linesit, line, 1)) { dk_delete(line); back = 1; } else { li = dk_new(LineInfo,1); if(li) { li->line = line; li->vf = 0; if(flags & FLAG_NUMFLOAT) { if(sscanf(line, "%lf", &d) == 1) { li->dv = d; li->vf = 1; } } else { if(sscanf(line, "%ld", &l) == 1) { li->lv = l; li->vf = 1; } } if(dksto_add(lines, li)) { back = 1; } else { dk_delete(li); } } } } else { li = dk_new(LineInfo,1); if(li) { li->line = line; li->vf = 0; if(flags & FLAG_NUMFLOAT) { if(sscanf(line, "%lf", &d) == 1) { li->dv = d; li->vf = 1; } } else { if(sscanf(line, "%ld", &l) == 1) { li->lv = l; li->vf = 1; } } if(dksto_add(lines, li)) { back = 1; } else { dk_delete(li); } } } } else { if(flags & FLAG_UNIQUE) { if(dksto_it_find_like(linesit, line, 1)) { back = 1; dk_delete(line); } else { back = dksto_add(lines, line); } } else { back = dksto_add(lines, line); } } return back; } /** Read input from input file. @param in Input file. @param buffer Buffer for line. @return 1 on success, 0 on error. */ static int read_file DK_P2(FILE *, in, char *, buffer) { int back = 1; size_t maxlgt; char *copyptr; char *logmsg[3]; maxlgt = linelength - 1; while(fgets(buffer, maxlgt, in)) { copyptr = dkstr_dup(buffer); if(copyptr) { if(!save_line(copyptr)) { dk_delete(copyptr); copyptr = NULL; back = 0; dkapp_log_msg(app, DK_LOG_LEVEL_ERROR, logmsg, 1); } } else { back = 0; dkapp_log_msg(app, DK_LOG_LEVEL_ERROR, logmsg, 1); } } return back; } /** Open input file, read input and Save all input lines in a sorted container. */ static int read_input DK_P0() { int back = 0; dk_fne_t *fne; int i; int need_correction; char *inputline, *cptr, *fn; FILE *infile; char *logmsg[3]; inputline = dk_new(char,linelength); if(inputline) { back = 1; if(names_to_use) { for(i = 0; i < names_to_use; i++) { cptr = filenames[i]; need_correction = dksf_must_expand_filename(filenames[i]); cptr = filenames[i]; if(need_correction) { need_correction = 0; fne = dkfne_open(cptr, 1, 0); if(fne) { while(dkfne_next(fne)) { need_correction = 1; fn = dkfne_get_fullname(fne); infile = dkapp_fopen(app, fn, "r"); if(infile) { if(!read_file(infile, inputline)) { back = 0; } fclose(infile); } else { back = 0; logmsg[0] = ksort_str[1]; logmsg[2] = ksort_str[2]; logmsg[1] = fn; dkapp_log_msg(app, DK_LOG_LEVEL_ERROR, logmsg, 3); } } if(!need_correction) { back = 0; logmsg[0] = ksort_str[3]; logmsg[2] = ksort_str[4]; logmsg[1] = cptr; dkapp_log_msg(app, DK_LOG_LEVEL_ERROR, logmsg, 3); } dkfne_close(fne); } else { back = 0; logmsg[0] = ksort_str[5]; logmsg[2] = ksort_str[6]; logmsg[1] = cptr; dkapp_log_msg(app, DK_LOG_LEVEL_ERROR, logmsg, 3); } } else { infile = dkapp_fopen(app, cptr, "r"); if(infile) { if(!read_file(infile, inputline)) { back = 0; } fclose(infile); } /* 2003/12/17 auskommentiert wegen Directory-Check else { back = 0; logmsg[0] = ksort_str[1]; logmsg[2] = ksort_str[2]; logmsg[1] = cptr; dkapp_log_msg(app, DK_LOG_LEVEL_ERROR, logmsg, 3); } */ } } } else { back = read_file(stdin, inputline); } dk_delete(inputline); } else { dkapp_log_msg(app, DK_LOG_LEVEL_ERROR, logmsg, 1); } return back; } /** Write output. */ static void write_to DK_P0() { LineInfo *li; char *s; dksto_it_reset(linesit); if(flags & (FLAG_NUMFLOAT | FLAG_NUMERIC)) { while((li = (LineInfo *)dksto_it_next(linesit)) != NULL) { fprintf(outputfile, "%s", li->line); } } else { while((s = (char *)dksto_it_next(linesit)) != NULL) { fprintf(outputfile, "%s", s); } } } /** Open output file and write output. */ static int write_output DK_P0() { int back = 0; FILE *myfile; dk_fne_t *fne; if(outputname) { dksf_correct_fnsep(outputname); if(dksf_must_expand_filename(outputname)) { fne = dkfne_open(outputname, 1, 0); if(fne) { char *cptr; cptr = dkapp_fne_one(app, fne, outputname); if(cptr) { myfile = dkapp_fopen(app,cptr,"w"); if(myfile) { outputfile = myfile; back = 1; write_to(); fclose(myfile); } else { dkapp_err_fopenw(app, cptr); } dk_delete(cptr); } dkfne_close(fne); fne = NULL; } else { dkapp_err_no_such_file(app, outputname); } } else { myfile = dkapp_fopen(app,outputname,"w"); if(myfile) { outputfile = myfile; back = 1; write_to(); fclose(myfile); } } } else { back = 1; outputfile = stdout; write_to(); } outputfile = NULL; return back; } /** Definition to allow the use of the sizeof() operator. */ typedef char *CHARPTR; /** Save configuration to preferences system. */ static void save_configuration DK_P0() { char buffer[32]; dkapp_set_pref(app,pn_blanks,((flags & FLAG_IGNORE_BLANKS) ? pv_on : pv_off)); dkapp_set_pref(app,pn_fold,((flags & FLAG_CASEINS) ? pv_on : pv_off)); dkapp_set_pref(app,pn_numeric,((flags & FLAG_NUMERIC) ? pv_on : pv_off)); dkapp_set_pref(app,pn_float,((flags & FLAG_NUMFLOAT) ? pv_on : pv_off)); dkapp_set_pref(app,pn_reverse,((flags & FLAG_REVERSED) ? pv_on : pv_off)); dkapp_set_pref(app,pn_unique,((flags & FLAG_UNIQUE) ? pv_on : pv_off)); if(outputname) { dkapp_set_pref(app,pn_output,outputname); } sprintf(buffer, "%d", linelength); dkapp_set_pref(app, pn_ll, buffer); } /** Print a string right aligned. @param str String to print. @param max Available space for string. */ static void print_string_right_aligned DK_P2(char *,str,size_t, max) { size_t i; i = 0; if(str) { i = dkapp_prlen(app, str); } while(i++ < max) fputc(' ', stdout); if(str) dkapp_stdout(app,str); } /** Three spaces are used before and after the option value. */ static char three_spaces[] = { " " }; /** Print a text option. @param key Option name. @param val Option value. @param desc Option description. @param max Available space for option value. */ static void print_string_option DK_P4(char *, key, char *, val, char *, desc, size_t, max) { dkapp_stdout(app, key); fputs(three_spaces, stdout); print_string_right_aligned(val, max); fputs(three_spaces, stdout); dkapp_stdout(app, desc); fputc('\n', stdout); } /** Print a boolean option. @param key Option name. @param val Option value. @param desc Option description. @param max Maximum space for value. */ static void print_bool_option DK_P4(char *, key, int, val, char *, desc, size_t, max) { dkapp_stdout(app, key); fputs(three_spaces, stdout); print_string_right_aligned((val ? ksort_str[7] : ksort_str[8]), max); fputs(three_spaces, stdout); dkapp_stdout(app,desc); fputc('\n', stdout); } /** Find maximum length of multiple strings. @param str One string to process. @param old Maximum of analized strings already processed. @return Maximum of \a old and the length of \a str. */ static size_t find_max_string_length DK_P2(char *,str,size_t, old) { size_t i; size_t back; back = old; if(str) { i = dkapp_prlen(app, str); if(i > back) back = i; } return back; } /** Show configuration. */ static void show_configuration DK_P0() { char llbuffer[32]; size_t max; sprintf(llbuffer, "%d", linelength); max = 0; max = find_max_string_length(llbuffer, max); max = find_max_string_length(ksort_str[7], max); max = find_max_string_length(ksort_str[8], max); dkapp_stdout(app, ksort_str[16]); fputc('\n', stdout); print_bool_option("-b", (flags & FLAG_IGNORE_BLANKS), ksort_str[10], max); print_bool_option("-d", (flags & FLAG_NUMERIC), ksort_str[11], max); print_bool_option("-f", (flags & FLAG_NUMFLOAT), ksort_str[12], max); print_bool_option("-i", (flags & FLAG_REVERSED), ksort_str[13], max); print_bool_option("-m", (flags & FLAG_UNIQUE), ksort_str[14], max); print_bool_option("-n", (flags & FLAG_CASEINS), ksort_str[15], max); print_string_option("-l", llbuffer, ksort_str[9], max); } /** The real main function which is run after creating the application. @param argc Number of command line arguments. @param argv Command line arguments array. @return 1 on success, 0 on error. */ static int run_main DK_P2(int, argc, char **, argv) { int back = 0; LineInfo *li; char *s; int i; char *logmsg[3]; if(argv) { filenames = dk_new(CHARPTR,argc); if(filenames) { for(i = 0; i < argc; i++) { filenames[i] = NULL; } lines = dksto_open(0); if(lines) { linesit = dksto_it_open(lines); if(linesit) { if(process_args(argc,argv)) { i = FLAG_HELP | FLAG_VERSION | FLAG_CONFIGURE | FLAG_SHOWCONF; if(flags & i) { if(flags & (FLAG_HELP | FLAG_VERSION)) { if(flags & FLAG_VERSION) { print_version(); } if(flags & FLAG_HELP) { dkapp_help(app, "ksort.txt", help_text); } } else { if(flags & FLAG_CONFIGURE) { if(!(flags & FLAG_UNCONF)) { save_configuration(); show_configuration(); } } else { if(flags & FLAG_SHOWCONF) { show_configuration(); } } } } else { dksto_set_comp(lines, compare_data, 0); back = 1; if(!read_input()) { back = 0; } if(!write_output()) { back = 0; } dksto_it_reset(linesit); if(flags & (FLAG_NUMERIC | FLAG_NUMFLOAT)) { while((li = (LineInfo *)dksto_it_next(linesit)) != NULL) { s = li->line; dk_delete(s); li->line = NULL; li->vf = 0; li->lv = 0L; li->dv = 0.0; dk_delete(li); } } else { while((s = (char *)dksto_it_next(linesit)) != NULL) { dk_delete(s); } } } } if(outputname) { dk_delete(outputname); outputname = NULL; } dksto_it_close(linesit); } else { dkapp_log_msg(app, DK_LOG_LEVEL_ERROR, logmsg, 1); } dksto_close(lines); } else { dkapp_log_msg(app, DK_LOG_LEVEL_ERROR, logmsg, 1); } for(i = 0; i < argc; i++) { filenames[i] = NULL; } dk_delete(filenames); } else { dkapp_log_msg(app, DK_LOG_LEVEL_ERROR, logmsg, 1); } } return back; } /** The main() function of the ksort program. @param argc Number of command line arguments. @param argv Command line arguments array. @return 0 on success, any other value indicates an error. */ #if DK_HAVE_PROTOTYPES int main(int argc, char *argv[]) #else int main(argc, argv) int argc; char *argv[]; #endif { int exval = 0; #line 1451 "ksort.ctr" app = dkapp_open_ext1(argc, argv, packagename, sysconfdir, 0, 0); if(app) { dkapp_find_multi(app, ksort_find, "ksort"); exval = run_main(dkapp_get_argc(app), dkapp_get_argv(app)); dkapp_close(app); app = NULL; } else { if(!dkapp_silence_check(argc,argv)) { fprintf(stderr, "ERROR: NOT ENOUGH MEMORY\n"); fflush(stderr); } } #line 1464 "ksort.ctr" exval = (exval ? 1 : 0); exit(exval); return exval; }