source: git/src/sorterr.c @ 350a042

stereo-2025
Last change on this file since 350a042 was 1a6692f, checked in by Olly Betts <olly@…>, 12 months ago

Minor improvements to --help output

  • Property mode set to 100644
File size: 6.8 KB
RevLine 
[d06141c]1/* sorterr.c */
2/* Sort a survex .err file */
[736f7df]3/* Copyright (C) 2001,2002,2005,2010,2011,2014 Olly Betts
[d06141c]4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
[ecbc6c18]17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
[d06141c]18 */
19
[4c83f84]20#include <config.h>
[d06141c]21
22#include <ctype.h>
23#include <math.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27
28#include "cmdline.h"
[fa42426]29#include "filename.h"
[bfe1242]30#include "message.h"
[d06141c]31#include "osalloc.h"
[5baea35]32#include "whichos.h"
[d06141c]33
34static const struct option long_opts[] = {
35   /* const char *name; int has_arg (0 no_argument, 1 required_*, 2 optional_*); int *flag; int val; */
36   {"horizontal", no_argument, 0, 'h'},
37   {"vertical", no_argument, 0, 'v'},
38   {"percentage", no_argument, 0, 'p'},
39   {"per-leg", no_argument, 0, 'l'},
[059d065]40   {"replace", no_argument, 0, 'r'},
[d06141c]41   {"help", no_argument, 0, HLP_HELP},
42   {"version", no_argument, 0, HLP_VERSION},
43   {0, 0, 0, 0}
44};
45
[059d065]46#define short_opts "hvplr"
[d06141c]47
48static struct help_msg help[] = {
49/*                              <-- */
[736f7df]50   /* TRANSLATORS: --help output for sorterr --horizontal option */
[45af761]51   {HLP_ENCODELONG(0),        /*sort by horizontal error factor*/179, 0},
[736f7df]52   /* TRANSLATORS: --help output for sorterr --vertical option */
[45af761]53   {HLP_ENCODELONG(1),        /*sort by vertical error factor*/180, 0},
[736f7df]54   /* TRANSLATORS: --help output for sorterr --percentage option */
[45af761]55   {HLP_ENCODELONG(2),        /*sort by percentage error*/181, 0},
[736f7df]56   /* TRANSLATORS: --help output for sorterr --per-leg option */
[45af761]57   {HLP_ENCODELONG(3),        /*sort by error per leg*/182, 0},
[736f7df]58   /* TRANSLATORS: --help output for sorterr --replace option */
[1a6692f]59   {HLP_ENCODELONG(4),        /*replace .err file with re-sorted version*/183, 0},
[45af761]60   {0, 0, 0}
[d06141c]61};
62
63typedef struct {
64   double err;
65   long fpos;
66} trav;
67
68static void
[dcf6125]69skipline(const char *fnm, FILE *fh)
[d06141c]70{
71   int ch;
72   do {
[e02a6a6]73      ch = GETC(fh);
[d06141c]74   } while (ch != '\n' && ch != EOF);
[dcf6125]75
[d06141c]76   if (ch == EOF) {
[dcf6125]77      if (ferror(fh))
78         fatalerror_in_file(fnm, 0, /*Error reading file*/18);
[ee7511a]79      fatalerror_in_file(fnm, 0, /*Couldn’t parse .err file*/112);
[d06141c]80   }
81}
82
83static void
[dcf6125]84printline(const char *fnm, FILE *fh, FILE *fh_out)
[d06141c]85{
86   int ch;
87   do {
[e02a6a6]88      ch = GETC(fh);
89      if (ch != EOF && ch != '\r' && ch != '\n') PUTC(ch, fh_out);
[d06141c]90   } while (ch != '\n' && ch != EOF);
[e02a6a6]91   PUTC('\n', fh_out);
[dcf6125]92
[d06141c]93   if (ch == EOF) {
[dcf6125]94      if (ferror(fh))
95         fatalerror_in_file(fnm, 0, /*Error reading file*/18);
[ee7511a]96      fatalerror_in_file(fnm, 0, /*Couldn’t parse .err file*/112);
[d06141c]97   }
98}
99
100static int
101cmp_trav(const void *a, const void *b)
102{
103   double diff = ((const trav *)a)->err - ((const trav *)b)->err;
104   if (diff < 0) return -1;
105   if (diff > 0) return 1;
106   return 0;
107}
108
109int
110main(int argc, char **argv)
111{
112   char *fnm;
113   FILE *fh;
114   char sortby = 'A';
115   size_t len = 1024;
116   trav *blk = osmalloc(1024 * sizeof(trav));
117   size_t next = 0;
118   size_t howmany = 0;
[059d065]119   FILE *fh_out = stdout;
120   char *fnm_out = NULL;
[d06141c]121
[bdfe97f]122   msg_init(argv);
[d06141c]123
[736f7df]124   /* TRANSLATORS: Part of sorterr --help */
[a7b5554]125   cmdline_set_syntax_message(/*ERR_FILE [HOW_MANY]*/268, 0, NULL);
[d06141c]126   cmdline_init(argc, argv, short_opts, long_opts, NULL, help, 1, 2);
127   while (1) {
128      int opt = cmdline_getopt();
129      if (opt == EOF) break;
130      switch (opt) {
131       case 'h': case 'v': case 'p': case 'l':
132         sortby = toupper(opt);
133         break;
[059d065]134       case 'r':
135         fh_out = NULL;
136         break;
[d06141c]137      }
138   }
139
140   fnm = argv[optind++];
141   if (argv[optind]) howmany = atoi(argv[optind]);
142
143   fh = fopen(fnm, "rb");
[ffee37e]144   if (!fh) fatalerror(/*Couldn’t open file “%s”*/24, fnm);
[d06141c]145
146   /* 4 line paragraphs, separated by blank lines...
147    * 041.verhall.12 - 041.verhall.13
148    * Original length   2.97m (  1 legs), moved   0.04m ( 0.04m/leg). Error   1.19%
149    * 0.222332
150    * H: 0.224749 V: 0.215352
151    *
152    */
153   while (1) {
154      int ch;
155      if (next == len) {
156         len += len;
[dd5a89c]157         blk = osrealloc(blk, len * ossizeof(trav));
[d06141c]158      }
[e03662e]159      blk[next].fpos = ftell(fh);
[e02a6a6]160      ch = GETC(fh);
[d06141c]161      if (ch == EOF) break;
[dcf6125]162      skipline(fnm, fh);
[d06141c]163      switch (sortby) {
164       case 'A':
[dcf6125]165         skipline(fnm, fh);
[d06141c]166         if (fscanf(fh, "%lf", &blk[next].err) != 1) {
167            baderrfile:
[4340dae]168            fatalerror_in_file(fnm, 0, /*Couldn’t parse .err file*/112);
[d06141c]169         }
[dcf6125]170         skipline(fnm, fh);
171         skipline(fnm, fh);
[d06141c]172         break;
173       case 'H': case 'V':
[dcf6125]174         skipline(fnm, fh);
175         skipline(fnm, fh);
[d06141c]176         do {
[e02a6a6]177            ch = GETC(fh);
[d06141c]178            if (ch == '\n' || ch == EOF) goto baderrfile;
179         } while (ch != sortby);
180         if (fscanf(fh, ":%lf", &blk[next].err) != 1) goto baderrfile;
[dcf6125]181         skipline(fnm, fh);
[d06141c]182         break;
183       case 'P':
184         do {
[e02a6a6]185            ch = GETC(fh);
[d06141c]186            if (ch == '\n' || ch == EOF) goto baderrfile;
187         } while (ch != ')');
188         do {
[e02a6a6]189            ch = GETC(fh);
[d06141c]190            if (ch == '\n' || ch == EOF) goto baderrfile;
191         } while (ch != ')');
192         do {
[e02a6a6]193            ch = GETC(fh);
[d06141c]194            if (ch == '\n' || ch == EOF) goto baderrfile;
195         } while (!isdigit(ch));
196         ungetc(ch, fh);
197         if (fscanf(fh, "%lf", &blk[next].err) != 1) goto baderrfile;
[dcf6125]198         skipline(fnm, fh);
199         skipline(fnm, fh);
200         skipline(fnm, fh);
[d06141c]201         break;
202       case 'L':
203         do {
[e02a6a6]204            ch = GETC(fh);
[d06141c]205            if (ch == '\n' || ch == EOF) goto baderrfile;
206         } while (ch != ')');
207         do {
[e02a6a6]208            ch = GETC(fh);
[d06141c]209            if (ch == '\n' || ch == EOF) goto baderrfile;
210         } while (ch != '(');
211         if (fscanf(fh, "%lf", &blk[next].err) != 1) goto baderrfile;
[dcf6125]212         skipline(fnm, fh);
213         skipline(fnm, fh);
214         skipline(fnm, fh);
[d06141c]215         break;
216      }
[dcf6125]217      skipline(fnm, fh);
[d06141c]218      next++;
219   }
220
[5baea35]221   if (next == 0) {
222      /* no entries - nothing more to do whether -r is specified or not */
223      exit(EXIT_SUCCESS);
224   }
225
[d06141c]226   qsort(blk, next, sizeof(trav), cmp_trav);
227
[059d065]228   if (fh_out == NULL) {
229      char *base = base_from_fnm(fnm);
230      fnm_out = add_ext(base, "tmp");
231      osfree(base);
[893cc20]232      fh_out = safe_fopen(fnm_out, "w");
[059d065]233   }
234
[d06141c]235   do {
236      --next;
[908298d]237      if (fseek(fh, blk[next].fpos, SEEK_SET) == -1)
238         fatalerror_in_file(fnm, 0, /*Error reading file*/18);
239
[dcf6125]240      printline(fnm, fh, fh_out);
241      printline(fnm, fh, fh_out);
242      printline(fnm, fh, fh_out);
243      printline(fnm, fh, fh_out);
[e02a6a6]244      PUTC('\n', fh_out);
[d06141c]245      if (howmany && --howmany == 0) break;
246   } while (next);
[e5d7e205]247   fclose(fh);
[d06141c]248
[059d065]249   if (fnm_out) {
[f1067a2]250      safe_fclose(fh_out);
[affaeee]251#if OS_WIN32
[1d89197]252      /* UNIX rename atomically replaces, so doesn't need this.
253       * WIN32 won't overwrite (from tests) so needs this code.
254       */
[893cc20]255      remove(fnm);
256#endif
[059d065]257      rename(fnm_out, fnm);
258   }
259
[d06141c]260   return 0;
261}
Note: See TracBrowser for help on using the repository browser.