1/* A program to enquire about the configuration of the PPL  -*- C++ -*-
2   and of the applications using it.
3   Copyright (C) 2001-2010 Roberto Bagnara <bagnara@cs.unipr.it>
4   Copyright (C) 2010-2016 BUGSENG srl (http://bugseng.com)
5
6This file is part of the Parma Polyhedra Library (PPL).
7
8The PPL is free software; you can redistribute it and/or modify it
9under the terms of the GNU General Public License as published by the
10Free Software Foundation; either version 3 of the License, or (at your
11option) any later version.
12
13The PPL is distributed in the hope that it will be useful, but WITHOUT
14ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16for more details.
17
18You should have received a copy of the GNU General Public License
19along with this program; if not, write to the Free Software Foundation,
20Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA.
21
22For the most up-to-date information see the Parma Polyhedra Library
23site: http://bugseng.com/products/ppl/ . */
24
25#include "ppl.hh"
26#include "BUGS.hh"
27#include "COPYING.hh"
28#include "CREDITS.hh"
29
30namespace PPL = Parma_Polyhedra_Library;
31
32#if PPL_VERSION_MAJOR == 0 && PPL_VERSION_MINOR < 8
33#error "PPL version 0.8 or following is required"
34#endif
35
36#include <cstdarg>
37#include <cstring>
38#include <cctype>
39#include <cstdio>
40#include <cstdlib>
41#include <iostream>
42#include <stdexcept>
43#include <string>
44
45#ifdef PPL_HAVE_GETOPT_H
46#include <getopt.h>
47
48// Try to accommodate non-GNU implementations of `getopt()'.
49#if !defined(no_argument) && defined(NO_ARG)
50#define no_argument NO_ARG
51#endif
52
53#if !defined(required_argument) && defined(REQUIRED_ARG)
54#define required_argument REQUIRED_ARG
55#endif
56
57#if !defined(optional_argument) && defined(OPTIONAL_ARG)
58#define optional_argument OPTIONAL_ARG
59#endif
60
61#endif // defined(PPL_HAVE_GETOPT_H)
62
63#ifdef PPL_HAVE_UNISTD_H
64// Include this for `getopt()': especially important if we do not have
65// <getopt.h>.
66#include <unistd.h>
67#endif
68
69
70namespace {
71
72enum Format {
73  NO_FORMAT,
74  PLAIN,
75  MAKEFILE,
76  SH,
77  CSH
78};
79
80enum Interface {
81  NO_INTERFACE,
82  CXX,
83  C,
84  CIAO_PROLOG,
85  GNU_PROLOG,
86  SICSTUS_PROLOG,
87  SWI_PROLOG,
88  XSB_PROLOG,
89  YAP_PROLOG,
90  OCAML,
91  JAVA
92};
93
94Format required_format = NO_FORMAT;
95
96Interface required_interface = NO_INTERFACE;
97
98#define PPL_LICENSE "GNU GENERAL PUBLIC LICENSE, Version 3"
99
100std::string prefix;
101std::string exec_prefix;
102
103bool required_application = false;
104bool required_library = false;
105bool required_prefix = false;
106bool required_exec_prefix = false;
107bool required_configure_options = false;
108bool required_version = false;
109bool required_version_major = false;
110bool required_version_minor = false;
111bool required_version_revision = false;
112bool required_version_beta = false;
113bool required_banner = false;
114bool required_coefficients = false;
115bool required_includedir = false;
116bool required_bindir = false;
117bool required_libdir = false;
118bool required_cppflags = false;
119bool required_cflags = false;
120bool required_cxxflags = false;
121bool required_ldflags = false;
122bool required_license = false;
123bool required_copying = false;
124bool required_bugs = false;
125bool required_credits = false;
126
127unsigned num_required_items = 0;
128
129
130#define OPTION_LETTERS "hF:I:ALp::e::OVMNRBEniblPCXDgcur"
131
132const char* program_name = 0;
133
134void
135fatal(const char* format, ...) __attribute__((__noreturn__));
136
137void
138fatal(const char* format, ...) {
139  va_list ap;
140  va_start(ap, format);
141  fprintf(stderr, "%s: ", program_name);
142  vfprintf(stderr, format, ap);
143  fprintf(stderr, "\n");
144  va_end(ap);
145  exit(1);
146}
147
148void
149internal_error() __attribute__((__noreturn__));
150
151void
152internal_error() {
153  fatal("internal error: please submit a bug report to ppl-devel@cs.unipr.it");
154}
155
156inline char
157to_lower(char c) {
158  return
159    static_cast<char>(tolower(static_cast<int>(static_cast<unsigned char>(c))));
160}
161
162bool
163strcaseeq(const char* s1, const char* s2) {
164  while (*s1 != '\0') {
165    if (*s2 == '\0' || to_lower(*s1) != to_lower(*s2))
166      return false;
167    ++s1;
168    ++s2;
169  }
170  return *s2 == '\0';
171}
172
173void
174process_options(int argc, char* argv[]) {
175
176  bool exec_prefix_set = false;
177
178#ifdef PPL_HAVE_GETOPT_H
179struct option long_options[] = {
180  {"help",              no_argument,       0, 'h'},
181  {"format",            required_argument, 0, 'F'},
182  {"interface",         required_argument, 0, 'I'},
183  {"application",       no_argument,       0, 'A'},
184  {"library",           no_argument,       0, 'L'},
185  {"prefix",            optional_argument, 0, 'p'},
186  {"exec-prefix",       optional_argument, 0, 'e'},
187  {"configure-options", no_argument,       0, 'O'},
188  {"version",           no_argument,       0, 'V'},
189  {"version-major",     no_argument,       0, 'M'},
190  {"version-minor",     no_argument,       0, 'N'},
191  {"version-revision",  no_argument,       0, 'R'},
192  {"version-beta",      no_argument,       0, 'B'},
193  {"banner",            no_argument,       0, 'E'},
194  {"coefficients",      no_argument,       0, 'n'},
195  {"includedir",        no_argument,       0, 'i'},
196  {"bindir",            no_argument,       0, 'b'},
197  {"libdir",            no_argument,       0, 'l'},
198  {"cppflags",          no_argument,       0, 'P'},
199  {"cflags",            no_argument,       0, 'C'},
200  {"cxxflags",          no_argument,       0, 'X'},
201  {"ldflags",           no_argument,       0, 'D'},
202  {"license",           no_argument,       0, 'g'},
203  {"copying",           no_argument,       0, 'c'},
204  {"bugs",              no_argument,       0, 'u'},
205  {"credits",           no_argument,       0, 'r'},
206  {0, 0, 0, 0}
207};
208#endif
209
210  static const char* usage_string
211  = "Usage: %s [OPTION]...\n"
212"Displays information, in various formats, about an installation\n"
213"of the Parma Polyhedra Library.\n\n"
214"Options:\n"
215"  -h, --help               prints this help text to stdout\n"
216"  -FFMT, --format=FMT      sets the output format to FMT\n"
217"                           (one of `plain', `makefile', `sh' or `csh')\n"
218"  -IINT, --interface=INT   selects a library interface (one of `C++', `C',\n"
219"                           `Ciao-Prolog', `GNU-Prolog', `SICStus-Prolog',\n"
220"                           `SWI-Prolog', `XSB-Prolog', `YAP-Prolog',\n"
221"                           `OCaml' or `Java')\n"
222"  -A, --application        selects output for building an application\n"
223"  -L, --library            selects output for building a library\n"
224"  -p[PFX], --prefix[=PFX]  prints or sets library prefix information\n"
225"  -e[PFX], --exec-prefix[=PFX]\n"
226"                           prints or sets library exec-prefix information\n"
227"  -O, --configure-options  prints configuration options\n"
228"  -V, --version            prints version information\n"
229"  -M, --version-major      prints version major number\n"
230"  -N, --version-minor      prints version minor number\n"
231"  -R, --version-revision   prints version revision number\n"
232"  -B, --version-beta       prints version beta number\n"
233"  -E, --banner             prints library banner\n"
234"  -n, --coefficients       prints type of library coefficients\n"
235"  -i, --includedir         prints include files directory\n"
236"  -b, --bindir             prints binary executables directory\n"
237"  -l, --libdir             prints library files directory\n"
238"  -P, --cppflags           prints preprocessor flags\n"
239"  -C, --cflags             prints C compiler flags\n"
240"  -X, --cxxflags           prints C++ compiler flags\n"
241"  -D, --ldflags            prints linker flags\n"
242"  -g, --license            prints synthetic licensing information\n"
243"  -c, --copying            prints detailed licensing information\n"
244"  -u, --bugs               prints bug reporting information\n"
245"  -r, --credits            prints credits\n"
246#ifndef PPL_HAVE_GETOPT_H
247"\n"
248"NOTE: this version does not support long options.\n"
249#endif
250"\n"
251"Report bugs to <ppl-devel@cs.unipr.it>.\n";
252
253  while (true) {
254#ifdef PPL_HAVE_GETOPT_H
255    int option_index = 0;
256    int c = getopt_long(argc, argv, OPTION_LETTERS, long_options,
257                        &option_index);
258#else
259    int c = getopt(argc, argv, OPTION_LETTERS);
260#endif
261
262    if (c == EOF)
263      break;
264
265    switch (c) {
266    case 0:
267      break;
268
269    case '?':
270    case 'h':
271      fprintf(stdout, usage_string, argv[0]);
272      exit(0);
273      break;
274
275      // --format
276    case 'F':
277      if (strcaseeq(optarg, "plain"))
278        required_format = PLAIN;
279      else if (strcaseeq(optarg, "makefile"))
280        required_format = MAKEFILE;
281      else if (strcaseeq(optarg, "sh"))
282        required_format = SH;
283      else if (strcaseeq(optarg, "csh"))
284        required_format = CSH;
285      else
286        fatal("invalid argument `%s' to --format: "
287              "must be `plain', `makefile', `sh' or `csh'",
288              optarg);
289      break;
290
291      // --interface
292    case 'I':
293      if (strcaseeq(optarg, "C++"))
294        required_interface = CXX;
295      else if (strcaseeq(optarg, "C"))
296        required_interface = C;
297      else if (strcaseeq(optarg, "Ciao-Prolog"))
298        required_interface = CIAO_PROLOG;
299      else if (strcaseeq(optarg, "GNU-Prolog"))
300        required_interface = GNU_PROLOG;
301      else if (strcaseeq(optarg, "SICStus-Prolog"))
302        required_interface = SICSTUS_PROLOG;
303      else if (strcaseeq(optarg, "SWI-Prolog"))
304        required_interface = SWI_PROLOG;
305      else if (strcaseeq(optarg, "XSB-Prolog"))
306        required_interface = XSB_PROLOG;
307      else if (strcaseeq(optarg, "YAP-Prolog"))
308        required_interface = YAP_PROLOG;
309      else if (strcaseeq(optarg, "OCaml"))
310        required_interface = OCAML;
311      else if (strcaseeq(optarg, "Java"))
312        required_interface = JAVA;
313      else
314        fatal("invalid argument `%s' to --interface: "
315              "must be `C++', `C', `Ciao-Prolog', `GNU-Prolog', "
316              "`SICStus-Prolog', `SWI-Prolog', `XSB-Prolog', `YAP-Prolog', "
317              "`OCaml' or `Java'",
318              optarg);
319      break;
320
321      // --application
322    case 'A':
323      required_application = true;
324      break;
325
326      // --library
327    case 'L':
328      required_library = true;
329      break;
330
331      // --prefix
332    case 'p':
333      if (optarg != 0) {
334        prefix = optarg;
335        if (!exec_prefix_set) {
336          exec_prefix = optarg;
337          exec_prefix_set = true;
338        }
339      }
340      else {
341        required_prefix = true;
342        ++num_required_items;
343      }
344      break;
345
346      // --exec_prefix
347    case 'e':
348      if (optarg != 0) {
349        exec_prefix = optarg;
350        exec_prefix_set = true;
351      }
352      else {
353        required_exec_prefix = true;
354        ++num_required_items;
355      }
356      break;
357
358      // --configure-options
359    case 'O':
360      required_configure_options = true;
361      ++num_required_items;
362      break;
363
364      // --version
365    case 'V':
366      required_version = true;
367      ++num_required_items;
368      break;
369
370      // --version-major
371    case 'M':
372      required_version_major = true;
373      ++num_required_items;
374      break;
375
376      // --version-minor
377    case 'N':
378      required_version_minor = true;
379      ++num_required_items;
380      break;
381
382      // --version-revision
383    case 'R':
384      required_version_revision = true;
385      ++num_required_items;
386      break;
387
388      // --version-beta
389    case 'B':
390      required_version_beta = true;
391      ++num_required_items;
392      break;
393
394      // --banner
395    case 'E':
396      required_banner = true;
397      ++num_required_items;
398      break;
399
400      // --coefficients
401    case 'n':
402      required_coefficients = true;
403      ++num_required_items;
404      break;
405
406      // --includedir
407    case 'i':
408      required_includedir = true;
409      ++num_required_items;
410      break;
411
412      // --bindir
413    case 'b':
414      required_bindir = true;
415      ++num_required_items;
416      break;
417
418      // --libdir
419    case 'l':
420      required_libdir = true;
421      ++num_required_items;
422      break;
423
424      // --cppflags
425    case 'P':
426      required_cppflags = true;
427      ++num_required_items;
428      break;
429
430      // --cflags
431    case 'C':
432      required_cflags = true;
433      ++num_required_items;
434      break;
435
436      // --cxxflags
437    case 'X':
438      required_cxxflags = true;
439      ++num_required_items;
440      break;
441
442      // --ldflags
443    case 'D':
444      required_ldflags = true;
445      ++num_required_items;
446      break;
447
448      // --license
449    case 'g':
450      required_license = true;
451      ++num_required_items;
452      break;
453
454      // --copying
455    case 'c':
456      required_copying = true;
457      ++num_required_items;
458      break;
459
460      // --bugs
461    case 'u':
462      required_bugs = true;
463      ++num_required_items;
464      break;
465
466      // --credits
467    case 'r':
468      required_credits = true;
469      ++num_required_items;
470      break;
471
472    default:
473      abort();
474    }
475  }
476
477  if (argc != optind)
478    // We have a spurious argument.
479    fatal("no arguments besides options are accepted");
480
481  if (required_application && required_library)
482    fatal("the --application and --library are mutually exclusive");
483
484  if (!required_application && !required_library)
485    required_application = true;
486
487  if (required_format == NO_FORMAT)
488    required_format = PLAIN;
489
490  if (required_interface == NO_INTERFACE)
491    required_interface = CXX;
492}
493
494void
495portray_name(const char* name) {
496  const char* variable_prefix = "PPL_";
497  switch (required_format) {
498  case PLAIN:
499    if (num_required_items > 1)
500      std::cout << variable_prefix << name << ": ";
501    break;
502  case MAKEFILE:
503    std::cout << variable_prefix << name << '=';
504    break;
505  case SH:
506    std::cout << "export " << variable_prefix << name << '=';
507    break;
508  case CSH:
509    std::cout << "setenv " << variable_prefix << name << ' ';
510    break;
511  default:
512    internal_error();
513  }
514}
515
516void
517portray(const char* const array[]) {
518  for (unsigned i = 0; array[i] != 0; ++i)
519    std::cout << array[i] << std::endl;
520}
521
522void
523portray(const char* string) {
524  std::cout << string;
525}
526
527void
528portray(long n) {
529  std::cout << n;
530}
531
532void
533portray(const char* name, const char* const array[]) {
534  portray_name(name);
535  portray(array);
536  std::cout << std::endl;
537}
538
539void
540portray(const char* name, const char* string) {
541  portray_name(name);
542  portray(string);
543  std::cout << std::endl;
544}
545
546void
547portray(const char* name, std::string s) {
548  portray(name, s.c_str());
549}
550
551void
552portray(const char* name, long n) {
553  portray_name(name);
554  portray(n);
555  std::cout << std::endl;
556}
557
558void
559replace(std::string& s,
560        const std::string& pattern, const std::string& replacement) {
561  std::string::size_type pos = 0;
562  while (true) {
563    pos = s.find(pattern, pos);
564    if (pos == std::string::npos)
565      break;
566    s.replace(pos, pattern.size(), replacement);
567    pos += replacement.length();
568  }
569}
570
571void
572replace_prefixes(std::string& s) {
573  static const std::string prefix_reference = "${prefix}";
574  static const std::string exec_prefix_reference = "${exec_prefix}";
575  replace(s, prefix_reference, prefix);
576  replace(s, exec_prefix_reference, exec_prefix);
577}
578
579void
580portray_with_prefixes(const char* name, std::string s) {
581  replace_prefixes(s);
582  portray(name, s);
583}
584
585} // namespace
586
587int
588main(int argc, char* argv[]) try {
589  program_name = argv[0];
590
591  if (strcmp(PPL_VERSION, PPL::version()) != 0)
592    fatal("was compiled with PPL version %s, but linked with version %s",
593          PPL_VERSION, PPL::version());
594
595  // Initialize prefixes.
596  prefix = "@prefix@";
597  exec_prefix = "@exec_prefix@";
598  replace_prefixes(prefix);
599  replace_prefixes(exec_prefix);
600
601  // Process command line options.
602  process_options(argc, argv);
603
604  if (required_prefix)
605    portray("PREFIX", prefix);
606
607  if (required_exec_prefix)
608    portray("EXEC_PREFIX", exec_prefix);
609
610  if (required_configure_options)
611    portray("CONFIGURE_OPTIONS", PPL_CONFIGURE_OPTIONS);
612
613  if (required_version)
614    portray("VERSION", PPL_VERSION);
615
616  if (required_version_major)
617    portray("VERSION_MAJOR", static_cast<long>(PPL_VERSION_MAJOR));
618
619  if (required_version_minor)
620    portray("VERSION_MINOR", static_cast<long>(PPL_VERSION_MINOR));
621
622  if (required_version_revision)
623    portray("VERSION_REVISION", static_cast<long>(PPL_VERSION_REVISION));
624
625  if (required_version_beta)
626    portray("VERSION_BETA", static_cast<long>(PPL_VERSION_BETA));
627
628  if (required_banner)
629    portray("BANNER", PPL::banner());
630
631  if (required_coefficients)
632    portray("COEFFICIENTS", "@coefficient_mnemonic@");
633
634  if (required_includedir)
635    portray_with_prefixes("INCLUDEDIR", "@includedir@");
636
637  if (required_bindir)
638    portray_with_prefixes("BINDIR", "@bindir@");
639
640  if (required_libdir)
641    portray_with_prefixes("LIBDIR", "@libdir@");
642
643  if (required_cppflags) {
644    if (required_application) {
645      std::string cppflags = "@CPPFLAGS@";
646      std::string s = "@includedir@";
647      replace_prefixes(s);
648      // `/usr/include' is the standard include directory:
649      // thus it needs not be specified.
650      if (s == "/usr/include")
651        s = cppflags;
652      else {
653        s = "-I" + s;
654        // Avoid duplicating the -I options.
655        if (cppflags.find(s) != std::string::npos)
656          s = "";
657        if (s.length() > 0 && strlen("@CPPFLAGS@") > 0)
658          s += ' ';
659        s += "@CPPFLAGS@";
660      }
661      if (s.length() > 0 && strlen("@extra_includes@") > 0)
662          s += ' ';
663      s += "@extra_includes@";
664      portray("CPPFLAGS", s);
665    }
666    else
667      portray("CPPFLAGS", "@CPPFLAGS@");
668  }
669
670  if (required_cflags)
671    portray("CFLAGS", "@CFLAGS@");
672
673  if (required_cxxflags)
674    portray("CXXFLAGS", "@CXXFLAGS@");
675
676  if (required_ldflags) {
677    std::string s = "@libdir@";
678    replace_prefixes(s);
679    const std::string ldflags = "@LDFLAGS@";
680    // `/usr/lib' is the standard library directory:
681    // thus it needs not be specified.
682    if (s == "/usr/lib")
683      s = ldflags;
684    else {
685      s = "-L" + s;
686      // Avoid duplicating the -L options.
687      if (ldflags.find(s) != std::string::npos)
688        s = "";
689      if (s.length() > 0 && ldflags.length() > 0)
690        s += ' ';
691      s += ldflags;
692    }
693    if (required_library) {
694      if (s.length() > 0 && strlen("@extra_libraries@") > 0)
695        s += ' ';
696      s += "@extra_libraries@";
697    }
698    else {
699      assert(required_application);
700      if (s.length() > 0)
701        s += ' ';
702      s += "-lppl";
703      if (required_interface == C)
704        s += " -lppl_c";
705      s += " -lgmpxx -lgmp";
706    }
707    portray("LDFLAGS", s);
708  }
709
710  if (required_license)
711    portray("LICENSE", PPL_LICENSE);
712
713  if (required_copying)
714    portray("COPYING", COPYING_array);
715
716  if (required_bugs)
717    portray("BUGS", BUGS_array);
718
719  if (required_credits)
720    portray("CREDITS", CREDITS_array);
721
722  return 0;
723}
724catch (const std::bad_alloc&) {
725  fatal("out of memory");
726  exit(1);
727}
728catch (const std::overflow_error& e) {
729  fatal("arithmetic overflow (%s)", e.what());
730  exit(1);
731}
732catch (...) {
733  internal_error();
734}
735