GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/unrrdu/undos.c Lines: 13 108 12.0 %
Date: 2017-05-26 Branches: 1 110 0.9 %

Line Branch Exec Source
1
/*
2
  Teem: Tools to process and visualize scientific data and images             .
3
  Copyright (C) 2013, 2012, 2011, 2010, 2009  University of Chicago
4
  Copyright (C) 2008, 2007, 2006, 2005  Gordon Kindlmann
5
  Copyright (C) 2004, 2003, 2002, 2001, 2000, 1999, 1998  University of Utah
6
7
  This library is free software; you can redistribute it and/or
8
  modify it under the terms of the GNU Lesser General Public License
9
  (LGPL) as published by the Free Software Foundation; either
10
  version 2.1 of the License, or (at your option) any later version.
11
  The terms of redistributing and/or modifying this software also
12
  include exceptions to the LGPL that facilitate static linking.
13
14
  This library is distributed in the hope that it will be useful,
15
  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
  Lesser General Public License for more details.
18
19
  You should have received a copy of the GNU Lesser General Public License
20
  along with this library; if not, write to Free Software Foundation, Inc.,
21
  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22
*/
23
24
#include "unrrdu.h"
25
#include "privateUnrrdu.h"
26
27
#define INFO "Converts DOS text files to normal, and more"
28
static const char *_unrrdu_undosInfoL =
29
  (INFO
30
   ".  Normally, it converts LF-CR pairs to just CR, or, with the \"-r\" "
31
   "option, convert back to DOS, for whatever sick and "
32
   "twisted reason you'd have to do that. Can also handle legacy MAC "
33
   "text files (only LF). Unlike the simple sed or perl scripts for "
34
   "this purpose, this program is careful to be idempotent. Also, this "
35
   "makes an effort to not meddle with binary files (on which this may be "
36
   "mistakenly invoked). A message is printed to stderr for all the files "
37
   "actually modified. Does various things, some more justified than "
38
   "others.\n "
39
   "* (not actually based on Nrrd)");
