/'* \file fb-doc_options.bas
\brief The source code for the \ref Options class

This file contains the source code for the Options class. It's used 
to scan the command line options and control the execution of fb-doc.

'/

#INCLUDE ONCE "fb-doc_options.bi"

/'* \brief Read options and parameters from the command line

The constructor scans all command line arguments and checks for 
options and their parameters (, see \ref sectionoptions for 
details). Options may be specified in short form (starting with a 
single minus character) or in human readable long form (starting 
with two minus characters). Some options max have an additinal 
parameter.

Each command line argument that is neither an option nor a parameter 
gets interpreted as a file name or pattern. fb-doc collects them in 
a queue and operates on this queue afterwards. The queue may have 
mixed entries (names and patterns). It's recommended to specify 
queue entries in single or double quotes.

'/
CONSTRUCTOR Options()
      Types = FB_STYLE
  Function_ = @cppCreateFunction
  Variable_ = @cppCreateTypNam

  VAR i = 1
  WHILE LEN(COMMAND(i)) '                               evaluate options
    SELECT CASE COMMAND(i)
    CASE       "--help", "-h" : RunMode = HELP_MESSAGE
    CASE    "--version", "-v" : RunMode = VERSION_MESSAGE
    CASE    "--asterix", "-a" : Asterix = GTK_DOC
    CASE     "--cstyle", "-c"
          Types = C_STYLE
      Function_ = @cCreateFunction
      Variable_ = @cCreateTypNam
    CASE    "--emitter", "-e" : chooseEmitter(i)
    CASE "--fileoutput", "-f"
      RunMode = FILE_OUT
      EmitIF = Emitters(C_SOURCE)
    CASE      "--geany", "-g"
      RunMode = GEANYFILTER
      EmitIF = Emitters(GTK_DOC_TEMPLATES)
      chooseEmitter(i)
    CASE       "--list", "-l"
      RunMode = SCAN_LIST
      EmitIF = Emitters(DOXYGEN_CALLEES)
      IF LCASE(COMMAND(i + 1)) = "ext" THEN AllCallees = -1 : i += 1
    CASE       "--path", "-p"
      SELECT CASE AS CONST ASC(COMMAND(i + 1))
      CASE ASC("-")
      CASE ASC(""""), ASC("'") : i += 1
        OutPath = MID(COMMAND(i), 2, LEN(COMMAND(i)) - 2)
      CASE ELSE : i += 1 : OutPath = COMMAND(i)
      END SELECT
    CASE   "--recursiv", "-r" : InRecursiv = 1
    CASE       "--tree", "-t" : InTree = 1 : AllCallees = -1
    CASE ELSE
      SELECT CASE AS CONST ASC(COMMAND(i))
      CASE ASC("-") : ERROUT("Unknown parameter: " & COMMAND(i))
      CASE ASC(""""), ASC("'")
                  InFile &= MID(COMMAND(i), 2, LEN(COMMAND(i)) - 2) & ";"
      CASE ELSE : InFile &= COMMAND(i) & ";"
      END SELECT
    END SELECT : i += 1
  WEND

  IF 0 = LEN(InFile) THEN _
     IF RunMode = DOXYFILTER THEN RunMode = HELP_MESSAGE _
                             ELSE InFile = "*.bas;*.bi;"

  IF RunMode = FILE_OUT THEN _
    IF 0 = LEN(OutPath) THEN _
      OutPath = ".." & SLASH & "doc" & SLASH & "c_src" & SLASH

  Pars = NEW Parser(EmitIF)
END CONSTRUCTOR


/'* \brief The destructor

Delete the memory used for an external emitter (if any) and for the 
Parser.

'/
DESTRUCTOR Options()
  IF DllEmitter THEN DYLIBFREE(OPT->DllEmitter)
  DELETE Pars
END DESTRUCTOR


/'* \brief Check next parameter for emitter name
\param I the index of the current parameter

This function checks the following command line parameter (I + 1) 
against the names of the internal emitters. The check is not 
case-sensitve and is done for a fragment as well, so it's enough to 
specify some of the start characters of the emitter name (ie \em dox 
instead of \em DoxygenTemplates).

In case of no match it tries to load an external emitter.

In case of a match of an internal or external emitter the index gets 
increased.

'/
SUB Options.chooseEmitter(BYREF I AS INTEGER)
  VAR p = I + 1
  IF 1 > LEN(COMMAND(p)) ORELSE LEFT(COMMAND(p), 1) = "-" THEN EXIT SUB
  VAR t = UCASE(COMMAND(p)), l = LEN(t)
  FOR e AS INTEGER = UBOUND(Emitters) TO 0 STEP -1
    IF t <> UCASE(LEFT(Emitters(e)->Nam, l)) THEN CONTINUE FOR
    EmitIF = Emitters(e) : I = p : EXIT SUB
  NEXT

#IFDEF __FB_DOS__
  ERROUT("No dll support on this platform!")
#ELSE
  VAR f = COMMAND(p)
  SELECT CASE AS CONST ASC(f)
  CASE ASC(""""), ASC("'") : f = MID(f, 2, LEN(f) - 2)
  END SELECT

  DllEmitter = DYLIBLOAD(f) : IF 0 = DllEmitter THEN EXIT SUB
  DIM ini AS FUNCTION CDECL() AS EmitterIF PTR
  ini = DYLIBSYMBOL(DllEmitter, "EMITTERINIT") : IF 0 = ini THEN EXIT SUB
  EmitIF = ini() : I = p
#ENDIF
END SUB


/'* \brief Create folder (if not exists)
\param P the folder name
\returns -1 on error, else 0

This SUB gets called when a recursiv scan walks through subfolders 
in a source tree. It creates matching subfolders in the target 
directory for the output files.

'/
FUNCTION Options.checkDir(BYREF P AS STRING) AS INTEGER
  VAR a = 1, e = a, l = LEN(P)
#IFDEF __FB_UNIX__
  IF LEFT(P, 1) = "/" THEN a = 2 : CHDIR("/")
#ELSE
  IF MID(P, 2, 1) = ":" THEN a = 4 : CHDIR(LEFT(P, 3))
#ENDIF

  DO
    e = INSTR(a, P, SLASH) : IF e = 0 THEN e = l + 1
    VAR n = MID(P, a, e - a)
    IF CHDIR(n) THEN MKDIR(n) : IF CHDIR(n) THEN RETURN -1
    a = e + 1
  LOOP UNTIL a > l : RETURN 0
END FUNCTION


/'* \brief Operate on all files matching a pattern

In case of file input this SUB scans a directory for matching file 
names (and its subfolders if option \em --recursiv is given). It 
opens the output file (when option \em --fileoutput is given) and 
calls the Parser to operate on the file.

'/
SUB Options.Pattern()
  IF InRecursiv > 0 THEN
    VAR n = DIR("*", fbDirectory), t = ""
    WHILE LEN(n)
      t &= n & ";"
      n = DIR()
    WEND
  
    VAR a = 1, e = a, l = LEN(t)
    WHILE a < l
      e = INSTR(a, t, ";")
      n = MID(t, a, e - a)
      VAR r = LEN(OutPath)
      CHDIR(n)
      OutPath &= n & SLASH
      Pattern()
      OutPath = LEFT(OutPath, r)
      CHDIR ("..")
      a = e + 1
    WEND
  END IF

  VAR c = 0, r = "", n = DIR(InPattern) : IF 0 = LEN(n) THEN EXIT SUB
  IF RunMode = FILE_OUT THEN
    VAR d = CURDIR()
    VAR r = checkDir(OutPath)
    CHDIR(d) : IF r THEN EXIT SUB
  END IF
  DO
    SELECT CASE AS CONST RunMode
    CASE FILE_OUT
      MSG_LINE(n)
      VAR f = OutPath & LEFT(n, INSTRREV(n, "."))
      IF LCASE(RIGHT(n, 3)) = ".bi" THEN f &= "h" ELSE f &= "c"
      Pars->Ocha = FREEFILE
      IF OPEN(f FOR OUTPUT AS #Pars->Ocha) THEN
        ERROUT("Couldn't write " & f)
      ELSE
        Pars->File_(n)
        CLOSE #Pars->Ocha
        ERROUT(" --> " & f)
      END IF
    CASE SCAN_LIST
      MSG_LINE(n)
      Pars->File_(n)
      ERROUT(" --> scanned")
    CASE ELSE 
      Pars->File_(n)
    END SELECT
    c += 1 : n = DIR()
  LOOP UNTIL 1 > LEN(n)
END SUB
