source: git/src/sorterr.c

Last change on this file was ae917b96, checked in by Olly Betts <olly@…>, 4 months ago

Simplify allocation functions

We don't need the xosmalloc(), osfree(), etc as the memory allocation
on a modern OS isn't limited in the size it can allocate by default.

  • 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
33static const struct option long_opts[] = {
34   /* const char *name; int has_arg (0 no_argument, 1 required_*, 2 optional_*); int *flag; int val; */
35   {"horizontal", no_argument, 0, 'h'},
36   {"vertical", no_argument, 0, 'v'},
37   {"percentage", no_argument, 0, 'p'},
38   {"per-leg", no_argument, 0, 'l'},
39   {"replace", no_argument, 0, 'r'},
40   {"help", no_argument, 0, HLP_HELP},
41   {"version", no_argument, 0, HLP_VERSION},
42   {0, 0, 0, 0}
43};
44
45#define short_opts "hvplr"
46
47static struct help_msg help[] = {
48/*                              <-- */
49   /* TRANSLATORS: --help output for sorterr --horizontal option */
50   {HLP_ENCODELONG(0),        /*sort by horizontal error factor*/179, 0, 0},
51   /* TRANSLATORS: --help output for sorterr --vertical option */
52   {HLP_ENCODELONG(1),        /*sort by vertical error factor*/180, 0, 0},
53   /* TRANSLATORS: --help output for sorterr --percentage option */
54   {HLP_ENCODELONG(2),        /*sort by percentage error*/181, 0, 0},
55   /* TRANSLATORS: --help output for sorterr --per-leg option */
56   {HLP_ENCODELONG(3),        /*sort by error per leg*/182, 0, 0},
57   /* TRANSLATORS: --help output for sorterr --replace option */
58   {HLP_ENCODELONG(4),        /*replace .err file with re-sorted version*/183, 0, 0},
59   {0, 0, 0, 0}
60};
61
62typedef struct {
63   double err;
64   long fpos;
65} trav;
66
67static void
68skipline(const char *fnm, FILE *fh)
69{
70   int ch;
71   do {
72      ch = GETC(fh);
73   } while (ch != '\n' && ch != EOF);
74
75   if (ch == EOF) {
76      if (FERROR(fh))
77         fatalerror_in_file(fnm, 0, /*Error reading file*/18);
78      fatalerror_in_file(fnm, 0, /*Couldn’t parse .err file*/112);
79   }
80}
81
82static void
83printline(const char *fnm, FILE *fh, FILE *fh_out)
84{
85   int ch;
86   do {
87      ch = GETC(fh);
88      if (ch != EOF && ch != '\r' && ch != '\n') PUTC(ch, fh_out);
89   } while (ch != '\n' && ch != EOF);
90   PUTC('\n', fh_out);
91
92   if (ch == EOF) {
93      if (FERROR(fh))
94         fatalerror_in_file(fnm, 0, /*Error reading file*/18);
95      fatalerror_in_file(fnm, 0, /*Couldn’t parse .err file*/112);
96   }
97}
98
99static int
100cmp_trav(const void *a, const void *b)
101{
102   double diff = ((const trav *)a)->err - ((const trav *)b)->err;
103   if (diff < 0) return -1;
104   if (diff > 0) return 1;
105   return 0;
106}
107
108int
109main(int argc, char **argv)
110{
111   char *fnm;
112   FILE *fh;
113   char sortby = 'A';
114   size_t len = 1024;
115   trav *blk = osmalloc(1024 * sizeof(trav));
116   size_t next = 0;
117   size_t howmany = 0;
118   FILE *fh_out = stdout;
119   char *fnm_out = NULL;
120
121   msg_init(argv);
122
123   /* TRANSLATORS: Part of sorterr --help */
124   cmdline_set_syntax_message(/*ERR_FILE [HOW_MANY]*/268, 0, NULL);
125   cmdline_init(argc, argv, short_opts, long_opts, NULL, help, 1, 2);
126   while (1) {
127      int opt = cmdline_getopt();
128      if (opt == EOF) break;
129      switch (opt) {
130       case 'h': case 'v': case 'p': case 'l':
131         sortby = toupper(opt);
132         break;
133       case 'r':
134         fh_out = NULL;
135         break;
136      }
137   }
138
139   fnm = argv[optind++];
140   if (argv[optind]) howmany = atoi(argv[optind]);
141
142   fh = fopen(fnm, "rb");
143   if (!fh) fatalerror(/*Couldn’t open file “%s”*/1, fnm);
144
145   /* 4 line paragraphs, separated by blank lines...
146    * 041.verhall.12 - 041.verhall.13
147    * Original length   2.97m (  1 legs), moved   0.04m ( 0.04m/leg). Error   1.19%
148    * 0.222332
149    * H: 0.224749 V: 0.215352
150    *
151    */
152   while (1) {
153      int ch;
154      if (next == len) {
155         len += len;
156         blk = osrealloc(blk, len * sizeof(trav));
157      }
158      blk[next].fpos = ftell(fh);
159      ch = GETC(fh);
160      if (ch == EOF) break;
161      skipline(fnm, fh);
162      switch (sortby) {
163       case 'A':
164         skipline(fnm, fh);
165         if (fscanf(fh, "%lf", &blk[next].err) != 1) {
166            baderrfile:
167            fatalerror_in_file(fnm, 0, /*Couldn’t parse .err file*/112);
168         }
169         skipline(fnm, fh);
170         skipline(fnm, fh);
171         break;
172       case 'H': case 'V':
173         skipline(fnm, fh);
174         skipline(fnm, fh);
175         do {
176            ch = GETC(fh);
177            if (ch == '\n' || ch == EOF) goto baderrfile;
178         } while (ch != sortby);
179         if (fscanf(fh, ":%lf", &blk[next].err) != 1) goto baderrfile;
180         skipline(fnm, fh);
181         break;
182       case 'P':
183         do {
184            ch = GETC(fh);
185            if (ch == '\n' || ch == EOF) goto baderrfile;
186         } while (ch != ')');
187         do {
188            ch = GETC(fh);
189            if (ch == '\n' || ch == EOF) goto baderrfile;
190         } while (ch != ')');
191         do {
192            ch = GETC(fh);
193            if (ch == '\n' || ch == EOF) goto baderrfile;
194         } while (!isdigit(ch));
195         ungetc(ch, fh);
196         if (fscanf(fh, "%lf", &blk[next].err) != 1) goto baderrfile;
197         skipline(fnm, fh);
198         skipline(fnm, fh);
199         skipline(fnm, fh);
200         break;
201       case 'L':
202         do {
203            ch = GETC(fh);
204            if (ch == '\n' || ch == EOF) goto baderrfile;
205         } while (ch != ')');
206         do {
207            ch = GETC(fh);
208            if (ch == '\n' || ch == EOF) goto baderrfile;
209         } while (ch != '(');
210         if (fscanf(fh, "%lf", &blk[next].err) != 1) goto baderrfile;
211         skipline(fnm, fh);
212         skipline(fnm, fh);
213         skipline(fnm, fh);
214         break;
215      }
216      skipline(fnm, fh);
217      next++;
218   }
219
220   if (next == 0) {
221      /* no entries - nothing more to do whether -r is specified or not */
222      exit(EXIT_SUCCESS);
223   }
224
225   qsort(blk, next, sizeof(trav), cmp_trav);
226
227   if (fh_out == NULL) {
228      char *base = base_from_fnm(fnm);
229      fnm_out = add_ext(base, "tmp");
230      free(base);
231      fh_out = safe_fopen(fnm_out, "w");
232   }
233
234   do {
235      --next;
236      if (fseek(fh, blk[next].fpos, SEEK_SET) == -1)
237         fatalerror_in_file(fnm, 0, /*Error reading file*/18);
238
239      printline(fnm, fh, fh_out);
240      printline(fnm, fh, fh_out);
241      printline(fnm, fh, fh_out);
242      printline(fnm, fh, fh_out);
243      PUTC('\n', fh_out);
244      if (howmany && --howmany == 0) break;
245   } while (next);
246   fclose(fh);
247
248   if (fnm_out) {
249      safe_fclose(fh_out);
250#ifdef _WIN32
251      /* UNIX rename atomically replaces, so doesn't need this.
252       * WIN32 won't overwrite (from tests) so needs this code.
253       */
254      remove(fnm);
255#endif
256      rename(fnm_out, fnm);
257   }
258
259   return 0;
260}
Note: See TracBrowser for help on using the repository browser.