2 /* Sort a survex .err file */
3 /* Copyright (C) 2001,2002,2005,2010,2011,2014 Olly Betts
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.
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.
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
36 static 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'},
42 {"replace", no_argument
, 0, 'r'},
43 {"help", no_argument
, 0, HLP_HELP
},
44 {"version", no_argument
, 0, HLP_VERSION
},
48 #define short_opts "hvplr"
50 static struct help_msg help
[] = {
52 /* TRANSLATORS: --help output for sorterr --horizontal option */
53 {HLP_ENCODELONG(0), /*sort by horizontal error factor*/179, 0},
54 /* TRANSLATORS: --help output for sorterr --vertical option */
55 {HLP_ENCODELONG(1), /*sort by vertical error factor*/180, 0},
56 /* TRANSLATORS: --help output for sorterr --percentage option */
57 {HLP_ENCODELONG(2), /*sort by percentage error*/181, 0},
58 /* TRANSLATORS: --help output for sorterr --per-leg option */
59 {HLP_ENCODELONG(3), /*sort by error per leg*/182, 0},
60 /* TRANSLATORS: --help output for sorterr --replace option */
61 {HLP_ENCODELONG(4), /*replace .err file with resorted version*/183, 0},
71 skipline(const char *fnm
, FILE *fh
)
76 } while (ch
!= '\n' && ch
!= EOF
);
80 fatalerror_in_file(fnm
, 0, /*Error reading file*/18);
81 fatalerror_in_file(fnm
, 0, /*Couldn’t parse .err file*/112);
86 printline(const char *fnm
, FILE *fh
, FILE *fh_out
)
91 if (ch
!= EOF
&& ch
!= '\r' && ch
!= '\n') PUTC(ch
, fh_out
);
92 } while (ch
!= '\n' && ch
!= EOF
);
97 fatalerror_in_file(fnm
, 0, /*Error reading file*/18);
98 fatalerror_in_file(fnm
, 0, /*Couldn’t parse .err file*/112);
103 cmp_trav(const void *a
, const void *b
)
105 double diff
= ((const trav
*)a
)->err
- ((const trav
*)b
)->err
;
106 if (diff
< 0) return -1;
107 if (diff
> 0) return 1;
112 main(int argc
, char **argv
)
118 trav
*blk
= osmalloc(1024 * sizeof(trav
));
121 FILE *fh_out
= stdout
;
122 char *fnm_out
= NULL
;
126 /* TRANSLATORS: Part of sorterr --help */
127 cmdline_set_syntax_message(/*ERR_FILE [HOW_MANY]*/268, 0, NULL
);
128 cmdline_init(argc
, argv
, short_opts
, long_opts
, NULL
, help
, 1, 2);
130 int opt
= cmdline_getopt();
131 if (opt
== EOF
) break;
133 case 'h': case 'v': case 'p': case 'l':
134 sortby
= toupper(opt
);
142 fnm
= argv
[optind
++];
143 if (argv
[optind
]) howmany
= atoi(argv
[optind
]);
145 fh
= fopen(fnm
, "rb");
146 if (!fh
) fatalerror(/*Couldn’t open file “%s”*/24, fnm
);
148 /* 4 line paragraphs, separated by blank lines...
149 * 041.verhall.12 - 041.verhall.13
150 * Original length 2.97m ( 1 legs), moved 0.04m ( 0.04m/leg). Error 1.19%
152 * H: 0.224749 V: 0.215352
159 blk
= osrealloc(blk
, len
* ossizeof(trav
));
161 blk
[next
].fpos
= ftell(fh
);
163 if (ch
== EOF
) break;
168 if (fscanf(fh
, "%lf", &blk
[next
].err
) != 1) {
170 fatalerror_in_file(fnm
, 0, /*Couldn’t parse .err file*/112);
180 if (ch
== '\n' || ch
== EOF
) goto baderrfile
;
181 } while (ch
!= sortby
);
182 if (fscanf(fh
, ":%lf", &blk
[next
].err
) != 1) goto baderrfile
;
188 if (ch
== '\n' || ch
== EOF
) goto baderrfile
;
192 if (ch
== '\n' || ch
== EOF
) goto baderrfile
;
196 if (ch
== '\n' || ch
== EOF
) goto baderrfile
;
197 } while (!isdigit(ch
));
199 if (fscanf(fh
, "%lf", &blk
[next
].err
) != 1) goto baderrfile
;
207 if (ch
== '\n' || ch
== EOF
) goto baderrfile
;
211 if (ch
== '\n' || ch
== EOF
) goto baderrfile
;
213 if (fscanf(fh
, "%lf", &blk
[next
].err
) != 1) goto baderrfile
;
224 /* no entries - nothing more to do whether -r is specified or not */
228 qsort(blk
, next
, sizeof(trav
), cmp_trav
);
230 if (fh_out
== NULL
) {
231 char *base
= base_from_fnm(fnm
);
232 fnm_out
= add_ext(base
, "tmp");
234 fh_out
= safe_fopen(fnm_out
, "w");
239 if (fseek(fh
, blk
[next
].fpos
, SEEK_SET
) == -1)
240 fatalerror_in_file(fnm
, 0, /*Error reading file*/18);
242 printline(fnm
, fh
, fh_out
);
243 printline(fnm
, fh
, fh_out
);
244 printline(fnm
, fh
, fh_out
);
245 printline(fnm
, fh
, fh_out
);
247 if (howmany
&& --howmany
== 0) break;
254 /* UNIX rename atomically replaces, so doesn't need this.
255 * WIN32 won't overwrite (from tests) so needs this code.
259 rename(fnm_out
, fnm
);