source: git/src/sorterr.c

walls-data
Last change on this file was 4c83f84, checked in by Olly Betts <olly@…>, 6 days ago

Don't check HAVE_CONFIG_H in most cases

This check is only useful for img.c, which is intended to be usable
outside of Survex (and had fallbacks for functions which may not be
available which will get used if built in a non-autotools project).
For all the other source files it's just useless boilerplate.

  • Property mode set to 100644
File size: 6.8 KB
Line 
1/* sorterr.c */
2/* Sort a survex .err file */
3/* Copyright (C) 2001,2002,2005,2010,2011,2014 Olly Betts
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
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18 */
19
20#include <config.h>
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"
29#include "filename.h"
30#include "message.h"
31#include "osalloc.h"
32#include "whichos.h"
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'},
40   {"replace", no_argument, 0, 'r'},
41   {"help", no_argument, 0, HLP_HELP},
42   {"version", no_argument, 0, HLP_VERSION},
43   {0, 0, 0, 0}
44};
45
46#define short_opts "hvplr"
47
48static struct help_msg help[] = {
49/*                              <-- */
50   /* TRANSLATORS: --help output for sorterr --horizontal option */
51   {HLP_ENCODELONG(0),        /*sort by horizontal error factor*/179, 0},
52   /* TRANSLATORS: --help output for sorterr --vertical option */
53   {HLP_ENCODELONG(1),        /*sort by vertical error factor*/180, 0},
54   /* TRANSLATORS: --help output for sorterr --percentage option */
55   {HLP_ENCODELONG(2),        /*sort by percentage error*/181, 0},
56   /* TRANSLATORS: --help output for sorterr --per-leg option */
57   {HLP_ENCODELONG(3),        /*sort by error per leg*/182, 0},
58   /* TRANSLATORS: --help output for sorterr --replace option */
59   {HLP_ENCODELONG(4),        /*replace .err file with resorted version*/183, 0},
60   {0, 0, 0}
61};
62
63typedef struct {
64   double err;
65   long fpos;
66} trav;
67
68static void
69skipline(const char *fnm, FILE *fh)
70{
71   int ch;
72   do {
73      ch = GETC(fh);
74   } while (ch != '\n' && ch != EOF);
75
76   if (ch == EOF) {
77      if (ferror(fh))
78         fatalerror_in_file(fnm, 0, /*Error reading file*/18);
79      fatalerror_in_file(fnm, 0, /*Couldn’t parse .err file*/112);
80   }
81}
82
83static void
84printline(const char *fnm, FILE *fh, FILE *fh_out)
85{
86   int ch;
87   do {
88      ch = GETC(fh);
89      if (ch != EOF && ch != '\r' && ch != '\n') PUTC(ch, fh_out);
90   } while (ch != '\n' && ch != EOF);
91   PUTC('\n', fh_out);
92
93   if (ch == EOF) {
94      if (ferror(fh))
95         fatalerror_in_file(fnm, 0, /*Error reading file*/18);
96      fatalerror_in_file(fnm, 0, /*Couldn’t parse .err file*/112);
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;
119   FILE *fh_out = stdout;
120   char *fnm_out = NULL;
121
122   msg_init(argv);
123
124   /* TRANSLATORS: Part of sorterr --help */
125   cmdline_set_syntax_message(/*ERR_FILE [HOW_MANY]*/268, 0, NULL);
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;
134       case 'r':
135         fh_out = NULL;
136         break;
137      }
138   }
139
140   fnm = argv[optind++];
141   if (argv[optind]) howmany = atoi(argv[optind]);
142
143   fh = fopen(fnm, "rb");
144   if (!fh) fatalerror(/*Couldn’t open file “%s”*/24, fnm);
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;
157         blk = osrealloc(blk, len * ossizeof(trav));
158      }
159      blk[next].fpos = ftell(fh);
160      ch = GETC(fh);
161      if (ch == EOF) break;
162      skipline(fnm, fh);
163      switch (sortby) {
164       case 'A':
165         skipline(fnm, fh);
166         if (fscanf(fh, "%lf", &blk[next].err) != 1) {
167            baderrfile:
168            fatalerror_in_file(fnm, 0, /*Couldn’t parse .err file*/112);
169         }
170         skipline(fnm, fh);
171         skipline(fnm, fh);
172         break;
173       case 'H': case 'V':
174         skipline(fnm, fh);
175         skipline(fnm, fh);
176         do {
177            ch = GETC(fh);
178            if (ch == '\n' || ch == EOF) goto baderrfile;
179         } while (ch != sortby);
180         if (fscanf(fh, ":%lf", &blk[next].err) != 1) goto baderrfile;
181         skipline(fnm, fh);
182         break;
183       case 'P':
184         do {
185            ch = GETC(fh);
186            if (ch == '\n' || ch == EOF) goto baderrfile;
187         } while (ch != ')');
188         do {
189            ch = GETC(fh);
190            if (ch == '\n' || ch == EOF) goto baderrfile;
191         } while (ch != ')');
192         do {
193            ch = GETC(fh);
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;
198         skipline(fnm, fh);
199         skipline(fnm, fh);
200         skipline(fnm, fh);
201         break;
202       case 'L':
203         do {
204            ch = GETC(fh);
205            if (ch == '\n' || ch == EOF) goto baderrfile;
206         } while (ch != ')');
207         do {
208            ch = GETC(fh);
209            if (ch == '\n' || ch == EOF) goto baderrfile;
210         } while (ch != '(');
211         if (fscanf(fh, "%lf", &blk[next].err) != 1) goto baderrfile;
212         skipline(fnm, fh);
213         skipline(fnm, fh);
214         skipline(fnm, fh);
215         break;
216      }
217      skipline(fnm, fh);
218      next++;
219   }
220
221   if (next == 0) {
222      /* no entries - nothing more to do whether -r is specified or not */
223      exit(EXIT_SUCCESS);
224   }
225
226   qsort(blk, next, sizeof(trav), cmp_trav);
227
228   if (fh_out == NULL) {
229      char *base = base_from_fnm(fnm);
230      fnm_out = add_ext(base, "tmp");
231      osfree(base);
232      fh_out = safe_fopen(fnm_out, "w");
233   }
234
235   do {
236      --next;
237      if (fseek(fh, blk[next].fpos, SEEK_SET) == -1)
238         fatalerror_in_file(fnm, 0, /*Error reading file*/18);
239
240      printline(fnm, fh, fh_out);
241      printline(fnm, fh, fh_out);
242      printline(fnm, fh, fh_out);
243      printline(fnm, fh, fh_out);
244      PUTC('\n', fh_out);
245      if (howmany && --howmany == 0) break;
246   } while (next);
247   fclose(fh);
248
249   if (fnm_out) {
250      safe_fclose(fh_out);
251#if OS_WIN32
252      /* UNIX rename atomically replaces, so doesn't need this.
253       * WIN32 won't overwrite (from tests) so needs this code.
254       */
255      remove(fnm);
256#endif
257      rename(fnm_out, fnm);
258   }
259
260   return 0;
261}
Note: See TracBrowser for help on using the repository browser.