/* cmdline.c
  Copyright (C) 2005,2006,2007 Eugene K. Ressler, Jr.

This file is part of Sketch, a small, simple system for making
3d drawings with LaTeX and the PSTricks or TikZ package.

Sketch is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.

Sketch is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Sketch; see the file COPYING.txt.  If not, see
http://www.gnu.org/copyleft */

#include <stdlib.h>
#include "cmdline.h"
#include "emit.h"
#include "memutil.h"
#include "parse.h"
#include "symbol.h"
#include "version.h"

void
usage (int exit_code)
{
 fprintf (stderr, "\n"
          "sketch [options] file1 [-D tag][-U tag] file2...\n"
          "-h                 Print this message to standard error\n"
          "-v                 Print version info to standard output\n"
          "-V x.y             Tell Sketch your PSTricks version is x.y\n"
          "-d                 Debug parser (for developers)\n"
          "-b                 Use BSP rather than Painters algorithm for HSR\n"
          "-T[u|e][p[P|T]]    Produce a complete LaTeX document\n"
          "  u                U.S. paper size (8.5 x 11 inches) (default)\n"
          "  e                European A4 paper size (297 x 210 mm)\n"
          "  p                Print document template to stdout\n"
          "    P              Print PSTricks version of doc template (default)\n"
          "    T              Print TikZ version of doc template\n"
          "      L            Print LaTeX version of template (default)\n"
          "      C            Print ConTeXt version of template\n"
          "-t templatefile    Load user document template\n"
          "                     (any text file with escape %%SKETCH_OUTPUT%%)\n"
          "-o outfile         Put output in outfile (default is stdout)\n"
          "-D tag             Define given tag\n"
          "-U tag             Undefine given tag\n");
 exit (exit_code);
}

static int
is_doc_template_file_name (char *s)
{
 return s[0] != '-' || s[1] == '\0';
}

