]> Git Repo - binutils.git/blob - gprofng/src/gp-archive.cc
Automatic date update in version.in
[binutils.git] / gprofng / src / gp-archive.cc
1 /* Copyright (C) 2021 Free Software Foundation, Inc.
2    Contributed by Oracle.
3
4    This file is part of GNU Binutils.
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3, or (at your option)
9    any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, 51 Franklin Street - Fifth Floor, Boston,
19    MA 02110-1301, USA.  */
20
21 #include "config.h"
22 #include <ctype.h>
23 #include <errno.h>
24 #include <unistd.h>
25 #include <getopt.h>
26
27 #include "util.h"
28 #include "StringMap.h"
29 #include "LoadObject.h"
30 #include "DbeSession.h"
31 #include "DbeFile.h"
32 #include "SourceFile.h"
33 #include "Elf.h"
34 #include "gp-archive.h"
35 #include "ArchiveExp.h"
36 #include "Print.h"
37 #include "Module.h"
38
39 er_archive::er_archive (int argc, char *argv[]) : DbeApplication (argc, argv)
40 {
41   force = 0;
42   common_archive_dir = NULL;
43   quiet = 0;
44   descendant = 1;
45   use_relative_path = 0;
46   s_option = ARCH_EXE_ONLY;
47   mask = NULL;
48 }
49
50 er_archive::~er_archive ()
51 {
52   if (mask)
53     {
54       for (long i = 0, sz = mask->size (); i < sz; i++)
55         {
56           regex_t *regex_desc = mask->get (i);
57           regfree (regex_desc);
58           delete regex_desc;
59         }
60       delete mask;
61     }
62   delete common_archive_dir;
63 }
64
65 int
66 er_archive::mask_is_on (const char *str)
67 {
68   if (mask == NULL)
69     return 1;
70   for (long i = 0, sz = mask->size (); i < sz; i++)
71     {
72       regex_t *regex_desc = mask->get (i);
73       if (regexec (regex_desc, str, 0, NULL, 0) == 0)
74         return 1;
75     }
76   return 0;
77 }
78
79 void
80 er_archive::usage ()
81 {
82 /*
83   fprintf (stderr, GTXT ("Usage: %s [-nqFV] [-a on|ldobjects|src|usedldobjects|usedsrc|off] [-m regexp] experiment\n"), whoami);
84 */
85
86 /*
87   Ruud - Isolate this line because it has an argument.  Otherwise it would be at the
88   end of this long list.
89 */
90   printf ( GTXT (
91     "Usage: gprofng archive [OPTION(S)] EXPERIMENT\n"));
92
93   printf ( GTXT (
94     "\n"
95     "Archive the associated application binaries and source files in a gprofng\n"
96     "experiment to make it self contained and portable.\n"
97     "\n"
98     "Options:\n"
99     "\n"
100     " --version           print the version number and exit.\n"
101     " --help              print usage information and exit.\n"
102     " --verbose {on|off}  enable (on) or disable (off) verbose mode; the default is \"off\".\n"
103     "\n"
104     " -a {off|on|ldobjects|src|usedldobjects|usedsrc}  specify archiving of binaries and other files;\n"
105     "                    in addition to disable this feature (off), or enable archiving off all\n"
106     "                    loadobjects and sources (on), the other options support a more\n"
107     "                    refined selection. All of these options enable archiving, but the\n"
108     "                    keyword controls what exactly is selected: all load objects (ldobjects),\n"
109     "                    all source files (src), the loadobjects asscoiated with a program counter\n"
110     "                    (usedldobjects), or the source files associated with a program counter\n"
111     "                    (usedsrc); the default is \"-a ldobjects\".\n"
112     "\n"
113     " -n                 archive the named experiment only, not any of its descendants.\n"
114     "\n"
115     " -q                 do not write any warnings to stderr; messages are archived and\n"
116     "                    can be retrieved later.\n"
117     "\n"
118     " -F                 force writing or rewriting of the archive; ignored with the -n\n"
119     "                    or -m options, or if this is a subexperiment.\n"
120     "\n"
121     " -d <path>          specifies the location of a common archive; this is a directory that\n"
122     "                    contains archived files.\n"
123     "\n"
124     " -m <regex>         archive only those source, object, and debug info files whose full\n"
125     "                    path name matches the given POSIX compliant regular expression.\n"
126     "\n"
127     "Limitations:\n"
128     "\n"
129     "Default archiving does not occur in case the application profiled terminates prematurely,\n"
130     "or if archiving is disabled when collecting the performance data. In such cases, this\n"
131     "tool can be used to afterwards archive the information, but it has to run on the same \n"
132     "system where the profiling data was recorded.\n"
133     "\n"
134     "Documentation:\n"
135     "\n"
136     "A getting started guide for gprofng is maintained as a Texinfo manual. If the info and\n"
137     "gprofng programs are properly installed at your site, the command \"info gprofng\"\n"
138     "should give you access to this document.\n"
139     "\n"
140     "See also:\n"
141     "\n"
142     "gprofng(1), gp-collect-app(1), gp-display-html(1), gp-display-src(1), gp-display-text(1)\n"));
143 // Ruud
144 /*
145   fprintf (stderr, GTXT ("GNU %s version %s\n"), get_basename (prog_name), VERSION);
146 */
147   exit (1);
148 }
149
150 Vector <LoadObject*> *
151 er_archive::get_loadObjs ()
152 {
153   Vector <LoadObject*> *objs = new Vector<LoadObject*>();
154   Vector <LoadObject*> *loadObjs = dbeSession->get_text_segments ();
155   if (s_option != ARCH_NOTHING)
156     {
157       for (long i = 0, sz = VecSize(loadObjs); i < sz; i++)
158         {
159           LoadObject *lo = loadObjs->get (i);
160           if ((lo->flags & SEG_FLAG_DYNAMIC) != 0)
161             continue;
162           DbeFile *df = lo->dbeFile;
163           if (df && ((df->filetype & DbeFile::F_FICTION) != 0))
164             continue;
165           if (!lo->isUsed && ((s_option & (ARCH_USED_EXE_ONLY | ARCH_USED_SRC_ONLY)) != 0))
166             continue;
167           objs->append (lo);
168         }
169     }
170   if (DEBUG_ARCHIVE)
171     {
172       Dprintf (DEBUG_ARCHIVE, NTXT ("get_text_segments(): %d\n"),
173                (int) (loadObjs ? loadObjs->size () : -1));
174       for (long i = 0, sz = loadObjs ? loadObjs->size () : 0; i < sz; i++)
175         {
176           LoadObject *lo = loadObjs->get (i);
177           Dprintf (DEBUG_ARCHIVE, NTXT ("%s:%d  [%2ld] %s\n"),
178                    get_basename (__FILE__), (int) __LINE__, i, STR (lo->dump ()));
179         }
180       Dprintf (DEBUG_ARCHIVE, NTXT ("\nget_loadObjs(): %d\n"),
181                (int) (objs ? objs->size () : -1));
182       for (long i = 0, sz = VecSize(objs); i < sz; i++)
183         {
184           LoadObject *lo = objs->get (i);
185           Dprintf (DEBUG_ARCHIVE, NTXT ("%s:%d  [%2ld] %s\n"),
186                    get_basename (__FILE__), (int) __LINE__, i, STR (lo->dump ()));
187         }
188     }
189   delete loadObjs;
190   return objs;
191 }
192
193 /**
194  * Clean old archive
195  * Except the following cases:
196  * 1. Founder experiment is an MPI experiment
197  * 2. "-n" option is passed (do not archive descendants)
198  * 3. "-m" option is passed (partial archiving)
199  * 4. Experiment name is not the founder experiment (it is a sub-experiment)
200  * @param expname
201  * @param founder_exp
202  * @return 0 - success
203  */
204 int
205 er_archive::clean_old_archive (char *expname, ArchiveExp *founder_exp)
206 {
207   if (0 == descendant)
208     { // do not archive descendants
209       fprintf (stderr, GTXT ("Warning: Option -F is ignored because -n option is specified (do not archive descendants)\n"));
210       return 1;
211     }
212   if (NULL != mask)
213     { // partial archiving
214       fprintf (stderr, GTXT ("Warning: Option -F is ignored because -m option is specified\n"));
215       return 1;
216     }
217   // Check if the experiment is the founder
218   char *s1 = dbe_strdup (expname);
219   char *s2 = dbe_strdup (founder_exp->get_expt_name ());
220   if (!s1 || !s2)
221     {
222       fprintf (stderr, GTXT ("Cannot allocate memory\n"));
223       exit (1);
224     }
225   // remove trailing slashes
226   for (int n = strlen (s1); n > 0; n--)
227     {
228       if ('/' != s1[n - 1])
229         break;
230       s1[n - 1] = 0;
231     }
232   for (int n = strlen (s2); n > 0; n--)
233     {
234       if ('/' != s2[n - 1])
235         break;
236       s2[n - 1] = 0;
237     }
238   if (strcmp (s1, s2) != 0)
239     { // not founder
240       fprintf (stderr, GTXT ("Warning: Option -F is ignored because specified experiment name %s does not match founder experiment name %s\n"), s1, s2);
241       free (s1);
242       free (s2);
243       return 1;
244     }
245   // Remove old "archives"
246   char *arch = founder_exp->get_arch_name ();
247   fprintf (stderr, GTXT ("INFO: removing existing archive: %s\n"), arch);
248   if (dbe_stat (arch, NULL) == 0)
249     {
250       char *cmd = dbe_sprintf ("/bin/rm -rf %s", arch);
251       system (cmd);
252       free (cmd);
253       if (dbe_stat (arch, NULL) != 0)
254         { // create "archives"
255           if (!founder_exp->create_dir (founder_exp->get_arch_name ()))
256             {
257               fprintf (stderr, GTXT ("Unable to create directory `%s'\n"), founder_exp->get_arch_name ());
258               exit (1);
259             }
260         }
261     }
262   free (s1);
263   free (s2);
264   return 0;
265 } // clean_old_archive_if_necessary
266
267 void
268 er_archive::start (int argc, char *argv[])
269 {
270   int last = argc - 1;
271   if (check_args (argc, argv) != last)
272     usage ();
273   check_env_var ();
274   if (s_option == ARCH_NOTHING)
275     return;
276
277   ArchiveExp *founder_exp = new ArchiveExp (argv[last]);
278   if (founder_exp->get_status () == Experiment::FAILURE)
279     {
280       if (!quiet)
281         fprintf (stderr, GTXT ("er_archive: %s: %s\n"), argv[last],
282                  pr_mesgs (founder_exp->fetch_errors (), NTXT (""), NTXT ("")));
283       exit (1);
284     }
285   if (!founder_exp->create_dir (founder_exp->get_arch_name ()))
286     {
287       fprintf (stderr, GTXT ("Unable to create directory `%s'\n"), founder_exp->get_arch_name ());
288       exit (1);
289     }
290   if (!common_archive_dir)
291     common_archive_dir = dbe_strdup (getenv ("GPROFNG_ARCHIVE_COMMON_DIR"));
292   if (common_archive_dir)
293     {
294       if (!founder_exp->create_dir (common_archive_dir))
295         if (dbe_stat (common_archive_dir, NULL) != 0)
296           {
297             fprintf (stderr, GTXT ("Unable to create directory for common archive `%s'\n"), common_archive_dir);
298             exit (1);
299           }
300     }
301   // Clean old archives if necessary
302   if (force)
303     clean_old_archive (argv[last], founder_exp);
304   Vector<ArchiveExp*> *exps = new Vector<ArchiveExp*>();
305   exps->append (founder_exp);
306   if (descendant)
307     {
308       Vector<char*> *exp_names = founder_exp->get_descendants_names ();
309       if (exp_names)
310         {
311           for (long i = 0, sz = exp_names->size (); i < sz; i++)
312             {
313               char *exp_path = exp_names->get (i);
314               ArchiveExp *exp = new ArchiveExp (exp_path);
315               if (exp->get_status () == Experiment::FAILURE)
316                 {
317                   if (!quiet)
318                     fprintf (stderr, GTXT ("er_archive: %s: %s\n"), exp_path,
319                              pr_mesgs (exp->fetch_errors (), NTXT (""), NTXT ("")));
320                   delete exp;
321                   continue;
322                 }
323               exps->append (exp);
324             }
325           exp_names->destroy ();
326           delete exp_names;
327         }
328     }
329   for (long i = 0, sz = exps->size (); i < sz; i++)
330     {
331       ArchiveExp *exp = exps->get (i);
332       exp->read_data (s_option);
333     }
334
335   Vector <DbeFile*> *copy_files = new Vector<DbeFile*>();
336   Vector <LoadObject*> *loadObjs = get_loadObjs ();
337   for (long i = 0, sz = VecSize(loadObjs); i < sz; i++)
338     {
339       LoadObject *lo = loadObjs->get (i);
340       if (strcmp (lo->get_pathname (), "LinuxKernel") == 0)
341         continue;
342       DbeFile *df = lo->dbeFile;
343       if ((df->filetype & DbeFile::F_FICTION) != 0)
344         continue;
345       if (df->get_location () == NULL)
346         {
347           copy_files->append (df);
348           continue;
349         }
350       if ((df->filetype & DbeFile::F_JAVACLASS) != 0)
351         {
352           if (df->container)
353             { // Found in .jar file
354               copy_files->append (df->container);
355             }
356           copy_files->append (df);
357           if ((s_option & ARCH_EXE_ONLY) != 0)
358             continue;
359         }
360       lo->sync_read_stabs ();
361       Elf *elf = lo->get_elf ();
362       if (elf && (lo->checksum != 0) && (lo->checksum != elf->elf_checksum ()))
363         {
364           if (!quiet)
365             fprintf (stderr, GTXT ("er_archive: '%s' has an unexpected checksum value; perhaps it was rebuilt. File ignored\n"),
366                        df->get_location ());
367           continue;
368         }
369       copy_files->append (df);
370       if (elf)
371         {
372           Elf *f = elf->find_ancillary_files (lo->get_pathname ());
373           if (f)
374             copy_files->append (f->dbeFile);
375           for (long i1 = 0, sz1 = VecSize(elf->ancillary_files); i1 < sz1; i1++)
376             {
377               Elf *ancElf = elf->ancillary_files->get (i1);
378               copy_files->append (ancElf->dbeFile);
379             }
380         }
381       Vector<Module*> *modules = lo->seg_modules;
382       for (long i1 = 0, sz1 = VecSize(modules); i1 < sz1; i1++)
383         {
384           Module *mod = modules->get (i1);
385           if ((mod->flags & MOD_FLAG_UNKNOWN) != 0)
386             continue;
387           else if ((s_option & (ARCH_USED_EXE_ONLY | ARCH_USED_SRC_ONLY)) != 0 &&
388                    !mod->isUsed)
389             continue;
390           if ((s_option & ARCH_ALL) != 0)
391             mod->read_stabs (false); // Find all Sources
392           if (mod->dot_o_file && mod->dot_o_file->dbeFile)
393             copy_files->append (mod->dot_o_file->dbeFile);
394         }
395     }
396   delete loadObjs;
397
398   int bmask = DbeFile::F_LOADOBJ | DbeFile::F_JAVACLASS | DbeFile::F_JAR_FILE |
399           DbeFile::F_DOT_O | DbeFile::F_DEBUG_FILE;
400   if ((s_option & (ARCH_USED_SRC_ONLY | ARCH_ALL)) != 0)
401     {
402       bmask |= DbeFile::F_JAVA_SOURCE | DbeFile::F_SOURCE;
403       Vector<SourceFile*> *sources = dbeSession->get_sources ();
404       for (long i = 0, sz = VecSize(sources); i < sz; i++)
405         {
406           SourceFile *src = sources->get (i);
407           if ((src->flags & SOURCE_FLAG_UNKNOWN) != 0)
408             continue;
409           else if ((s_option & ARCH_USED_SRC_ONLY) != 0)
410             {
411               if ((src->dbeFile->filetype & DbeFile::F_JAVA_SOURCE) != 0 &&
412                   !src->isUsed)
413                 continue;
414             }
415           if (src->dbeFile)
416             copy_files->append (src->dbeFile);
417         }
418     }
419
420   Vector <DbeFile*> *notfound_files = new Vector<DbeFile*>();
421   for (long i = 0, sz = VecSize(copy_files); i < sz; i++)
422     {
423       DbeFile *df = copy_files->get (i);
424       char *fnm = df->get_location ();
425       char *nm = df->get_name ();
426       Dprintf (DEBUG_ARCHIVE,
427                "%s::%d copy_files[%ld] filetype=%4d inArchive=%d '%s' --> '%s'\n",
428                get_basename (__FILE__), (int) __LINE__, i,
429                df->filetype, df->inArchive ? 1 : 0, STR (nm), STR (fnm));
430       Dprintf (DEBUG_ARCHIVE && df->container,
431                "    copy_files[%ld]: Found '%s' in '%s'\n",
432                i, STR (nm), STR (df->container->get_name ()));
433       if (fnm == NULL)
434         {
435           if (!quiet)
436             notfound_files->append (df);
437           continue;
438         }
439       else if (df->inArchive)
440         {
441           Dprintf (DEBUG_ARCHIVE,
442                    "  NOT COPIED: copy_files[%ld]: inArchive=1 '%s'\n",
443                    i, STR (nm));
444           continue;
445         }
446       else if ((df->filetype & bmask) == 0)
447         {
448           Dprintf (DEBUG_ARCHIVE,
449                    "  NOT COPIED: copy_files[%ld]: container=%p filetype=%d bmask=%d '%s'\n",
450                    i, df->container, df->filetype, bmask, STR (nm));
451           continue;
452         }
453       else if (df->container &&
454                (df->filetype & (DbeFile::F_JAVA_SOURCE | DbeFile::F_SOURCE)) == 0)
455         {
456           Dprintf (DEBUG_ARCHIVE,
457                    "  NOT COPIED: copy_files[%ld]: container=%p filetype=%d bmask=%d '%s'\n",
458                    i, df->container, df->filetype, bmask, STR (nm));
459           continue;
460         }
461       else if (!mask_is_on (df->get_name ()))
462         {
463           Dprintf (DEBUG_ARCHIVE,
464                    "  NOT COPIED: copy_files[%ld]: mask is off for '%s'\n",
465                    i, STR (nm));
466           continue;
467         }
468       char *anm = founder_exp->getNameInArchive (nm, false);
469       if (force)
470         unlink (anm);
471       int res = founder_exp->copy_file (fnm, anm, quiet, common_archive_dir, use_relative_path);
472       if (0 == res)  // file successfully archived
473         df->inArchive = 1;
474       delete anm;
475     }
476   delete copy_files;
477
478   if (notfound_files->size () > 0)
479     {
480       for (long i = 0, sz = notfound_files->size (); i < sz; i++)
481         {
482           DbeFile *df = notfound_files->get (i);
483           fprintf (stderr, GTXT ("er_archive: Cannot find file: `%s'\n"), df->get_name ());
484         }
485       fprintf (stderr, GTXT ("\n If you know the correct location of the missing file(s)"
486                              " you can help %s to find them by manually editing the .gprofng.rc file."
487                              " See %s man pages for more details.\n"),
488                whoami, whoami);
489     }
490   delete notfound_files;
491 }
492
493 int
494 er_archive::check_args (int argc, char *argv[])
495 {
496   int opt;
497   int rseen = 0;
498   int dseen = 0;
499   // Parsing the command line
500   opterr = 0;
501   optind = 1;
502   static struct option long_options[] = {
503     {"help",    no_argument,        0, 'h'},
504     {"version", no_argument,        0, 'V'},
505     {"whoami",  required_argument,  0, 'w'},
506     {"outfile", required_argument,  0, 'O'},
507     {NULL, 0, 0, 0}
508   };
509   while (1)
510     {
511       int option_index = 0;
512       opt = getopt_long (argc, argv, NTXT (":VFa:d:qnr:m:"),
513                          long_options, &option_index);
514       if (opt == EOF)
515         break;
516       switch (opt)
517         {
518         case 'F':
519           force = 1;
520           break;
521         case 'd': // Common archive directory (absolute path)
522           if (rseen)
523             {
524               fprintf (stderr, GTXT ("Error: invalid combination of options: -r and -d are in conflict.\n"));
525               return -1;
526             }
527           if (dseen)
528             fprintf (stderr, GTXT ("Warning: option -d was specified several times. Last value is used.\n"));
529           free (common_archive_dir);
530           common_archive_dir = strdup (optarg);
531           dseen = 1;
532           break;
533         case 'q':
534           quiet = 1;
535           break;
536         case 'n':
537           descendant = 0;
538           break;
539         case 'r': // Common archive directory (relative path)
540           if (dseen)
541             {
542               fprintf (stderr, GTXT ("Error: invalid combination of options: -d and -r are in conflict.\n"));
543               return -1;
544             }
545           if (rseen)
546             fprintf (stderr, GTXT ("Warning: option -r was specified several times. Last value is used.\n"));
547           free (common_archive_dir);
548           common_archive_dir = strdup (optarg);
549           use_relative_path = 1;
550           rseen = 1;
551           break;
552         case 'a':
553           if (strcmp (optarg, "off") == 0)
554             s_option = ARCH_NOTHING;
555           else if (strcmp (optarg, "on") == 0 ||
556                    strcmp (optarg, "ldobjects") == 0)
557             s_option = ARCH_EXE_ONLY;
558           else if (strcmp (optarg, "usedldobjects") == 0)
559             s_option = ARCH_USED_EXE_ONLY;
560           else if (strcmp (optarg, "usedsrc") == 0)
561             s_option = ARCH_USED_EXE_ONLY | ARCH_USED_SRC_ONLY;
562           else if (strcmp (optarg, "all") == 0 || strcmp (optarg, "src") == 0)
563             s_option = ARCH_ALL;
564           else
565             {
566               fprintf (stderr, GTXT ("Error: invalid option: `-%c %s'\n"),
567                        optopt, optarg);
568               return -1;
569             }
570           break;
571         case 'm':
572           {
573             regex_t *regex_desc = new regex_t ();
574             if (regcomp (regex_desc, optarg, REG_EXTENDED | REG_NOSUB | REG_NEWLINE))
575               {
576                 delete regex_desc;
577                 fprintf (stderr, GTXT ("Error: invalid option: `-%c %s'\n"),
578                          optopt, optarg);
579                 return -1;
580               }
581             if (mask == NULL)
582               mask = new Vector<regex_t *>();
583             mask->append (regex_desc);
584             break;
585           }
586         case 'O':
587           {
588             int fd = open (optarg, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
589             if (fd == -1)
590               {
591                 fprintf (stderr, GTXT ("er_archive: Can't open %s: %s\n"),
592                          optarg, strerror (errno));
593                 break;
594               }
595             if (dup2 (fd, 2) == -1)
596               {
597                 close (fd);
598                 fprintf (stderr, GTXT ("er_archive: Can't divert stderr: %s\n"),
599                          strerror (errno));
600                 break;
601               }
602             if (dup2 (fd, 1) == -1)
603               {
604                 close (fd);
605                 fprintf (stderr, GTXT ("er_archive: Can't divert stdout: %s\n"),
606                          strerror (errno));
607                 break;
608               }
609             close (fd);
610             struct timeval tp;
611             gettimeofday (&tp, NULL);
612             fprintf (stderr, "### Start %s#", ctime (&tp.tv_sec));
613             for (int i = 0; i < argc; i++)
614               fprintf (stderr, " %s", argv[i]);
615             fprintf (stderr, "\n");
616             break;
617           }
618         case 'V':
619 // Ruud
620           Application::print_version_info ();
621 /*
622           printf (GTXT ("GNU %s version %s\n"), get_basename (prog_name), VERSION);
623 */
624           exit (0);
625         case 'w':
626           whoami = optarg;
627           break;
628         case 'h':
629           usage ();
630           exit (0);
631         case ':': // -s -m without operand
632           fprintf (stderr, GTXT ("Option -%c requires an operand\n"), optopt);
633           return -1;
634         case '?':
635         default:
636           fprintf (stderr, GTXT ("Unrecognized option: -%c\n"), optopt);
637           return -1;
638         }
639     }
640   return optind;
641 }
642
643 void
644 er_archive::check_env_var ()
645 {
646   char *ename = NTXT ("GPROFNG_ARCHIVE");
647   char *var = getenv (ename);
648   if (var == NULL)
649     return;
650   var = dbe_strdup (var);
651   Vector<char*> *opts = new Vector<char*>();
652   opts->append (ename);
653   for (char *s = var;;)
654     {
655       while (*s && isblank (*s))
656         s++;
657       if (*s == 0)
658         break;
659       opts->append (s);
660       while (*s && !isblank (*s))
661         s++;
662       if (*s == 0)
663         break;
664       *s = 0;
665       s++;
666     }
667   if (opts->size () > 0)
668     {
669       char **arr = (char **) malloc (sizeof (char *) *opts->size ());
670       for (long i = 0; i < opts->size (); i++)
671         arr[i] = opts->get (i);
672       if (-1 == check_args (opts->size (), arr))
673         fprintf (stderr, GTXT ("Error: Wrong SP_ER_ARCHIVE: '%s'\n"), var);
674       free (arr);
675     }
676   delete opts;
677   free (var);
678 }
679
680 static int
681 real_main (int argc, char *argv[])
682 {
683   er_archive *archive = new er_archive (argc, argv);
684   dbeSession->archive_mode = 1;
685   archive->start (argc, argv);
686   dbeSession->unlink_tmp_files ();
687   return 0;
688 }
689
690 /**
691  * Call catch_out_of_memory(int (*real_main)(int, char*[]), int argc, char *argv[]) which will call real_main()
692  * @param argc
693  * @param argv
694  * @return
695  */
696 int
697 main (int argc, char *argv[])
698 {
699   return catch_out_of_memory (real_main, argc, argv);
700 }
This page took 0.065748 seconds and 4 git commands to generate.