source: tags/svn.1.5.4/CONVERTALN/main.cxx

Last change on this file was 8309, checked in by westram, 14 years ago
  • moved much code into static scope

(partly reverted by [8310])

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.2 KB
Line 
1// ------------------------------------------------------------
2//
3// Format Conversion Program.
4//
5// Woese Lab., Dept. of Microbiology, UIUC
6// Modified for use in ARB by ARB team
7//
8// ------------------------------------------------------------
9
10#include "defs.h"
11#include "fun.h"
12#include "global.h"
13
14Convaln_exception *Convaln_exception::thrown = NULL;
15
16struct TypeSwitch { const char *switchtext; Format format; };
17
18static TypeSwitch convertible_type[] = { // see fconv.cxx@format_spec
19    { "GenBank",   GENBANK   },
20    { "EMBL",      EMBL      },
21    { "AE2",       MACKE     },
22    { "SwissProt", SWISSPROT },
23    { "NEXUS",     NEXUS     },
24    { "PHYLIP",    PHYLIP    },
25    { "FASTDNAML", FASTDNAML },
26    { "GCG",       GCG       },
27    { "PRINTABLE", PRINTABLE },
28};
29
30static void show_command_line_usage() {
31    fputs("Command line usage:\n"
32          "  $ arb_convert_aln -INFMT input_file -OUTFMT output_file\n"
33          "  where\n"
34          "      INFMT  may be 'GenBank', 'EMBL', 'AE2' or 'SwissProt' and\n"
35          "      OUTFMT may be 'GenBank', 'EMBL', 'AE2', 'NEXUS', 'PHYLIP', 'FASTDNAML', 'GCG' or 'Printable'\n"
36          "  (Note: you may abbreviate the format names)\n"
37          "  FASTDNAML writes a PHYLIP file with content from STDIN appended at end of first line (used for arb_fastdnaml).\n"
38          , stderr);
39}
40
41static void valid_name_or_die(const char *file_name) {
42    if (str0len(file_name) <= 0) {
43        throw_errorf(152, "illegal file name: %s", file_name);
44    }
45}
46static bool file_exists(const char *file_name) {
47    FILE *ifp    = fopen(file_name, "r");
48    bool  exists = ifp != NULL;
49    if (ifp) fclose(ifp);
50
51    return exists;
52}
53
54static void change_file_suffix(const char *old_file, char *file_name, int type) {
55    // Define the default file name by changing suffix.
56    int indi, indj;
57
58    for (indi = str0len(old_file) - 1; indi >= 0 && old_file[indi] != '.'; indi--)
59        if (indi == 0)
60            strcpy(file_name, old_file);
61        else {
62            for (indj = 0; indj < (indi - 1); indj++)
63                file_name[indj] = old_file[indj];
64            file_name[indj] = '\0';
65        }
66    switch (type) {
67        case GENBANK:
68            strcat(file_name, ".GB");
69            break;
70        case MACKE:
71            strcat(file_name, ".aln");
72            break;
73        case NEXUS:
74            strcat(file_name, ".NEXUS");
75            break;
76        case PHYLIP:
77            strcat(file_name, ".PHY");
78            break;
79        case EMBL:
80            strcat(file_name, ".EMBL");
81            break;
82        case PRINTABLE:
83            strcat(file_name, ".prt");
84            break;
85        default:
86            strcat(file_name, ".???");
87    }
88}
89
90static void ask_for_conversion_params(FormattedFile& in, FormattedFile& out) {
91    char temp[LINESIZE];
92    char choice[LINESIZE];
93
94    fputs("---------------------------------------------------------------\n"
95          "\n"
96          "  convert_aln - an alignment and file converter written by\n"
97          "  WenMin Kuan for the RDP database project.\n"
98          "\n"
99          "  Modified for use in ARB by Oliver Strunk & Ralf Westram\n"
100          "  Report errors or deficiencies to devel@arb-home.de\n"
101          "\n"
102          , stderr);
103    show_command_line_usage();
104    fputs("\n"
105          "---------------------------------------------------------------\n"
106          "\n"
107          "Select input format (<CR> means default)\n"
108          "\n"
109          "  (1)  GenBank [default]\n"
110          "  (2)  EMBL\n"
111          "  (3)  AE2\n"
112          "  (4)  SwissProt\n"
113          "  (5)  Quit\n"
114          "  ? "
115          , stderr);
116
117    Getstr(choice, LINESIZE);
118    {
119        Format inType = UNKNOWN;
120        switch (choice[0]) {
121            case '\0': // [default]
122            case '1': inType = GENBANK; break;
123            case '2': inType = EMBL; break;
124            case '3': inType = MACKE; break;
125            case '4': inType = SWISSPROT; break;
126            case '5': exit(0); // ok - interactive mode only
127            default: throw_errorf(16, "Unknown input format selection '%s'", choice);
128        }
129
130        fputs("\nInput file name? ", stderr);
131        Getstr(temp, LINESIZE);
132        in.init(temp, inType);
133    }
134
135    valid_name_or_die(temp);
136    if (!file_exists(temp)) throw_error(77, "Input file not found");
137
138    // output file information
139    fputs("\n"
140          "Select output format (<CR> means default)\n"
141          "\n"
142          "  (1)  GenBank\n"
143          "  (2)  EMBL\n"
144          "  (3)  AE2 [default]\n"
145          "  (4)  NEXUS (Paup)\n"
146          "  (5)  PHYLIP\n"
147          "  (6)  GCG\n"
148          "  (7)  Printable\n"
149          "  (8)  Quit\n"
150          "  ? ", stderr);
151
152    Getstr(choice, LINESIZE);
153    {
154        Format ouType = UNKNOWN;
155        switch (choice[0]) {
156            case '1': ouType = GENBANK; break;
157            case '2': ouType = EMBL; break;
158            case '\0': // [default]
159            case '3': ouType = MACKE; break;
160            case '4': ouType = NEXUS; break;
161            case '5': ouType = PHYLIP; break;
162            case '6': ouType = GCG; break;
163            case '7': ouType = PRINTABLE; break;
164            case '8': exit(0); // ok - interactive mode only
165            default: throw_errorf(66, "Unknown output format selection '%s'", choice);
166        }
167        change_file_suffix(in.name(), temp, ouType);
168        if (ouType != GCG) {
169            fprintf(stderr, "\nOutput file name [%s]? ", temp);
170            Getstr(temp, LINESIZE);
171            if (str0len(temp) == 0)
172                change_file_suffix(in.name(), temp, ouType);
173        }
174        out.init(temp, ouType);
175    }
176}
177
178static int strcasecmp_start(const char *s1, const char *s2) {
179    int cmp = 0;
180    for (int p = 0; !cmp; p++) {
181        cmp = tolower(s1[p])-tolower(s2[p]);
182        if (!s1[p]) return 0;
183    }
184    return cmp;
185}
186
187static bool is_abbrev_switch(const char *arg, const char *switchtext) {
188    return arg[0] == '-' && strcasecmp_start(arg+1, switchtext) == 0;
189}
190
191static Format parse_type(const char *arg) {
192    for (size_t i = 0; i<ARRAY_ELEMS(convertible_type); ++i) {
193        const TypeSwitch& type = convertible_type[i];
194        if (is_abbrev_switch(arg, type.switchtext)) {
195            return type.format;
196        }
197    }
198    return UNKNOWN;
199}
200
201static Format parse_intype(const char *arg) {
202    Format type = parse_type(arg);
203    if (!is_input_format(type)) throw_errorf(65, "Unsupported input file type '%s'", arg);
204    if (type == UNKNOWN) throw_errorf(67, "UNKNOWN input file type '%s'", arg);
205    return type;
206}
207
208static Format parse_outtype(const char *arg) {
209    Format type = parse_type(arg);
210    if (type == UNKNOWN) throw_errorf(68, "UNKNOWN output file type '%s'", arg);
211    return type;
212}
213
214static bool is_help_req(const char *arg) {
215    return strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0;
216}
217static bool command_line_conversion(int argc, const char * const *argv, FormattedFile& in, FormattedFile& out) {
218    for (int c = 1; c<argc; c++) {
219        if (is_help_req(argv[c])) {
220            show_command_line_usage();
221            return false;
222        }
223    }
224
225    if (argc != 5) throw_errorf(69, "arb_convert_aln expects exactly 4 parameters (you specified %i). Try '--help'", argc-1);
226
227    in.init(argv[2], parse_intype(argv[1]));
228    out.init(argv[4], parse_outtype(argv[3]));
229
230    return true;
231}
232
233static void do_conversion(const FormattedFile& in, const FormattedFile& out) {
234#ifdef CALOG
235    fprintf(stderr, "\n\nConvert file %s to file %s.\n", in.name(), out.name());
236#endif
237
238    // check if output file exists and filename's validation
239    valid_name_or_die(out.name());
240    if (file_exists(out.name())) warningf(151, "Output file %s exists, will be overwritten.", out.name());
241
242    // file format transfer...
243    convert(in, out);
244}
245
246int ARB_main(int argc, const char *argv[]) {
247    int exitcode = EXIT_SUCCESS;
248    try {
249        FormattedFile in;
250        FormattedFile out;
251
252        if (argc < 2) {
253            ask_for_conversion_params(in, out); 
254            do_conversion(in, out);
255        }
256        else {
257            if (command_line_conversion(argc, argv, in, out)) {
258                do_conversion(in, out);
259            }
260        }
261    }
262    catch (Convaln_exception& err) {
263        fprintf(stderr, "ERROR(%d): %s\n", err.get_code(), err.get_msg());
264        exitcode = EXIT_FAILURE;
265    }
266    return exitcode;
267}
268
269// --------------------------------------------------------------------------------
270
271#ifdef UNIT_TESTS
272#include <test_unit.h>
273
274void TEST_BASIC_switch_parsing() {
275    TEST_ASSERT(strcasecmp_start("GenBank", "GenBank") == 0);
276    TEST_ASSERT(strcasecmp_start("GEnbaNK", "genBANK") == 0);
277    TEST_ASSERT(strcasecmp_start("Ge", "GenBank") == 0);
278    TEST_ASSERT(strcasecmp_start("GenBank", "NEXUS") < 0);
279    TEST_ASSERT(strcasecmp_start("NEXUS", "GenBank") > 0);
280
281    TEST_ASSERT(!is_abbrev_switch("notAswitch", "notAswitch"));
282    TEST_ASSERT(!is_abbrev_switch("-GenbankPlus", "Genbank"));
283    TEST_ASSERT(!is_abbrev_switch("-Ge", "NEXUS"));
284
285    TEST_ASSERT(is_abbrev_switch("-Ge", "Genbank"));
286    TEST_ASSERT(is_abbrev_switch("-N", "NEXUS"));
287    TEST_ASSERT(is_abbrev_switch("-NEXUS", "NEXUS"));
288
289    TEST_ASSERT_EQUAL(parse_outtype("-PH"), PHYLIP);
290    TEST_ASSERT_EQUAL(parse_outtype("-PHYLIP"), PHYLIP);
291    TEST_ASSERT_EQUAL(parse_outtype("-phylip"), PHYLIP);
292}
293
294#endif // UNIT_TESTS
Note: See TracBrowser for help on using the repository browser.