source: git/src/sorterr.c @ 870439d

RELEASE/1.0
Last change on this file since 870439d was 870439d, checked in by Olly Betts <olly@…>, 13 years ago

Backport change from 1.2.0:
src/: Use GETC() and PUTC() everywhere.

git-svn-id: file:///home/survex-svn/survex/branches/1.0@3709 4b37db11-9a0c-4f06-9ece-9ab7cdaee568

  • Property mode set to 100644
File size: 6.7 KB
RevLine 
[d06141c]1/* sorterr.c */
2/* Sort a survex .err file */
[fa42426]3/* Copyright (C) 2001,2002 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
[1b71c05]17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
[d06141c]18 */
19
20#ifdef HAVE_CONFIG_H
21# include <config.h>
22#endif
23
24#include <ctype.h>
25#include <math.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29
30#include "cmdline.h"
[fa42426]31#include "filename.h"
[bfe1242]32#include "message.h"
[d06141c]33#include "osalloc.h"
[5baea35]34#include "whichos.h"
[d06141c]35
36static const struct option long_opts[] = {
37   /* const char *name; int has_arg (0 no_argument, 1 required_*, 2 optional_*); int *flag; int val; */
38   {"horizontal", no_argument, 0, 'h'},
39   {"vertical", no_argument, 0, 'v'},
40   {"percentage", no_argument, 0, 'p'},
41   {"per-leg", no_argument, 0, 'l'},
[059d065]42   {"replace", no_argument, 0, 'r'},
[d06141c]43   {"help", no_argument, 0, HLP_HELP},
44   {"version", no_argument, 0, HLP_VERSION},
45   {0, 0, 0, 0}
46};
47
[059d065]48#define short_opts "hvplr"
[d06141c]49
50static struct help_msg help[] = {
51/*                              <-- */
[547d9ed]52   {HLP_ENCODELONG(0),          "Sort by horizontal error factor"},
53   {HLP_ENCODELONG(1),          "Sort by vertical error factor"},
54   {HLP_ENCODELONG(2),          "Sort by percentage error"},
55   {HLP_ENCODELONG(3),          "Sort by error per leg"},
[059d065]56   {HLP_ENCODELONG(4),          "Replace .err file with resorted version"},
[d06141c]57   {0, 0}
58};
59
60typedef struct {
61   double err;
62   long fpos;
63} trav;
64
65static void
[dcf6125]66skipline(const char *fnm, FILE *fh)
[d06141c]67{
68   int ch;
69   do {
[870439d]70      ch = GETC(fh);
[d06141c]71   } while (ch != '\n' && ch != EOF);
[dcf6125]72
[d06141c]73   if (ch == EOF) {
[dcf6125]74      if (ferror(fh))
75         fatalerror_in_file(fnm, 0, /*Error reading file*/18);
76      fatalerror_in_file(fnm, 0, /*Couldn't parse .err file*/112);
[d06141c]77   }
78}
79
80static void
[dcf6125]81printline(const char *fnm, FILE *fh, FILE *fh_out)
[d06141c]82{
83   int ch;
84   do {
[870439d]85      ch = GETC(fh);
86      if (ch != EOF && ch != '\r' && ch != '\n') PUTC(ch, fh_out);
[d06141c]87   } while (ch != '\n' && ch != EOF);
[870439d]88   PUTC('\n', fh_out);
[dcf6125]89
[d06141c]90   if (ch == EOF) {
[dcf6125]91      if (ferror(fh))
92         fatalerror_in_file(fnm, 0, /*Error reading file*/18);
93      fatalerror_in_file(fnm, 0, /*Couldn't parse .err file*/112);
[d06141c]94   }
95}
96
97static int
98cmp_trav(const void *a, const void *b)
99{
100   double diff = ((const trav *)a)->err - ((const trav *)b)->err;
101   if (diff < 0) return -1;
102   if (diff > 0) return 1;
103   return 0;
104}
105
106int
107main(int argc, char **argv)
108{
109   char *fnm;
110   FILE *fh;
111   char sortby = 'A';
112   size_t len = 1024;
113   trav *blk = osmalloc(1024 * sizeof(trav));
114   size_t next = 0;
115   size_t howmany = 0;
[059d065]116   FILE *fh_out = stdout;
117   char *fnm_out = NULL;
[d06141c]118
[bdfe97f]119   msg_init(argv);
[d06141c]120
[6912d74]121   cmdline_set_syntax_message("ERR_FILE [HOW MANY]", NULL); /* TRANSLATE */
[d06141c]122   cmdline_init(argc, argv, short_opts, long_opts, NULL, help, 1, 2);
123   while (1) {
124      int opt = cmdline_getopt();
125      if (opt == EOF) break;
126      switch (opt) {
127       case 'h': case 'v': case 'p': case 'l':
128         sortby = toupper(opt);
129         break;
[059d065]130       case 'r':
131         fh_out = NULL;
132         break;
[d06141c]133      }
134   }
135
136   fnm = argv[optind++];
137   if (argv[optind]) howmany = atoi(argv[optind]);
138
139   fh = fopen(fnm, "rb");
[bfe1242]140   if (!fh) fatalerror(/*Couldn't open file `%s'*/93, fnm);
[d06141c]141
142   /* 4 line paragraphs, separated by blank lines...
143    * 041.verhall.12 - 041.verhall.13
144    * Original length   2.97m (  1 legs), moved   0.04m ( 0.04m/leg). Error   1.19%
145    * 0.222332
146    * H: 0.224749 V: 0.215352
147    *
148    */
149   while (1) {
150      int ch;
151      if (next == len) {
152         len += len;
[dd5a89c]153         blk = osrealloc(blk, len * ossizeof(trav));
[d06141c]154      }
[e03662e]155      blk[next].fpos = ftell(fh);
[870439d]156      ch = GETC(fh);
[d06141c]157      if (ch == EOF) break;
[dcf6125]158      skipline(fnm, fh);
[d06141c]159      switch (sortby) {
160       case 'A':
[dcf6125]161         skipline(fnm, fh);
[d06141c]162         if (fscanf(fh, "%lf", &blk[next].err) != 1) {
163            baderrfile:
[908298d]164            fatalerror_in_file(fnm, 0, /*Couldn't parse .err file*/112);
[d06141c]165         }
[dcf6125]166         skipline(fnm, fh);
167         skipline(fnm, fh);
[d06141c]168         break;
169       case 'H': case 'V':
[dcf6125]170         skipline(fnm, fh);
171         skipline(fnm, fh);
[d06141c]172         do {
[870439d]173            ch = GETC(fh);
[d06141c]174            if (ch == '\n' || ch == EOF) goto baderrfile;
175         } while (ch != sortby);
176         if (fscanf(fh, ":%lf", &blk[next].err) != 1) goto baderrfile;
[dcf6125]177         skipline(fnm, fh);
[d06141c]178         break;
179       case 'P':
180         do {
[870439d]181            ch = GETC(fh);
[d06141c]182            if (ch == '\n' || ch == EOF) goto baderrfile;
183         } while (ch != ')');
184         do {
[870439d]185            ch = GETC(fh);
[d06141c]186            if (ch == '\n' || ch == EOF) goto baderrfile;
187         } while (ch != ')');
188         do {
[870439d]189            ch = GETC(fh);
[d06141c]190            if (ch == '\n' || ch == EOF) goto baderrfile;
191         } while (!isdigit(ch));
192         ungetc(ch, fh);
193         if (fscanf(fh, "%lf", &blk[next].err) != 1) goto baderrfile;
[dcf6125]194         skipline(fnm, fh);
195         skipline(fnm, fh);
196         skipline(fnm, fh);
[d06141c]197         break;
198       case 'L':
199         do {
[870439d]200            ch = GETC(fh);
[d06141c]201            if (ch == '\n' || ch == EOF) goto baderrfile;
202         } while (ch != ')');
203         do {
[870439d]204            ch = GETC(fh);
[d06141c]205            if (ch == '\n' || ch == EOF) goto baderrfile;
206         } while (ch != '(');
207         if (fscanf(fh, "%lf", &blk[next].err) != 1) goto baderrfile;
[dcf6125]208         skipline(fnm, fh);
209         skipline(fnm, fh);
210         skipline(fnm, fh);
[d06141c]211         break;
212      }
[dcf6125]213      skipline(fnm, fh);
[d06141c]214      next++;
215   }
216
[5baea35]217   if (next == 0) {
218      /* no entries - nothing more to do whether -r is specified or not */
219      exit(EXIT_SUCCESS);
220   }
221
[d06141c]222   qsort(blk, next, sizeof(trav), cmp_trav);
223
[059d065]224   if (fh_out == NULL) {
225      char *base = base_from_fnm(fnm);
226      fnm_out = add_ext(base, "tmp");
227      osfree(base);
[893cc20]228      fh_out = safe_fopen(fnm_out, "w");
[059d065]229   }
230
[d06141c]231   do {
232      --next;
[908298d]233      if (fseek(fh, blk[next].fpos, SEEK_SET) == -1)
234         fatalerror_in_file(fnm, 0, /*Error reading file*/18);
235
[dcf6125]236      printline(fnm, fh, fh_out);
237      printline(fnm, fh, fh_out);
238      printline(fnm, fh, fh_out);
239      printline(fnm, fh, fh_out);
[870439d]240      PUTC('\n', fh_out);
[d06141c]241      if (howmany && --howmany == 0) break;
242   } while (next);
[e5d7e205]243   fclose(fh);
[d06141c]244
[059d065]245   if (fnm_out) {
[f1067a2]246      safe_fclose(fh_out);
[1d89197]247#if (OS!=UNIX) && !defined(__DJGPP__)
248      /* UNIX rename atomically replaces, so doesn't need this.
249       * DJGPP "removes destination first if it exists" according to docs
250       *    (testing confirms this) so doesn't need this.
251       * BorlandC won't overwrite (from tests) so needs this code
252       * WIN32 won't overwrite (from tests) so needs this code.
253       * RISC OS won't overwrite on some filing systems, 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.