# ProgressTransformDriver.java

    /*
    ** Module   : ProgressTransformDriver.java
    ** Abstract : runs the Progress 4GL to Progress 4GL transformation for a file or set of files
    **
    ** Copyright (c) 2018-2021, Golden Code Development Corporation.
    **
    ** -#- -I- --Date-- ---------------------------------------Description---------------------------------------
    ** 001 GES 20181023 First version.
    ** 002 ECF 20190221 Added blacklist (filespec + ignore list) mode.
    ** 003 CA  20200412 Added incremental conversion support.
    **     OM  20210923 Added -P<name> command line option for specifying the configuration profile.
    */

    /*
    ** This program is free software: you can redistribute it and/or modify
    ** it under the terms of the GNU Affero General Public License as
    ** published by the Free Software Foundation, either version 3 of the
    ** License, or (at your option) any later version.
    **
    ** This program 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 Affero General Public License for more details.
    **
    ** You may find a copy of the GNU Affero GPL version 3 at the following
    ** location: https://www.gnu.org/licenses/agpl-3.0.en.html
    **
    ** Additional terms under GNU Affero GPL version 3 section 7:
    **
    **   Under Section 7 of the GNU Affero GPL version 3, the following additional
    **   terms apply to the works covered under the License.  These additional terms
    **   are non-permissive additional terms allowed under Section 7 of the GNU
    **   Affero GPL version 3 and may not be removed by you.
    **
    **   0. Attribution Requirement.
    **
    **     You must preserve all legal notices or author attributions in the covered
    **     work or Appropriate Legal Notices displayed by works containing the covered
    **     work.  You may not remove from the covered work any author or developer
    **     credit already included within the covered work.
    **
    **   1. No License To Use Trademarks.
    **
    **     This license does not grant any license or rights to use the trademarks
    **     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
    **     of Golden Code Development Corporation. You are not authorized to use the
    **     name Golden Code, FWD, or the names of any author or contributor, for
    **     publicity purposes without written authorization.
    **
    **   2. No Misrepresentation of Affiliation.
    **
    **     You may not represent yourself as Golden Code Development Corporation or FWD.
    **
    **     You may not represent yourself for publicity purposes as associated with
    **     Golden Code Development Corporation, FWD, or any author or contributor to
    **     the covered work, without written authorization.
    **
    **   3. No Misrepresentation of Source or Origin.
    **
    **     You may not represent the covered work as solely your work.  All modified
    **     versions of the covered work must be marked in a reasonable way to make it
    **     clear that the modified work is not originating from Golden Code Development
    **     Corporation or FWD.  All modified versions must contain the notices of
    **     attribution required in this license.
    */

    package com.goldencode.p2j.convert;

    import java.io.*;
    import java.util.*;
    import com.goldencode.ast.*;
    import com.goldencode.p2j.cfg.*;
    import com.goldencode.p2j.schema.*;

    /**
     * Provides a harness to drive the Progress 4GL to Progress 4GL transformation for a file or set
     * of files.
     * <p>
     * This program provides a command line interface.  See {@link #main} for the syntax.
     */
    public class ProgressTransformDriver
    extends TransformDriver
    {
       /** Associates mode names with detailed mode definitions. */
       private static final Map<String, RunMode> modes = new HashMap<>();

       /** Job title, which needs to be implemented in each subclass. */
       private static final String TITLE = "Progress 4GL Transformation Driver";

       /** Help text, which needs to be implemented in each subclass. */
       private static final String[] helpText = new String[]
       {
          "--------------------" + TITLE + "--------------------",
          "",
          "Syntax:",
          "   java -DP2J_HOME=<home> ProgressTransformDriver [options]* <mode> [user_defined_rule_set] <file-specs>",
          "",
          "Where",
          "   Options (F, S, and X are mutually exclusive. If none is specified <file-specs>",
          "              is a list of files added to command line):",
          "      Dn    = set DEBUG level 'n'. Must be a numeric digit between " + MSG_NONE + " (none)",
          "              and " + MSG_TRACE + " (trace) inclusive",
          "      F     = <file-specs> is a <filename> containing a custom FILE-LIST",
          "      S     = <file-specs> is composed of a root <directory> and \"<file-filter>\"",
          "              to select SPECIFIC files",
          "      X     = <file-specs> is similar to S but has an additional custom EXCLUDE",
          "              list file \"<filename>\" to be ignored",
          "      N     = NO recursion in <file-filter> (S/X options)",
          "      A     = ABORT scan part of front end on an error",
          "      Tn    = specify number of THREADS 'n' to use for front end file scan ('n'",
          "              must be >= 0; defaults to 1; set to 0 to use 1 thread per",
          "              available CPU)",
          "      L     = LIST files to be processed only; do not perform any further task",
          "      I     = INCREMENTAL conversion; only changed/new programs will be parsed",
          "              and converted",
          "      Pname = the <name> of the configuration PROFILE follows the option",
          "",
          "   Mode (one or more of the following values, use '+' to delimit if there are two",
          "           or more values; don't insert spaces!)",
          "      -------------------------------- Front End --------------------------------",
          "      F0 = preprocessor (in honor cache mode), lexer, parser, AST persistence and",
          "           post-parse fixups",
          "      F1 = F0 + forced preprocessor execution",
          "      F2 = F1 + schema loader/fixups",
          "      F3 = F2 + call graph generation",
          "",
          "      ----------------------------- Transformation ------------------------------",
          "      TR = execute a user-defined transformation ruleset (this requires the",
          "           user-defined rule-set to be added)",
          "",
          "      ------------------------------ Anti-Parsing -------------------------------",
          "      AP = output ASTs to Progress 4GL source code",
          "",
          "   user_defined_rule_set (only possible in TR mode)",
          "",
          "   filelist   = arbitrary list of absolute and/or relative file names to scan",
          "                   (default approach)",
          "   directory  = a relative or absolute path (only used when using <file-filter>,",
          "                   S/X options)",
          "   file-filter= file filter specification of the filenames in the given directory",
          "                   to scan, should be enclosed in double quotes if any of the",
          "                   wildcard characters '*' or '?' are used (only used with S/X",
          "                   modes)",
          "   filename   = when used with the -F option, this is a single absolute or",
          "                   relative name of a text file that contains a custom list of",
          "                   absolute and/or relative file names of files to scan (i.e. the",
          "                   file list will be read from a file instead of being hard coded",
          "                   on the command line); there must be one file name per line in",
          "                   the file;",
          "                when used with the -X option, this is a single absolute or",
          "                   relative name of a text file that contains a custom list of",
          "                   specifications of file names to ignore; all other files",
          "                   specified by the primary <file-filter> are scanned.",
       };

       static
       {
          modes.put("F0", new RunMode(true , false, false, false, false, false));
          modes.put("F1", new RunMode(true , true , false, false, false, false));
          modes.put("F2", new RunMode(true , true , true , false, false, false));
          modes.put("F3", new RunMode(true , true , true , true , false, false));
          modes.put("TR", new RunMode(false, false, false, false, true , false));
          modes.put("AP", new RunMode(false, false, false, false, false, true));
       }

       /**
        * Creates an instance with a specific configuration.
        *
        * @param    job
        *           The details of this driver run.
        */
       ProgressTransformDriver(JobDefinition job)
       {
          super(job);
       }

       /**
        * Drive the transformation process using the file list of Progress ASTs that is already
        * defined in this instance.  The user must have provided a TRPL rule-set to execute,
        * otherwise this phase will be a NOP.
        */
       protected void middle()
       throws ConfigurationException,
              AstException,
              SchemaException,
              IOException
       {
          if (job.transform == null || job.transform.isEmpty())
          {
             return;
          }

          // ensure that downstream processing has the proper list of files
          convertSourceNamesToAstNames();

          processTrees("User-Defined Transformation",
                       job.transform,
                       null,
                       false,
                       asts,
                       debug);
       }

       /**
        * Drive the back end of the transformation process using the file list of Progress ASTs
        * that is already defined in this instance.  Each AST will be anti-parsed back to
        * Progress 4GL source code.
        */
       protected void back()
       throws ConfigurationException,
              AstException,
              SchemaException,
              IOException
       {
          // ensure that downstream processing has the proper list of files
          convertSourceNamesToAstNames();

          processTrees("Anti-Parsing",
                       "progress/anti_parser",
                       null,
                       false,
                       asts,
                       debug);
       }

       /**
        * Provides a command line interface for an end user to drive the scanning harness.
        * <p>
        * The program will return a non-zero code if there is a fatal error running the conversion.
        * <p>
        * Syntax:
        * <pre>{@code java -DP2J_HOME=<home> ProgressTransformDriver [-options]* <mode> [user_defined_rule_set] <file-specs>}</pre>
        * Where:
        * <ul>
        *   <li>Options (F, S, and X are mutually exclusive. If none is specified <file-specs> is a list of files
        *       added to command line):
        *       <ul>
        *          <li>Dn = set debug level 'n' (must be a numeric digit between {@code MSG_NONE} (0) and
        *              {@code MSG_TRACE} (3) inclusive
        *          <li>I = incremental conversion; only changed/new programs will be parsed and converted.
        *          <li>F = {@code <file-specs>} is a {@code <filename>} containing a custom FILE-LIST, instead of
        *              using the explicit command line file list
        *          <li>S = {@code <file-specs>} is composed of a root {@code <directory>} and a {@code
        *              "<file-filter>"}, to select SPECIFIC files instead of an explicit command line file list
        *          <li>X = {@code <file-specs>} is similar to S but has an additional custom EXCLUDE list file
        *              {@code "<filename>"} to be ignored
        *          <li>N = NO recursion in {@code <file-filter>} (S/X options)",
        *          <li>A = ABORT scan part of front end on an error
        *          <li>Tn = specify number of THREADS 'n' to use for front end file scan ('n' must be {@code >=}
        *              0; defaults to 1; set to 0 to use 1 thread per available CPU)
        *          <li>L = LIST files to be processed only; do not perform any further task
        *          <li>Pname = the {@code <name>} of the configuration PROFILE follows the option
        *       </ul>
        *   <li>{@code mode} (one or more of the following values, use '+' to delimit if there are two or more
        *       values; don't insert spaces!)
        *       <ul>
        *          <li>Front End
        *              <ul>
        *                 <li>F0 = preprocessor (in honor cache mode), lexer, parser, AST persistence and
        *                          post-parse fixups
        *                 <li>F1 = F0 + forced preprocessor execution
        *                 <li>F2 = F1 + schema loader/fixups
        *                 <li>F3 = F2 + call graph generation
        *              </ul>
        *          <li>Transformation
        *              <ul>
        *                 <li>TR = execute a user-defined transformation ruleset (this requires an extra parameter
        *                          after the mode and before the source file specifications)
        *              </ul>
        *          <li>Anti-Parsing
        *              <ul>
        *                 <li>AP = output ASTs to Progress 4GL source code
        *              </ul>
        *       </ul>
        *   <li>The optional {@code user_defined_rule_set} specifies the user-defined rule-set filename to execute
        *        (only some modes support this, see sub-class documentation for details)
        *   <li>explicit command line list (default approach if none of S, P, or F are present)
        *       <ul>
        *          <li>{@code <filelist>} is arbitrary list of absolute and/or relative file names to scan, this
        *              list is hard coded in the command line itself
        *          <li>any number of files may be listed on the command line, subject to command shell limits
        *       </ul>
        *   <li>custom file list (FILE approach)
        *       <ul>
        *          <li>{@code <filename>} is a single absolute or relative filename of a text file that contains a
        *              custom list of absolute and/or relative file names of files to scan
        *          <li>in other words, the file list will be read from a file instead of being hard coded on the
        *              command line
        *          <li>there must be one filename per line in the file
        *          <li>there is no limit of the number of files in the list
        *       </ul>
        *   <li>file-spec mode (expressly SPECIFIED files approach)
        *       <ul>
        *          <li>{@code <directory>} is the root directory to search for files
        *          <li>{@code "filespec"} is the file specification that will be used to create a list of files to
        *              process, should be enclosed in double quotes if any of the wildcard characters '*' or '?'
        *              are used
        *       </ul>
        *   <li>custom ignore list (file-spec mode with additional EXCLUDE list)
        *       <ul>
        *          <li>{@code <directory>} is the root directory to search for files
        *          <li>{@code "filespec"}" is the file specification that will be used to create a list of files
        *              to process, should be enclosed in double quotes if any of the wildcard characters '*' or
        *              '?' are used
        *          <li>{@code <filename>} is a single absolute or relative filename of a text file that contains a
        *              custom list of specifications of file names to ignore
        *          <li>asterisk (*) and question mark (?) wildcards are permitted to represent zero or more and
        *              exactly one wildcard characters, respectively
        *          <li>files specified by the primary {@code filespec} which are not matched by the ignore list
        *              are scanned as they would be in {@code filespec} mode.
        *       </ul>
        * </ul>
        *
        * @param   args
        *          List of command line arguments.
        */
       public static void main(String[] args)
       {
          JobDefinition job = processCommandLine(args, modes, helpText);

          if (job != null)
          {
             ProgressTransformDriver driver = new ProgressTransformDriver(job);
             driver.executeJob(TITLE);
          }
       }
    }