source: git/src/cavern.c @ 02ac18d

RELEASE/1.0
Last change on this file since 02ac18d was 1b71c05, checked in by Olly Betts <olly@…>, 14 years ago

src/: Update FSF address in (C) notices in source files.

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

  • Property mode set to 100644
File size: 12.3 KB
Line 
1/* cavern.c
2 * SURVEX Cave surveying software: data reduction main and related functions
3 * Copyright (C) 1991-2003,2004,2005 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#ifdef HAVE_CONFIG_H
21#include <config.h>
22#endif
23
24#include <limits.h>
25#include <time.h>
26
27#include "cavern.h"
28#include "cmdline.h"
29#include "commands.h"
30#include "datain.h"
31#include "debug.h"
32#include "message.h"
33#include "filename.h"
34#include "filelist.h"
35#include "img.h"
36#include "listpos.h"
37#include "netbits.h"
38#include "netskel.h"
39#include "osdepend.h"
40#include "out.h"
41#include "str.h"
42#include "validate.h"
43
44#if (OS==WIN32)
45#include <conio.h> /* for _kbhit() and _getch() */
46#endif
47
48#ifdef CHASM3DX
49# if OS != RISCOS
50/* include header for getcwd() */
51#  if OS == MSDOS && !defined(__DJGPP__)
52#   include <dir.h>
53#  elif OS == WIN32
54#   include <direct.h>
55#  else
56#   include <unistd.h>
57#  endif
58#endif
59
60#ifndef MAXPATHLEN
61#define MAXPATHLEN 1024
62#endif
63#endif
64
65/* For funcs which want to be immune from messing around with different
66 * calling conventions */
67#ifndef CDECL
68# define CDECL
69#endif
70
71/* Globals */
72node *stnlist = NULL;
73settings *pcs;
74prefix *root;
75long cLegs, cStns;
76long cComponents;
77bool fExportUsed = fFalse;
78
79FILE *fhErrStat = NULL;
80img *pimg = NULL;
81#ifndef NO_PERCENTAGE
82bool fPercent = fFalse;
83#endif
84bool fQuiet = fFalse; /* just show brief summary + errors */
85bool fMute = fFalse; /* just show errors */
86bool fSuppress = fFalse; /* only output 3d(3dx) file */
87static bool fLog = fFalse; /* stdout to .log file */
88static bool f_warnings_are_errors = fFalse; /* turn warnings into errors */
89
90nosurveylink *nosurveyhead;
91
92real totadj, total, totplan, totvert;
93real min[3], max[3];
94prefix *pfxHi[3], *pfxLo[3];
95
96char *survey_title = NULL;
97int survey_title_len;
98
99bool fExplicitTitle = fFalse;
100
101char *fnm_output_base = NULL;
102int fnm_output_base_is_dir = 0;
103
104static void do_stats(void);
105
106static const struct option long_opts[] = {
107   /* const char *name; int has_arg (0 no_argument, 1 required_*, 2 optional_*); int *flag; int val; */
108#ifdef NO_PERCENTAGE
109   {"percentage", no_argument, 0, 0},
110   {"no-percentage", no_argument, 0, 0},
111#else
112   {"percentage", no_argument, 0, 'p'},
113   {"no-percentage", no_argument, 0, 3},
114#endif
115   {"output", required_argument, 0, 'o'},
116   {"quiet", no_argument, 0, 'q'},
117   {"no-auxiliary-files", no_argument, 0, 's'},
118   {"warnings-are-errors", no_argument, 0, 'w'},
119   {"log", no_argument, 0, 1},
120#ifdef CHASM3DX
121   {"chasm-format", no_argument, 0, 'x'},
122#endif
123#if (OS==WIN32)
124   {"pause", no_argument, 0, 2},
125#endif
126   {"help", no_argument, 0, HLP_HELP},
127   {"version", no_argument, 0, HLP_VERSION},
128   {0, 0, 0, 0}
129};
130
131#ifdef CHASM3DX
132#define short_opts "pxao:qswz:"
133#else
134#define short_opts "pao:qswz:"
135#endif
136
137/* TRANSLATE extract help messages to message file */
138static struct help_msg help[] = {
139/*                              <-- */
140   {HLP_ENCODELONG(0),          "display percentage progress"},
141   {HLP_ENCODELONG(2),          "set location for output files"},
142   {HLP_ENCODELONG(3),          "only show brief summary (-qq for errors only)"},
143   {HLP_ENCODELONG(4),          "do not create .err file"},
144   {HLP_ENCODELONG(5),          "turn warnings into errors"},
145   {HLP_ENCODELONG(6),          "log output to .log file"},
146#ifdef CHASM3DX
147   {HLP_ENCODELONG(7),          "output data in chasm's 3dx format"},
148#endif
149 /*{'z',                        "set optimizations for network reduction"},*/
150   {0, 0}
151};
152
153/* atexit functions */
154static void
155delete_output_on_error(void)
156{
157   if (msg_errors || (f_warnings_are_errors && msg_warnings))
158      filename_delete_output();
159}
160
161#if (OS==WIN32)
162static void
163pause_on_exit(void)
164{
165   while (_kbhit()) _getch();
166   _getch();
167}
168#endif
169
170extern CDECL int
171main(int argc, char **argv)
172{
173   int d;
174   time_t tmUserStart = time(NULL);
175   clock_t tmCPUStart = clock();
176   init_screen();
177
178   msg_init(argv);
179
180   pcs = osnew(settings);
181   pcs->next = NULL;
182   pcs->Translate = ((short*) osmalloc(ossizeof(short) * 257)) + 1;
183
184   /* Set up root of prefix hierarchy */
185   root = osnew(prefix);
186   root->up = root->right = root->down = NULL;
187   root->stn = NULL;
188   root->pos = NULL;
189   root->ident = NULL;
190   root->min_export = root->max_export = 0;
191   root->sflags = BIT(SFLAGS_SURVEY);
192   root->filename = NULL;
193
194   nosurveyhead = NULL;
195
196   stnlist = NULL;
197   cLegs = cStns = cComponents = 0;
198   totadj = total = totplan = totvert = 0.0;
199
200   for (d = 0; d <= 2; d++) {
201      min[d] = HUGE_REAL;
202      max[d] = -HUGE_REAL;
203      pfxHi[d] = pfxLo[d] = NULL;
204   }
205
206   /* at least one argument must be given */
207   cmdline_init(argc, argv, short_opts, long_opts, NULL, help, 1, -1);
208   while (1) {
209      int opt = cmdline_getopt();
210      if (opt == EOF) break;
211      switch (opt) {
212       case 'p':
213#ifndef NO_PERCENTAGE
214         fPercent = 1;
215#endif
216         break;
217#ifndef NO_PERCENTAGE
218       case 3:
219         fPercent = 0;
220         break;
221#endif
222       case 'o': {
223         osfree(fnm_output_base); /* in case of multiple -o options */
224         /* can be a directory (in which case use basename of leaf input)
225          * or a file (in which case just trim the extension off) */
226         if (fDirectory(optarg)) {
227            /* this is a little tricky - we need to note the path here,
228             * and then add the leaf later on (in datain.c) */
229            fnm_output_base = base_from_fnm(optarg);
230            fnm_output_base_is_dir = 1;
231         } else {
232            fnm_output_base = base_from_fnm(optarg);
233         }
234         break;
235       }
236#ifdef CHASM3DX
237       case 'x': {
238         fUseNewFormat = 1;
239         break;
240       }
241#endif
242       case 'q':
243         if (fQuiet) fMute = 1;
244         fQuiet = 1;
245         break;
246       case 's':
247         fSuppress = 1;
248         break;
249       case 'w':
250         f_warnings_are_errors = 1;
251         break;
252       case 'z': {
253         /* Control which network optimisations are used (development tool) */
254         static int first_opt_z = 1;
255         char c;
256         if (first_opt_z) {
257            optimize = 0;
258            first_opt_z = 0;
259         }
260         /* Lollipops, Parallel legs, Iterate mx, Delta* */
261         while ((c = *optarg++) != '\0')
262            if (islower((unsigned char)c)) optimize |= BITA(c);
263         break;
264       case 1:
265         fLog = fTrue;
266         break;
267#if (OS==WIN32)
268       case 2:
269         atexit(pause_on_exit);
270         break;
271#endif
272       }
273      }
274   }
275
276   if (fLog) {
277      char *fnm;
278      if (!fnm_output_base) {
279         char *p;
280         p = baseleaf_from_fnm(argv[optind]);
281         fnm = add_ext(p, EXT_LOG);
282         osfree(p);
283      } else if (fnm_output_base_is_dir) {
284         char *p;
285         fnm = baseleaf_from_fnm(argv[optind]);
286         p = use_path(fnm_output_base, fnm);
287         osfree(fnm);
288         fnm = add_ext(p, EXT_LOG);
289         osfree(p);
290      } else {
291         fnm = add_ext(fnm_output_base, EXT_LOG);
292      }
293
294      if (!freopen(fnm, "w", stdout))
295         fatalerror(/*Failed to open output file `%s'*/47, fnm);
296
297      osfree(fnm);
298   }
299
300   if (!fMute) {
301      const char *p = COPYRIGHT_MSG;
302      puts(PRETTYPACKAGE" "VERSION);
303      while (1) {
304          const char *q = p;
305          p = strstr(p, "(C)");
306          if (p == NULL) {
307              puts(q);
308              break;
309          }
310          fwrite(q, 1, p - q, stdout);
311          fputs(msg(/*&copy;*/0), stdout);
312          p += 3;
313      }
314   }
315
316   atexit(delete_output_on_error);
317
318   /* end of options, now process data files */
319   while (argv[optind]) {
320      const char *fnm = argv[optind];
321
322      if (!fExplicitTitle) {
323         char *lf;
324         lf = baseleaf_from_fnm(fnm);
325         if (survey_title) s_catchar(&survey_title, &survey_title_len, ' ');
326         s_cat(&survey_title, &survey_title_len, lf);
327         osfree(lf);
328      }
329
330      /* Select defaults settings */
331      default_all(pcs);
332#ifdef CHASM3DX
333      /* we need to get the filename of the first one for our base_source */
334      /* and also run_file */
335      if (fUseNewFormat) {
336         create_twig(root, fnm);
337         rhizome = root->twig_link;
338         limb = get_twig(root);
339         firstfilename = osstrdup(fnm);
340         startingdir = osmalloc(MAXPATHLEN);
341#if (OS==RISCOS)
342         strcpy(startingdir, "@");
343#else
344         getcwd(startingdir, MAXPATHLEN);
345#endif
346      }
347#endif
348      data_file(NULL, fnm); /* first argument is current path */
349
350      optind++;
351   }
352
353   validate();
354
355   solve_network(/*stnlist*/); /* Find coordinates of all points */
356   validate();
357
358#ifdef CHASM3DX
359   if (fUseNewFormat) {
360      /* this actually does all the writing */
361      if (!cave_close(pimg)) {
362         char *fnm = add_ext(fnm_output_base, EXT_SVX_3DX);
363         fatalerror(/*Error writing to file `%s'*/110, fnm);
364      }
365   } else {
366#endif
367      /* close .3d file */
368      if (!img_close(pimg)) {
369         char *fnm = add_ext(fnm_output_base, EXT_SVX_3D);
370         fatalerror(img_error(), fnm);
371      }
372#ifdef CHASM3DX
373   }
374#endif
375   if (fhErrStat) safe_fclose(fhErrStat);
376
377   out_current_action(msg(/*Calculating statistics*/120));
378   if (!fMute) do_stats();
379   if (!fQuiet) {
380      /* clock() typically wraps after 72 minutes, but there doesn't seem
381       * to be a better way.  Still 72 minutes means some cave!
382       * We detect if clock() could have wrapped and suppress CPU time
383       * printing in this case.
384       */
385      double tmUser = difftime(time(NULL), tmUserStart);
386      double tmCPU;
387      clock_t now = clock();
388#define CLOCK_T_WRAP \
389        (sizeof(clock_t)<sizeof(long)?(1ul << (CHAR_BIT * sizeof(clock_t))):0)
390      tmCPU = (now - (unsigned long)tmCPUStart)
391         / (double)CLOCKS_PER_SEC;
392      if (now < tmCPUStart)
393         tmCPU += CLOCK_T_WRAP / (double)CLOCKS_PER_SEC;
394      if (tmUser >= tmCPU + CLOCK_T_WRAP / (double)CLOCKS_PER_SEC)
395         tmCPU = 0;
396
397      /* tmUser is integer, tmCPU not - equivalent to (ceil(tmCPU) >= tmUser) */
398      if (tmCPU + 1 > tmUser) {
399         printf(msg(/*CPU time used %5.2fs*/140), tmCPU);
400      } else if (tmCPU == 0) {
401         if (tmUser != 0.0) {
402            printf(msg(/*Time used %5.2fs*/141), tmUser);
403         } else {
404            fputs(msg(/*Time used unavailable*/142), stdout);
405         }
406      } else {
407         printf(msg(/*Time used %5.2fs (%5.2fs CPU time)*/143), tmUser, tmCPU);
408      }
409      putnl();
410
411      puts(msg(/*Done.*/144));
412   }
413   if (msg_warnings || msg_errors) {
414      if (msg_errors || (f_warnings_are_errors && msg_warnings)) {
415         printf(msg(/*There were %d warning(s) and %d non-fatal error(s) - no output files produced.*/113),
416                msg_warnings, msg_errors);
417         putnl();
418         return EXIT_FAILURE;
419      }
420      printf(msg(/*There were %d warning(s).*/16), msg_warnings);
421      putnl();
422   }
423   return EXIT_SUCCESS;
424}
425
426static void
427do_range(int d, int msg1, int msg2, int msg3)
428{
429   printf(msg(msg1), max[d] - min[d]);
430   fprint_prefix(stdout, pfxHi[d]);
431   printf(msg(msg2), max[d]);
432   fprint_prefix(stdout, pfxLo[d]);
433   printf(msg(msg3), min[d]);
434   putnl();
435}
436
437static void
438do_stats(void)
439{
440   long cLoops = cComponents + cLegs - cStns;
441
442   putnl();
443
444   if (cStns == 1) {
445      fputs(msg(/*Survey contains 1 survey station,*/172), stdout);
446   } else {
447      printf(msg(/*Survey contains %ld survey stations,*/173), cStns);
448   }
449
450   if (cLegs == 1) {
451      fputs(msg(/* joined by 1 leg.*/174), stdout);
452   } else {
453      printf(msg(/* joined by %ld legs.*/175), cLegs);
454   }
455
456   putnl();
457
458   if (cLoops == 1) {
459      fputs(msg(/*There is 1 loop.*/138), stdout);
460   } else {
461      printf(msg(/*There are %ld loops.*/139), cLoops);
462   }
463
464   putnl();
465
466   if (cComponents != 1) {
467      printf(msg(/*Survey has %ld connected components.*/178), cComponents);
468      putnl();
469   }
470
471   printf(msg(/*Total length of survey legs = %7.2fm (%7.2fm adjusted)*/132),
472          total, totadj);
473   putnl();
474   printf(msg(/*Total plan length of survey legs = %7.2fm*/133),
475          totplan);
476   putnl();
477   printf(msg(/*Total vertical length of survey legs = %7.2fm*/134),
478          totvert);
479   putnl();
480
481   /* If there's no underground survey, we've no ranges */
482   if (pfxHi[0]) {
483      do_range(2, /*Vertical range = %4.2fm (from */135,
484               /* at %4.2fm to */136, /* at %4.2fm)*/137);
485      do_range(1, /*North-South range = %4.2fm (from */148,
486               /* at %4.2fm to */196, /* at %4.2fm)*/197);
487      do_range(0, /*East-West range = %4.2fm (from */149,
488               /* at %4.2fm to */196, /* at %4.2fm)*/197);
489   }
490
491   print_node_stats();
492   /* Also, could give:
493    *  # nodes stations (ie have other than two references or are fixed)
494    *  # fixed stations (list of?)
495    */
496}
Note: See TracBrowser for help on using the repository browser.