// process argv[1..argc-1] to fill in env and prepare it for wrapping
void
process_global_options (CMD_LINE_OPT_ENV * env, int argc, char **argv,
                       SYMBOL_TABLE * sym_tab)
{
 int i, j;
 unsigned lang, set;

 // i = 0
 // argc = 0;
 // argv = NULL;
 // sym_tab = NULL;
 // bsp_only_p = false
 // doc_template_file_name = NULL
 // out_file_name = NULL
 // skip_input_p = false
 // n_files = 0
 SET_STRUCT_ZERO (env);
 env->sym_tab = sym_tab;
 parse_pst_version(env->pst_version, STRINGIFY(ASSUMED_PST_VERSION), no_line);

 // we'll copy args that need to be processed in order with filenames here.
 // the convention will be that args with paramaters like -Dfoo will be
 // separated into -D and foo, so we could end up doubling the number of args.
 env->argv = safe_malloc (2 * (argc - 1) * sizeof (char *));

 for (i = 1; i < argc; i++)
   {
     if (argv[i][0] == '-')
       {
         switch (argv[i][1])
           {
           case 'b':
             env->bsp_only_p = 1;
             break;
           case 'd':
             yydebug = 1;
             break;
           case 'h':
             usage (0);
             break;
           case 'D':
           case 'U':
             env->argv[env->argc++] = argv[i];
             if (argv[i][2])
               env->argv[env->argc++] = &argv[i][2];
             else if (i + 1 < argc)
               env->argv[env->argc++] = argv[++i];
             else
               err (no_line, "missing tag after %s", argv[i]);
             break;
           case 'o':
             if (env->out_file_name)
               err (no_line, "only one use of -o is allowed");
             if (argv[i][2])
               env->out_file_name = &argv[i][2];
             else
               {
                 if (i + 1 < argc)
                   env->out_file_name = &argv[++i][0];
                 else
                   err (no_line, "missing file name after -o");
               }
             break;
           case 't':
             if (argv[i][2])
               env->doc_template_file_name = &argv[i][2];
             else if (i + 1 < argc
                      && is_doc_template_file_name (argv[i + 1]))
               env->doc_template_file_name = argv[++i];
             else
               err (no_line, "missing document template file name after -t");
             break;
           case 'T':
             j = 2;
             if (argv[i][j] == 'e')
               {
                 env->doc_template_file_name =
                   standard_euro_doc_template_file_name_flag;
                 ++j;
               }
             else if (argv[i][j] == 'u')
               {
                 env->doc_template_file_name =
                   standard_us_doc_template_file_name_flag;
                 ++j;
               }
             else
               {
                 env->doc_template_file_name =
                   standard_us_doc_template_file_name_flag;
               }
             if (argv[i][j] == 'p')
               {
                 lang = set = 0;
                 for (++j; argv[i][j]; ++j)
                   {
                     switch (argv[i][j])
                       {
                       case 'P':
                         if (set & GEOL_GRAPHICS_BIT)
                           err (no_line, "-tP with two graphics package specs");
                         lang |= GEOL_PSTRICKS;
                         set  |= GEOL_GRAPHICS_BIT;
                         break;
                       case 'T':
                         if (set & GEOL_GRAPHICS_BIT)
                           err (no_line, "-tP with two graphics package specs");
                         lang |= GEOL_TIKZ;
                         set  |= GEOL_GRAPHICS_BIT;
                         break;
                       case 'L':
                         if (set & GEOL_TEX_MACROS_BIT)
                           err (no_line, "-tP with two macro package specs");
                         lang |= GEOL_LATEX;
                         set  |= GEOL_TEX_MACROS_BIT;
                         break;
                       case 'C':
                         if (set & GEOL_TEX_MACROS_BIT)
                           err (no_line, "-tP with two macro package specs");
                         lang |= GEOL_CONTEXT;
                         set  |= GEOL_TEX_MACROS_BIT;
                         break;
                       default:
                         err (no_line, "unrecognized language spec after -Tp, '%c'",
                              argv[i][j]);
                       }
                   }
                 printf ("%% %s document template:\n%s",
                         output_language_str[lang],
                         doc_template_from_file (env->doc_template_file_name, lang));
                 env->skip_input_p = 1;
               }
             else if (argv[i][j] != '\0')
               {
                 err (no_line, "unrecognized modifier of option '-T%c'",
                      argv[i][j]);
               }
             break;
           case 'V':
             if (argv[i][2] != '\0')
               {
                 parse_pst_version(env->pst_version, &argv[i][2], no_line);
               }
             else
               {
                 if (i + 1 < argc)
                   parse_pst_version(env->pst_version, &argv[++i][0], no_line);
                 else
                   err (no_line, "missing PSTricks version");
               }
             break;
           case 'v':
             fprintf (stdout, "%% sketch version %s\n", VER_STRING);
             fprintf (stdout, "%% assumes PSTricks version %s (change with -V)\n",
                      env->pst_version->str);
             env->skip_input_p = 1;
             break;
           default:
             err (no_line, "unrecognized option '%s'", argv[i]);
             break;
           }
       }
     else
       {
         // no leading -
         ++env->n_files;
         env->argv[env->argc++] = argv[i];
       }
   }
 env->argv = safe_realloc (env->argv, env->argc * sizeof (char *));
}

// advance the environment initialized above until the next filename
// has been found, processing non-global arguments
char *
advance_to_next_file_name (CMD_LINE_OPT_ENV * env)
{
 for (; env->i < env->argc; env->i++)
   {
     if (env->argv[env->i][0] == '-')
       {
         switch (env->argv[env->i][1])
           {
           case 'D':
             ++env->i;
             (void) new_symbol (env->sym_tab, env->argv[env->i], NULL,
                                new_tag_def (), no_line);
             break;
           case 'U':
             // this will produce an error message if tag doesn't exist
             ++env->i;
             if (tag_exists_p (env->sym_tab, env->argv[env->i]))
               remove_symbol (env->sym_tab, env->argv[env->i], no_line);
             break;
           default:
             die (no_line, "advance_to_next_file_name: unexpected option %c",
                  env->argv[env->i][1]);
             break;
           }
       }
     else
       {
         return env->argv[env->i++];
       }
   }
 return NULL;
}