40
41
#define CR 10
42
#define LF 13
43
#define BAD_PERC 5.0
44
45
static void
46
undosConvert(const char *me, char *name, int reverse, int mac,
47
             int quiet, int noAction) {
48
  airArray *mop;
49
  FILE *fin, *fout;
50
  char *data=NULL;
51
  airArray *dataArr;
52
  unsigned int ci;
53
  int car, numBad, willConvert;
54
  airPtrPtrUnion appu;
55
56
  mop = airMopNew();
57
  if (!airStrlen(name)) {
58
    fprintf(stderr, "%s: empty filename\n", me);
59
    airMopError(mop); return;
60
  }
61
62
  /* -------------------------------------------------------- */
63
  /* open input file  */
64
  fin = airFopen(name, stdin, "rb");
65
  if (!fin) {
66
    if (!quiet) {
67
      fprintf(stderr, "%s: couldn't open \"%s\" for reading: \"%s\"\n",
68
              me, name, strerror(errno));
69
    }
70
    airMopError(mop); return;
71
  }
72
  airMopAdd(mop, fin, (airMopper)airFclose, airMopOnError);
73
74
  /* -------------------------------------------------------- */
75
  /* create buffer */
76
  appu.c = &data;
77
  dataArr = airArrayNew(appu.v, NULL, sizeof(char), AIR_STRLEN_HUGE);
78
  if (!dataArr) {
79
    if (!quiet) {
80
      fprintf(stderr, "%s: internal allocation error #1\n", me);
81
    }
82
    airMopError(mop); return;
83
  }
84
  airMopAdd(mop, dataArr, (airMopper)airArrayNuke, airMopAlways);
85
86
  /* -------------------------------------------------------- */
87
  /* read input file, testing for binary-ness along the way */
88
  numBad = 0;
89
  car = getc(fin);
90
  if (EOF == car) {
91
    if (!quiet) {
92
      fprintf(stderr, "%s: \"%s\" is empty, skipping ...\n", me, name);
93
    }
94
    airMopError(mop); return;
95
  }
96
  do {
97
    ci = airArrayLenIncr(dataArr, 1);
98
    if (!dataArr->data) {
99
      if (!quiet) {
100
        fprintf(stderr, "%s: internal allocation error #2\n", me);
101
      }
102
      airMopError(mop); return;
103
    }
104
    data[ci] = car;
105
    numBad += !(isprint(car) || isspace(car));
106
    car = getc(fin);
107
  } while (EOF != car && BAD_PERC > 100.0*numBad/dataArr->len);
108
  if (EOF != car) {
109
    if (!quiet) {
110
      fprintf(stderr, "%s: more than %g%% of \"%s\" is non-printing, "
111
              "skipping ...\n", me, BAD_PERC, name);
112
    }
113
    airMopError(mop); return;
114
  }
115
  fin = airFclose(fin);
116
117
  /* -------------------------------------------------------- */
118
  /* see if we really need to do anything */
119
  willConvert = AIR_FALSE;
120
  if (!strcmp("-", name)) {
121
    willConvert = AIR_TRUE;
122
  } else if (reverse) {
123
    for (ci=0; ci<dataArr->len; ci++) {
124
      if (mac) {
125
        if (CR == data[ci]) {
126
          willConvert = AIR_TRUE;
127
          break;
128
        }
129
      } else {
130
        if (CR == data[ci] && (ci && LF != data[ci-1])) {
131
          willConvert = AIR_TRUE;
132
          break;
133
        }
134
      }
135
    }
136
  } else {
137
    for (ci=0; ci<dataArr->len; ci++) {
138
      if (mac) {
139
        if (LF == data[ci]) {
140
          willConvert = AIR_TRUE;
141
          break;
142
        }
143
      } else {
144
        if (LF == data[ci] && (ci+1<dataArr->len && CR == data[ci+1])) {
145
          willConvert = AIR_TRUE;
146
          break;
147
        }
148
      }
149
    }
150
  }
151
  if (!willConvert) {
152
    /* no, we don't need to do anything; quietly quit */
153
    airMopOkay(mop);
154
    return;
155
  } else {
156
    if (!quiet) {
157
      fprintf(stderr, "%s: %s \"%s\" %s %s ... \n", me,
158
              noAction ? "would convert" : "converting",
159
              name,
160
              reverse ? "to" : "from",
161
              mac ? "MAC" : "DOS");
162
    }
163
  }
164
  if (noAction) {
165
    /* just joking, we won't actually write anything.
166
       (yes, even if input was stdin) */
167
    airMopOkay(mop);
168
    return;
169
  }
170
171
  /* -------------------------------------------------------- */
172
  /* open output file */
173
  fout = airFopen(name, stdout, "wb");
174
  if (!fout) {
175
    if (!quiet) {
176
      fprintf(stderr, "%s: couldn't open \"%s\" for writing: \"%s\"\n",
177
              me, name, strerror(errno));
178
    }
179
    airMopError(mop); return;
180
  }
181
  airMopAdd(mop, fout, (airMopper)airFclose, airMopOnError);
182
183
  /* -------------------------------------------------------- */
184
  /* write output file */
185
  car = 'a';
186
  if (reverse) {
187
    for (ci=0; ci<dataArr->len; ci++) {
188
      if ((mac && CR == data[ci])
189
          || (CR == data[ci] && (ci && LF != data[ci-1]))) {
190
        car = putc(LF, fout);
191
        if (!mac && EOF != car) {
192
          car = putc(CR, fout);
193
        }
194
      } else {
195
        car = putc(data[ci], fout);
196
      }
197
    }
198
  } else {
199
    for (ci=0; EOF != car && ci<dataArr->len; ci++) {
200
      if ((mac && LF == data[ci])
201
          || (LF == data[ci] && (ci+1<dataArr->len && CR == data[ci+1]))) {
202
        car = putc(CR, fout);
203
        ci += !mac;
204
      } else {
205
        car = putc(data[ci], fout);
206
      }
207
    }
208
  }
209
  if (EOF == car) {
210
    if (!quiet) {
211
      fprintf(stderr, "%s: ERROR writing \"%s\" possible data loss !!! "
212
              "(sorry)\n", me, name);
213
    }
214
  }
215
  fout = airFclose(fout);
216
217
  airMopOkay(mop);
218
  return;
219
}
220
221
int
222
unrrdu_undosMain(int argc, const char **argv, const char *me,
223
                 hestParm *hparm) {
224
  /* these are stock for unrrdu */
225
2
  hestOpt *opt = NULL;
226
  airArray *mop;
227
  int pret;
228
1
  char *err;
229
  /* these are specific to this command */
230
1
  char **name;
231
1
  int lenName, ni, reverse, quiet, noAction, mac;
232
233
1
  hestOptAdd(&opt, "r", NULL, airTypeInt, 0, 0, &reverse, NULL,
234
             "convert back to DOS, instead of converting from DOS to normal");
235
1
  hestOptAdd(&opt, "q", NULL, airTypeInt, 0, 0, &quiet, NULL,
236
             "never print anything to stderr, even for errors.");
237
1
  hestOptAdd(&opt, "m", NULL, airTypeInt, 0, 0, &mac, NULL,
238
             "deal with legacy MAC text files.");
239
1
  hestOptAdd(&opt, "n", NULL, airTypeInt, 0, 0, &noAction, NULL,
240
             "don't actually write converted files, just pretend to. "
241
             "This is useful to see which files WOULD be converted. ");
242
1
  hestOptAdd(&opt, NULL, "file", airTypeString, 1, -1, &name, NULL,
243
             "all the files to convert.  Each file will be over-written "
244
             "with its converted contents.  Use \"-\" to read from stdin "
245
             "and write to stdout", &lenName);
246
247
1
  mop = airMopNew();
248
1
  airMopAdd(mop, opt, (airMopper)hestOptFree, airMopAlways);
249
2
  USAGE(_unrrdu_undosInfoL);
250
  PARSE();
251
  airMopAdd(mop, opt, (airMopper)hestParseFree, airMopAlways);
252
253
  for (ni=0; ni<lenName; ni++) {
254
    undosConvert(me, name[ni], reverse, mac, quiet, noAction);
255
  }
256
257
  airMopOkay(mop);
258
  return 0;
259
1
}
260
261
UNRRDU_CMD_HIDE(undos, INFO);