Current Version: 1.0.10
Project Name: csspp
csspp.cpp
Go to the documentation of this file.
1 // CSS Preprocessor
2 // Copyright (C) 2015-2016 Made to Order Software Corp.
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 
228 #include "csspp/assembler.h"
229 #include "csspp/compiler.h"
230 #include "csspp/exceptions.h"
231 #include "csspp/parser.h"
232 
233 #include <advgetopt/advgetopt.h>
234 
235 #include <cstdlib>
236 #include <fstream>
237 #include <iostream>
238 
239 #include <unistd.h>
240 
241 namespace
242 {
243 
244 std::vector<std::string> const g_configuration_files; // Empty
245 
246 void free_char(char * ptr)
247 {
248  free(ptr);
249 }
250 
251 advgetopt::getopt::option const g_options[] =
252 {
253  {
254  '\0',
255  advgetopt::getopt::GETOPT_FLAG_SHOW_USAGE_ON_ERROR,
256  NULL,
257  NULL,
258  "Usage: %p [-<opt>] [file.css ...] [-o out.css]",
259  advgetopt::getopt::help_argument
260  },
261  {
262  '\0',
263  advgetopt::getopt::GETOPT_FLAG_SHOW_USAGE_ON_ERROR,
264  NULL,
265  NULL,
266  "where -<opt> is one or more of:",
267  advgetopt::getopt::help_argument
268  },
269  {
270  'a',
271  0,
272  "args",
273  nullptr,
274  "define values in the $_csspp_args variable map",
275  advgetopt::getopt::required_multiple_argument
276  },
277  {
278  'd',
279  0,
280  "debug",
281  nullptr,
282  "show all messages, including @debug messages",
283  advgetopt::getopt::no_argument
284  },
285  {
286  'h',
287  0,
288  "help",
289  nullptr,
290  "display this help screen",
291  advgetopt::getopt::no_argument
292  },
293  {
294  'I',
295  0,
296  nullptr,
297  nullptr,
298  "specify a path to various user defined CSS files; \"-\" to clear the list",
299  advgetopt::getopt::required_multiple_argument
300  },
301  {
302  '\0',
303  0,
304  "no-logo",
305  nullptr,
306  "prevent the \"logo\" from appearing in the output file",
307  advgetopt::getopt::no_argument
308  },
309  {
310  'o',
311  advgetopt::getopt::GETOPT_FLAG_SHOW_USAGE_ON_ERROR,
312  "output",
313  nullptr,
314  "save the results in the specified file",
315  advgetopt::getopt::required_argument
316  },
317  {
318  'p',
319  0,
320  "precision",
321  nullptr,
322  "define the number of digits to use after the decimal point, defaults to 3; note that for percent values, the precision is always 2.",
323  advgetopt::getopt::no_argument
324  },
325  {
326  'q',
327  0,
328  "quiet",
329  nullptr,
330  "suppress @info and @warning messages",
331  advgetopt::getopt::no_argument
332  },
333  {
334  's',
335  0,
336  "style",
337  nullptr,
338  "output style: compressed, tidy, compact, expanded",
339  advgetopt::getopt::required_argument
340  },
341  {
342  '\0',
343  advgetopt::getopt::GETOPT_FLAG_SHOW_USAGE_ON_ERROR,
344  "version",
345  nullptr,
346  "show the version of the snapdb executable",
347  advgetopt::getopt::no_argument
348  },
349  {
350  '\0',
351  0,
352  "Werror",
353  nullptr,
354  "make warnings count as errors",
355  advgetopt::getopt::no_argument
356  },
357  {
358  '\0',
359  advgetopt::getopt::GETOPT_FLAG_SHOW_USAGE_ON_ERROR,
360  NULL,
361  NULL,
362  "[file.css ...]; use stdin if no filename specified",
363  advgetopt::getopt::default_multiple_argument
364  },
365  {
366  '\0',
367  0,
368  NULL,
369  NULL,
370  NULL,
371  advgetopt::getopt::end_of_options
372  }
373 };
374 
375 class pp
376 {
377 public:
378  pp(int argc, char * argv[]);
379 
380  int compile();
381 
382 private:
383  std::shared_ptr<advgetopt::getopt> f_opt;
384  int f_precision = 3;
385 };
386 
387 pp::pp(int argc, char * argv[])
388  : f_opt(new advgetopt::getopt(argc, argv, g_options, g_configuration_files, NULL))
389 {
390  if(f_opt->is_defined("version"))
391  {
392  std::cerr << CSSPP_VERSION << std::endl;
393  exit(1);
394  }
395 
396  if(f_opt->is_defined("help"))
397  {
398  f_opt->usage(advgetopt::getopt::no_error, "csspp");
399  exit(0);
400  }
401 
402  if(f_opt->is_defined("quiet"))
403  {
405  }
406 
407  if(f_opt->is_defined("debug"))
408  {
410  }
411 
412  if(f_opt->is_defined("Werror"))
413  {
415  }
416 
417  if(f_opt->is_defined("precision"))
418  {
419  f_precision = f_opt->get_long("precision");
420  }
421 }
422 
424 {
427  std::unique_ptr<std::stringstream> ss;
428 
429  csspp::safe_precision_t safe_precision(f_precision);
430 
431  if(f_opt->is_defined("--"))
432  {
433  // one or more filename specified
434  int const arg_count(f_opt->size("--"));
435  if(arg_count == 1
436  && f_opt->get_string("--") == "-")
437  {
438  // user asked for stdin
439  pos.reset(new csspp::position("-"));
440  l.reset(new csspp::lexer(std::cin, *pos));
441  }
442  else
443  {
444  std::unique_ptr<char, void (*)(char *)> cwd(get_current_dir_name(), free_char);
445  ss.reset(new std::stringstream);
446  pos.reset(new csspp::position("csspp.css"));
447  for(int idx(0); idx < arg_count; ++idx)
448  {
449  // full paths so the -I have no effects on those files
450  std::string filename(f_opt->get_string("--", idx));
451  if(filename.empty())
452  {
453  csspp::error::instance() << *pos
454  << "You cannot include a file with an empty name."
456  return 1;
457  }
458  if(filename == "-")
459  {
460  csspp::error::instance() << *pos
461  << "You cannot currently mix files and stdin. You may use @import \"filename\"; in your stdin data though."
463  return 1;
464  }
465  if(filename[0] == '/')
466  {
467  // already absolute
468  *ss << "@import \"" << filename << "\";\n";
469  }
470  else
471  {
472  // make absolute so we do not need to have a "." path
473  *ss << "@import \"" << cwd.get() << "/" << filename << "\";\n";
474  }
475  }
476  l.reset(new csspp::lexer(*ss, *pos));
477  }
478  }
479  else
480  {
481  // default to stdin
482  pos.reset(new csspp::position("-"));
483  l.reset(new csspp::lexer(std::cin, *pos));
484  }
485 
486  // run the lexer and parser
487  csspp::error_happened_t error_tracker;
488  csspp::parser p(l);
490  if(error_tracker.error_happened())
491  {
492  return 1;
493  }
494 
495  csspp::node::pointer_t csspp_args(new csspp::node(csspp::node_type_t::LIST, root->get_position()));
496  csspp::node::pointer_t args_var(new csspp::node(csspp::node_type_t::VARIABLE, root->get_position()));
497  args_var->set_string("_csspp_args");
498  csspp::node::pointer_t wrapper(new csspp::node(csspp::node_type_t::LIST, root->get_position()));
499  csspp::node::pointer_t array(new csspp::node(csspp::node_type_t::ARRAY, root->get_position()));
500  wrapper->add_child(array);
501  csspp_args->add_child(args_var);
502  csspp_args->add_child(wrapper);
503  if(f_opt->is_defined("args"))
504  {
505  int const count(f_opt->size("args"));
506  for(int idx(0); idx < count; ++idx)
507  {
508  csspp::node::pointer_t arg(new csspp::node(csspp::node_type_t::STRING, root->get_position()));
509  arg->set_string(f_opt->get_string("args", idx));
510  array->add_child(arg);
511  }
512  }
513  root->set_variable("_csspp_args", csspp_args);
514 
515  // run the compiler
516  csspp::compiler c;
517  c.set_root(root);
518  c.set_date_time_variables(time(nullptr));
519 
520  // add paths to the compiler (i.e. for the user and system @imports)
521  if(f_opt->is_defined("I"))
522  {
523  int const count(f_opt->size("I"));
524  for(int idx(0); idx < count; ++idx)
525  {
526  std::string const path(f_opt->get_string("I", idx));
527  if(path == "-")
528  {
529  c.clear_paths();
530  }
531  else
532  {
533  c.add_path(path);
534  }
535  }
536  }
537 
538  if(f_opt->is_defined("no-logo"))
539  {
540  c.set_no_logo();
541  }
542 
543  if(f_opt->is_defined(""))
544  {
546  }
547 
548  c.compile(false);
549  if(error_tracker.error_happened())
550  {
551  return 1;
552  }
553 
554 //std::cerr << "Compiler result is: [" << *c.get_root() << "]\n";
556  if(f_opt->is_defined("style"))
557  {
558  std::string const mode(f_opt->get_string("style"));
559  if(mode == "compressed")
560  {
561  output_mode = csspp::output_mode_t::COMPRESSED;
562  }
563  else if(mode == "tidy")
564  {
565  output_mode = csspp::output_mode_t::TIDY;
566  }
567  else if(mode == "compact")
568  {
569  output_mode = csspp::output_mode_t::COMPACT;
570  }
571  else if(mode == "expanded")
572  {
573  output_mode = csspp::output_mode_t::EXPANDED;
574  }
575  else
576  {
577  csspp::error::instance() << root->get_position()
578  << "The output mode \""
579  << mode
580  << "\" is not supported. Try one of: compressed, tidy, compact, expanded instead."
582  return 1;
583  }
584  }
585 
586  std::ostream * out;
587  if(f_opt->is_defined("output")
588  && f_opt->get_string("output") != "-")
589  {
590  out = new std::ofstream(f_opt->get_string("output"));
591  }
592  else
593  {
594  out = &std::cout;
595  }
596  csspp::assembler a(*out);
597  a.output(c.get_root(), output_mode);
598  if(f_opt->is_defined("output")
599  && f_opt->get_string("output") != "-")
600  {
601  delete out;
602  }
603  if(error_tracker.error_happened())
604  {
605  // this should be rare as the assembler generally does not generate
606  // errors (it may throw though.)
607  return 1;
608  }
609 
610  return 0;
611 }
612 
613 } // no name namespace
614 
615 int main(int argc, char *argv[])
616 {
617  try
618  {
619  pp preprocessor(argc, argv);
620  return preprocessor.compile();
621  }
622  catch(csspp::csspp_exception_exit const & e)
623  {
624  // something went wrong in the library
625  return e.exit_code();
626  }
627  catch(csspp::csspp_exception_logic const & e)
628  {
629  std::cerr << "fatal error: a logic exception, which should NEVER occur, occurred: " << e.what() << std::endl;
630  exit(1);
631  }
632  catch(csspp::csspp_exception_overflow const & e)
633  {
634  std::cerr << "fatal error: an overflow exception occurred: " << e.what() << std::endl;
635  exit(1);
636  }
637  catch(csspp::csspp_exception_runtime const & e)
638  {
639  std::cerr << "fatal error: a runtime exception occurred: " << e.what() << std::endl;
640  exit(1);
641  }
642  catch(advgetopt::getopt_exception_undefined const & e)
643  {
644  std::cerr << "fatal error: an undefined exception occurred because of your command line: " << e.what() << std::endl;
645  exit(1);
646  }
647  catch(advgetopt::getopt_exception_invalid const & e)
648  {
649  std::cerr << "fatal error: there is an error on your command line, an exception occurred: " << e.what() << std::endl;
650  exit(1);
651  }
652 }
653 
654 // Local Variables:
655 // mode: cpp
656 // indent-tabs-mode: nil
657 // c-basic-offset: 4
658 // tab-width: 4
659 // End:
660 
661 // vim: ts=4 sw=4 et
void set_no_logo(bool no_logo=true)
Definition: compiler.cpp:499
std::shared_ptr< node > pointer_t
Definition: node.h:122
void set_hide_all(bool show_debug)
Definition: error.cpp:126
void add_path(std::string const &path)
Definition: compiler.cpp:509
advgetopt::getopt::option const g_options[]
Definition: csspp.cpp:251
node::pointer_t stylesheet()
Definition: parser.cpp:70
void compile(bool bare)
Definition: compiler.cpp:514
void set_root(node::pointer_t root)
Definition: compiler.cpp:405
void free_char(char *ptr)
Definition: csspp.cpp:246
output_mode_t
Definition: assembler.h:25
void set_show_debug(bool show_debug)
Definition: error.cpp:131
void output(node::pointer_t n, output_mode_t mode)
Definition: assembler.cpp:327
std::shared_ptr< lexer > pointer_t
Definition: lexer.h:28
void set_empty_on_undefined_variable(bool const empty_on_undefined_variable)
Definition: compiler.cpp:494
std::shared_ptr< position > pointer_t
Definition: position.h:32
node::pointer_t get_root() const
Definition: compiler.cpp:410
void clear_paths()
Definition: compiler.cpp:504
std::vector< std::string > const g_configuration_files
Definition: csspp.cpp:244
#define CSSPP_VERSION
Definition: csspp.h:47
static error & instance()
Definition: error.cpp:78
int main(int argc, char *argv[])
Definition: csspp.cpp:615
void set_date_time_variables(time_t now)
Definition: compiler.cpp:420
std::shared_ptr< advgetopt::getopt > f_opt
Definition: csspp.cpp:383
bool error_happened() const
Definition: error.cpp:285
void set_count_warnings_as_errors(bool warnings_as_errors)
Definition: error.cpp:101

Documentation of CSS Preprocessor.

This document is part of the Snap! Websites Project.

Copyright by Made to Order Software Corp.