unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / tools / src / tools / configtool / standalone / common / ecosconfig.cxx
1 //####COPYRIGHTBEGIN####
2 //                                                                          
3 // ----------------------------------------------------------------------------
4 // Copyright (C) 2003 Bart Veer
5 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
6 //
7 // This program is part of the eCos host tools.
8 //
9 // This program is free software; you can redistribute it and/or modify it 
10 // under the terms of the GNU General Public License as published by the Free 
11 // Software Foundation; either version 2 of the License, or (at your option) 
12 // any later version.
13 // 
14 // This program is distributed in the hope that it will be useful, but WITHOUT 
15 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
16 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
17 // more details.
18 // 
19 // You should have received a copy of the GNU General Public License along with
20 // this program; if not, write to the Free Software Foundation, Inc., 
21 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22 //
23 // ----------------------------------------------------------------------------
24 //                                                                          
25 //####COPYRIGHTEND####
26 //==========================================================================
27 //
28 //      ecosconfig.cxx
29 //
30 //      The implementation of ecosconfig command line processing
31 //
32 //==========================================================================
33 //==========================================================================
34 //#####DESCRIPTIONBEGIN####                                             
35 //
36 // Author(s):           jld
37 // Date:                1999-11-08
38 //
39 //####DESCRIPTIONEND####
40 //==========================================================================
41
42 #ifndef _MSC_VER
43 #include <sys/param.h>
44 #include <unistd.h> /* for realpath() */
45 #endif
46 #ifdef __CYGWIN__
47 #include <windows.h>
48 #include <sys/cygwin.h> /* for cygwin_conv_to_win32_path() */
49 #endif
50 #include "cdl_exec.hxx"
51 #include "ecosconfig.hxx"
52
53 #define TOOL_VERSION "2.0b1"
54 #define TOOL_COPYRIGHT "Copyright (c) 2002 Red Hat, Inc."
55 #define DEFAULT_SAVE_FILE "ecos.ecc"
56 static char* tool = "ecosconfig";
57
58 // When running under cygwin there may be confusion between cygwin and
59 // Windows paths. Some paths will be passed on to the Tcl library,
60 // which sometimes will accept a cygwin path and sometimes not. This
61 // does not affect the VC++ build which only accepts Windows paths,
62 // and obviously it does not affect any Unix platfom.
63 #ifdef __CYGWIN__
64 static std::string
65 translate_path(std::string& path)
66 {
67     std::string result;
68     char buffer [MAXPATHLEN + 1];
69     if ("" == path) {
70         result = path;
71     } else {
72         cygwin_conv_to_win32_path (path.c_str (), buffer);
73         result = std::string(buffer);
74     }
75     return result;
76 }
77 # define TRANSLATE_PATH(a) translate_path(a)
78 #else
79 # define TRANSLATE_PATH(a) (a)
80 #endif
81
82 int main (int argc, char * argv []) {
83
84     // process command qualifiers
85     std::string repository;     // --srcdir=
86     std::string savefile;       // --config=
87     std::string install_prefix; // --prefix=
88     bool version = false;       // --version
89     bool no_resolve = false;    // --no-resolve
90     bool quiet = false;         // -q, --quiet
91     bool verbose = false;       // -v, --verbose
92     bool ignore_errors = false; // -i, --ignore-errors
93     bool no_updates = false;    // -n, --no-updates,
94     bool help = false;          // --help
95     bool enable_debug_set = false;  // --enable-debug or --disable-debug
96     int  debug_level = 0;       // --enable-debug=[0|1|2]
97
98     Tcl_FindExecutable(argv[0]);
99     
100     // getopt() cannot easily be used here since this code has to
101     // build with VC++ as well.
102     bool args_ok = true;
103     int command_index;
104     for (command_index = 1; command_index < argc; command_index++) { // for each command line argument
105         char* arg = argv[command_index];
106         if (0 == strcmp(arg, "--help")) {
107             help = true;
108         } else if ((0 == strcmp(arg, "-q")) || (0 == strcmp(arg, "--quiet"))) {
109             // Allow repeated use of -q and -v to override each other.
110             // This is useful in conjunction with shell aliases.
111             quiet = true;
112             verbose = false;
113         } else if ((0 == strcmp(arg, "-v")) || (0 == strcmp(arg, "--verbose"))) {
114             verbose = true;
115             quiet = false;
116         } else if ((0 == strcmp(arg, "-i")) || (0 == strcmp(arg, "--ignore-errors"))) {
117             // Duplicate use of -i and the other flags is harmless.
118             ignore_errors = true;
119         } else if ((0 == strcmp(arg, "-n")) || (0 == strcmp(arg, "--no-updates"))) {
120             no_updates = true;
121         } else if (0 == strcmp(arg, "--version")) {
122             version = true;
123         } else if (0 == strcmp(arg, "--no-resolve")) {
124             no_resolve = true;
125         } else if (0 == strcmp(arg, "--enable-debug")) {
126             enable_debug_set = true;
127             debug_level = 1;
128         } else if (0 == strcmp(arg, "--disable-debug")) {
129             enable_debug_set = true;
130             debug_level = 0;
131         } else if (0 == strncmp(arg, "--srcdir", 8)) {
132             // Duplicate use of --srcdir and other data-containing options should
133             // be marked as an error.
134             if ("" != repository) {
135                 fprintf(stderr, "%s: the `--srcdir' option should be used only once.\n", tool);
136                 args_ok = false;
137             } else {
138                 if ('=' == arg[8]) {
139                     repository = std::string(arg + 9);
140                     if ("" == repository) {
141                         fprintf(stderr, "%s: missing component repository after `--srcdir='\n", tool);
142                         args_ok = false;
143                     }
144                 } else if ('\0' == arg[8]) {
145                     command_index++;
146                     if (command_index == argc) {
147                         fprintf(stderr, "%s: missing component repository after `--srcdir'\n", tool);
148                         args_ok = false;
149                     } else {
150                         repository = argv[command_index];
151                     }
152                 } else {
153                     fprintf(stderr, "%s: invalid option `%s'\n", tool, arg);
154                     args_ok = false;
155                 }
156             }
157         } else if (0 == strncmp(arg, "--config", 8)) {
158             if ("" != savefile) {
159                 fprintf(stderr, "%s: the `--config' option should be used only once.\n", tool);
160                 args_ok = false;
161             } else {
162                 if ('=' == arg[8]) {
163                     savefile = std::string(arg + 9);
164                     if ("" == savefile) {
165                         fprintf(stderr, "%s: missing configuration savefile after `--config='\n", tool);
166                         args_ok = false;
167                     }
168                 } else if ('\0' == arg[8]) {
169                     command_index++;
170                     if (command_index == argc) {
171                         fprintf(stderr, "%s: missing configuration savefile after `--config'\n", tool);
172                         args_ok = false;
173                     } else {
174                         savefile = argv[command_index];
175                     }
176                 } else {
177                     fprintf(stderr, "%s: invalid option `%s'\n", tool, arg);
178                     args_ok = false;
179                 }
180             }
181         } else if (0 == strncmp(arg, "--prefix", 8)) {
182             if ("" != install_prefix) {
183                 fprintf(stderr, "%s: the `--prefix' option should be used only once.\n", tool);
184                 args_ok = false;
185             } else {
186                 if ('=' == arg[8]) {
187                     install_prefix = std::string(arg + 9);
188                     if ("" == install_prefix) {
189                         fprintf(stderr, "%s: missing install prefix after `--prefix='\n", tool);
190                         args_ok = false;
191                     }
192                 } else if ('\0' == arg[8]) {
193                     command_index++;
194                     if (command_index == argc) {
195                         fprintf(stderr, "%s: missing install prefix after `--prefix'\n", tool);
196                         args_ok = false;
197                     } else {
198                         install_prefix = argv[command_index];
199                     }
200                 } else {
201                     fprintf(stderr, "%s: invalid option `%s'\n", tool, arg);
202                     args_ok = false;
203                 }
204             }
205         } else {
206             // The argument is not a qualifier
207             // However, none of the sub-commands begin with a -
208             if ('-' == arg[0]) {
209                 fprintf(stderr, "%s: unknown option `%s'\n", tool, arg);
210                 args_ok = false;
211             }
212             break; // end of qualifiers
213         }
214     }
215
216 #if 0
217     printf("args_ok is %d\n", args_ok);
218     printf("help is %d\n", help);
219     printf("version is %d\n", version);
220     printf("no_resolve is %d\n", no_resolve);
221     printf("quiet is %d\n", quiet);
222     printf("verbose is %d\n", verbose);
223     printf("no-updates is %d\n", no_updates);
224     printf("ignore_errors is %d\n", ignore_errors);
225     printf("repository is %s\n", repository.c_str());
226     printf("savefile is %s\n", savefile.c_str());
227     printf("install_prefix is %s\n", install_prefix.c_str());
228     exit(EXIT_SUCCESS);
229 #endif
230     
231     // Usually argv[command_index] will be a sub-command, unless
232     // --help or --version has been used.
233     
234     // Always output the version number, irrespective of subsequent
235     // commands or any problems. This can be useful in batch jobs.
236     if (version) {
237         printf ("ecosconfig %s (%s %s)\n%s\n", TOOL_VERSION, __DATE__, __TIME__, TOOL_COPYRIGHT);
238         if (command_index == argc) {
239             return EXIT_SUCCESS;
240         }
241     }
242     // Cope with --help and any user errors. If --help is used then
243     // subsequent arguments should be ignored, as should any problems
244     // with the arguments. This allows the user to type a partial
245     // command, then switch to --help, and use shell history editing
246     // to complete/correct the command.
247     if (help || !args_ok || (command_index == argc)) {
248         usage_message();
249         return help ? EXIT_SUCCESS : EXIT_FAILURE;
250     }
251     
252     // set the default save file
253     if (savefile.empty ()) { // if the save file was not specified on the command line
254         savefile = DEFAULT_SAVE_FILE; // use the default save file
255     }
256
257     // find the repository
258     if (repository.empty ()) { // if the repository was not specified on the command line
259         const char * env_var = getenv ("ECOS_REPOSITORY");
260         if (env_var) { // if the ECOS_REPOSITORY environment variable is defined
261             repository = env_var;
262         } else { // the ECOS_REPOSITORY environment variable is not defined
263             // assume that the tool is located in the root of the repository
264 #ifdef _MSC_VER
265             char toolpath [_MAX_PATH + 1];
266             _fullpath (toolpath, argv [0], sizeof (toolpath)); // get the absolute path to the tool
267 #else
268             // NOTE: portability problem. realpath() is not a POSIX function.
269             // Alternative code may be needed on some platforms.
270             char toolpath [MAXPATHLEN + 1];
271             realpath (argv [0], toolpath); // get the absolute path to the tool
272 #endif
273             repository = toolpath;
274             for (unsigned int n = repository.size () - 1; n > 0; n--) { // for each char starting at the tail
275                 if (('\\' == repository [n]) || ('/' == repository [n])) { // if the char is a directory separator
276                     repository.resize (n); // remove the filename from the filepath
277                     break;
278                 }
279             }
280         }
281     }
282
283     repository          = TRANSLATE_PATH(repository);
284     savefile            = TRANSLATE_PATH(savefile);
285     install_prefix      = TRANSLATE_PATH(install_prefix);
286
287     // Initialize the cdl_exec code (not quite sure why this needs a
288     // separate object rather than just a bunch of statics). 
289     cdl_exec exec (trim_path (repository), savefile, trim_path (install_prefix), no_resolve);
290     cdl_exec::set_quiet_mode(quiet);
291     cdl_exec::set_verbose_mode(verbose);
292     cdl_exec::set_ignore_errors_mode(ignore_errors);
293     cdl_exec::set_no_updates_mode(no_updates);
294     if (enable_debug_set) {
295         cdl_exec::set_debug_level(debug_level);
296     }
297     
298     // Now identify and process the sub-command.
299     const std::string command = argv [command_index];
300     command_index++;
301     bool status = false;
302
303     if ("new" == command) {
304         // Usage: ecosconfig new <target> [template [version]]
305         if ((command_index == argc) || ((command_index + 3) <= argc)) {
306             usage_message();
307         } else {
308             // The default values for template and template_version
309             // are part of the cdl_exec class, so cdl_exec::cmd_new() has
310             // to be invoked with the right number of arguments.
311             if ((command_index + 1) == argc) {
312                 status = exec.cmd_new(argv[command_index]);
313             } else if ((command_index + 2) == argc) {
314                 status = exec.cmd_new(argv[command_index], argv[command_index + 1]);
315             } else {
316                 status = exec.cmd_new(argv[command_index], argv[command_index + 1], argv[command_index + 2]);
317             }
318         }
319     } else if ("tree" == command) {
320         // Usage: ecosconfig tree
321         if (command_index == argc) {
322             status = exec.cmd_tree ();
323         } else {
324             usage_message ();
325         }
326     } else if ("list" == command) {
327         // Usage: ecosconfig list
328         if (command_index == argc) {
329             status = exec.cmd_list ();
330         } else {
331             usage_message ();
332         }
333     } else if ("check" == command) {
334         // Usage: ecosconfig check
335         if (command_index == argc) {
336             status = exec.cmd_check ();
337         } else {
338             usage_message ();
339         }
340     } else if ("resolve" == command) {
341         // Usage: ecosconfig resolve
342         if (command_index == argc) {
343             status = exec.cmd_resolve ();
344         } else {
345             usage_message ();
346         }
347     } else if ("add" == command) {
348         // Usage: ecosconfig add <package> [<package2> ...]
349         if (command_index < argc) {
350             std::vector<std::string> packages;
351             for (int n = command_index; n < argc; n++) {
352                 packages.push_back (argv [n]);
353             }
354             status = exec.cmd_add (packages);
355         } else {
356             usage_message ();
357         }
358     } else if ("remove" == command) {
359         // Usage: ecosconfig remove <package> [<package2> ...]
360         if (command_index < argc) {
361             std::vector<std::string> packages;
362             for (int n = command_index; n < argc; n++) {
363                 packages.push_back (argv [n]);
364             }
365             status = exec.cmd_remove (packages);
366         } else {
367             usage_message ();
368         }
369     } else if ("version" == command) {
370         // Usage: ecosconfig version <version> <package> [<package2> ...]
371         // Note that it is not possible to change several packages to different versions. 
372         if (command_index + 1 < argc) {
373             std::vector<std::string> packages;
374             for (int n = command_index + 1; n < argc; n++) {
375                 packages.push_back (argv [n]);
376             }
377             status = exec.cmd_version (argv [command_index], packages);
378         } else {
379             usage_message ();
380         }
381
382     } else if ("target" == command) {
383         // Usage: ecosconfig target <target>
384         if (command_index + 1 == argc) {
385             status = exec.cmd_target (argv [command_index]);
386         } else {
387             usage_message ();
388         }
389
390     } else if ("template" == command) {
391         // Usage: ecosconfig template <template> [<version>]
392         if (command_index + 1 == argc) {
393             status = exec.cmd_template (argv [command_index]);
394         } else if (command_index + 2 == argc) {
395             status = exec.cmd_template (argv [command_index], argv [command_index]);
396         } else {
397             usage_message ();
398         }
399
400     } else if ("export" == command) {
401         // Usage: ecosconfige export <filename>
402         if (command_index + 1 == argc) {
403             std::string filename = std::string(argv[command_index]);
404             filename = TRANSLATE_PATH(filename);
405             status = exec.cmd_export(filename);
406         } else {
407             usage_message ();
408         }
409
410     } else if ("import" == command) {
411         // Usage: ecosconfig import <filename>
412         if (command_index + 1 == argc) {
413             std::string filename = std::string(argv[command_index]);
414             filename = TRANSLATE_PATH(filename);
415             status = exec.cmd_import(filename);
416         } else {
417             usage_message ();
418         }
419
420     } else {
421         usage_message ();
422     }
423
424     return status ? EXIT_SUCCESS : EXIT_FAILURE;
425 }
426
427 // remove the trailing directory separator from a file path if present
428 std::string trim_path (const std::string input) {
429     std::string output = input;
430     if (! output.empty ()) {
431         const char last_char = output [output.size () - 1];
432         if (('\\' == last_char) || ('/' == last_char)) { // if the last char is a directory separator
433             output.resize (output.size () - 1); // remove the last char
434         }
435     }
436     return output;
437 }
438
439 // print a usage message
440 void usage_message () {
441     printf ("Usage: ecosconfig [ qualifier ... ] [ command ]\n");
442     printf ("  commands are:\n");
443     printf ("    list                                       : list repository contents\n");
444     printf ("    new TARGET [ TEMPLATE [ VERSION ] ]        : create a configuration\n");
445     printf ("    target TARGET                              : change the target hardware\n");
446     printf ("    template TEMPLATE [ VERSION ]              : change the template\n");
447     printf ("    add PACKAGE [ PACKAGE ... ]                : add package(s)\n");
448     printf ("    remove PACKAGE [ PACKAGE ... ]             : remove package(s)\n");
449     printf ("    version VERSION PACKAGE [ PACKAGE ... ]    : change version of package(s)\n");
450     printf ("    export FILE                                : export minimal config info\n");
451     printf ("    import FILE                                : import additional config info\n");
452     printf ("    check                                      : check the configuration\n");
453     printf ("    resolve                                    : resolve conflicts\n");
454     printf ("    tree                                       : create a build tree\n");
455     printf ("  qualifiers are:\n");
456     printf ("    --config=FILE                              : the configuration file\n");
457     printf ("    --prefix=DIRECTORY                         : the install prefix\n");
458     printf ("    --srcdir=DIRECTORY                         : the source repository\n");
459     printf ("    --no-resolve                               : disable conflict resolution\n");
460     printf ("    --version                                  : show version and copyright\n");
461     printf ("    -q, --quiet                                : reduce verbosity\n");    
462     printf ("    -v, --verbose                              : increase verbosity\n");    
463     printf ("    -i, --ignore-errors                        : ignore unresolved conflicts\n");
464     printf ("    -n, --no-updates                           : read-only mode, do not modify the file system\n");
465     printf ("    --enable-debug                             : enable debugging in this configuration\n");
466     printf ("    --disable-debug                            : disable debugging in this configuration\n");
467     printf ("    --help                                     : display this message\n");
468 }