fb-doc  0.4.0
FreeBASIC documentation tool
fbdoc_options.bas
Go to the documentation of this file.
1 
12 
13 #INCLUDE ONCE "fbdoc_options.bi"
14 #INCLUDE ONCE "fbdoc_version.bi"
15 #INCLUDE ONCE "fbdoc_emit_syntax.bi"
16 #INCLUDE ONCE "fbdoc_emit_lfn.bi"
17 #INCLUDE ONCE "fbdoc_doxyfile.bi"
18 
19 
20 
36 CONSTRUCTOR Options()
37  Efnr = FREEFILE
38  IF OPEN ERR (AS #Efnr) THEN ?PROJ_NAME & ": " & "couldn't open STDERR" : Efnr = 0 : EXIT CONSTRUCTOR
39 
40  CreateFunction = @cppCreateFunction()
41  CreateVariable = @cppCreateTypNam()
42  Types = FB_STYLE
43 END CONSTRUCTOR
44 
45 
46 
52 DESTRUCTOR Options()
53  IF DllEmitter THEN DYLIBFREE(DllEmitter)
54  IF Pars THEN DELETE Pars
55  CLOSE #Efnr
56 END DESTRUCTOR
57 
58 
59 
71 FUNCTION Options.parseOptpara(BYREF Idx AS INTEGER) AS STRING
72  VAR p = Idx + 1
73  IF LEN(COMMAND(p)) ANDALSO LEFT(COMMAND(p), 1) <> "-" THEN
74  Idx = p
75  SELECT CASE AS CONST ASC(COMMAND(p))
76  CASE ASC(""""), ASC("'") : RETURN MID(COMMAND(p), 2, LEN(COMMAND(p)) - 2)
77  END SELECT : RETURN COMMAND(p)
78  END IF : Errr = ", parameter expected [" & COMMAND(Idx) & "]" : RETURN ""
79 END FUNCTION
80 
81 
82 
100 FUNCTION Options.parseCLI() AS RunModes
101  VAR i = 1, emi = "", par = ""
102  WHILE LEN(COMMAND(i)) ' evaluate options
103  SELECT CASE AS CONST ASC(COMMAND(i))
104  CASE ASC("-")
105  SELECT CASE COMMAND(i)
106  CASE "-f", "--file-mode"
107  IF RunMode <> DEF_MODE THEN Errr &= ", multiple run modes" : RETURN ERROR_MESSAGE
108  RunMode = FILE_MODE
109  EmitTyp = C_SOURCE
110  CASE "-g", "--geany-mode"
111  IF RunMode <> DEF_MODE THEN Errr &= ", multiple run modes" : RETURN ERROR_MESSAGE
112  RunMode = GEANY_MODE
113  EmitTyp = GTK_DOC_TEMPLATES
114  IF LEN(COMMAND(i + 1)) THEN emi = parseOptpara(i)
115  CASE "-l", "--list-mode"
116  IF RunMode <> DEF_MODE THEN Errr &= ", multiple run modes" : RETURN ERROR_MESSAGE
117  RunMode = LIST_MODE
118  EmitTyp = FUNCTION_NAMES
119  CASE "-s", "--syntax-mode"
120  IF RunMode <> DEF_MODE THEN Errr &= ", multiple run modes" : RETURN ERROR_MESSAGE
121  RunMode = SYNT_MODE
122  EmitTyp = SYNTAX_REPAIR
123 
124  CASE "-a", "--asterix" : Asterix = 1
125  CASE "-c", "--cstyle"
126  Types = C_STYLE
127  CreateFunction = @cCreateFunction()
128  CreateVariable = @cCreateTypNam()
129  CASE "-d", "--doc-comments" : Docom = 1
130  CASE "-t", "--tree" : InTree = 1
131 
132  CASE "-e", "--emitter"
133  IF LEN(emi) THEN Errr &= ", multiple emitter setting" : RETURN ERROR_MESSAGE
134  emi = parseOptpara(i)
135  IF 0 = LEN(emi) THEN Errr &= ", invalid emitter setting" : RETURN ERROR_MESSAGE
136  CASE "-o", "--outpath"
137  IF LEN(OutPath) THEN Errr &= ", multiple outpaths" : RETURN ERROR_MESSAGE
138  OutPath = parseOptpara(i)
139  IF 0 = LEN(OutPath) THEN Errr &= ", invalid outpath" : RETURN ERROR_MESSAGE
140  CASE "-r", "--recursiv" : InRecursiv = 1
141 
142  CASE "-h", "--help" : RETURN HELP_MESSAGE
143  CASE "-v", "--version" : RETURN VERSION_MESSAGE
144 
145  CASE ELSE : par &= !"\t" & COMMAND(i)
146  END SELECT
147  CASE ELSE
148  SELECT CASE AS CONST ASC(COMMAND(i))
149  CASE ASC(""""), ASC("'")
150  InFiles &= MID(COMMAND(i), 2, LEN(COMMAND(i)) - 2) & !"\n"
151  CASE ELSE : InFiles &= COMMAND(i) & !"\n"
152  END SELECT
153  END SELECT : i += 1
154  WEND
155 
156  EmitIF = chooseEmitter(emi, par)
157  IF LEN(par) THEN Errr &= "unknown options '" & par & "'"
158 
159  IF 0 = LEN(InFiles) ANDALSO RunMode = DEF_MODE THEN RunMode = HELP_MESSAGE
160  Pars = NEW Parser(EmitIF)
161  RETURN IIF(LEN(Errr), ERROR_MESSAGE, RunMode)
162 END FUNCTION
163 
164 
165 
187 FUNCTION Options.chooseEmitter(BYREF F AS STRING, BYREF P AS STRING) AS EmitterIF PTR
188  VAR l = LEN(F)
189  IF l THEN
190  SELECT CASE UCASE(F)
191  CASE LEFT( "C_SOURCE", l) : EmitTyp = C_SOURCE
192  CASE LEFT( "FUNCTIONNAMES", l) : EmitTyp = FUNCTION_NAMES
193  CASE LEFT( "GTKDOCTEMPLATES", l) : EmitTyp = GTK_DOC_TEMPLATES
194  CASE LEFT( "DOXYGENTEMPLATES", l) : EmitTyp = DOXYGEN_TEMPLATES
195  CASE LEFT("SYNTAXHIGHLIGHTING", l) : EmitTyp = SYNTAX_REPAIR
196  CASE ELSE : EmitTyp = EXTERNAL
197  END SELECT
198  END IF
199 
200  VAR r = NEW EmitterIF
201 #IFDEF __FB_DOS__
202  Errr &= ", no plugin support on DOS platform!"
203 #ELSE
204  SELECT CASE AS CONST EmitTyp
205  CASE C_SOURCE : init_csource(r)
206  CASE FUNCTION_NAMES : init_lfn(r)
207  CASE GTK_DOC_TEMPLATES : init_gtk(r)
208  CASE DOXYGEN_TEMPLATES : init_doxy(r)
209  CASE SYNTAX_REPAIR : init_syntax(r)
210  CASE ELSE
211  DllEmitter = DYLIBLOAD(F)
212  IF 0 = DllEmitter THEN Errr &= ", couldn't load plugin " & F : EXIT SELECT
213  DIM ini AS FUNCTION CDECL(BYVAL AS EmitterIF PTR, BYREF AS STRING) AS EmitterIF PTR _
214  = DYLIBSYMBOL(DllEmitter, "EMITTERINIT") '&EmitterInit();
215  IF 0 = ini THEN Errr &= ", no EMITTERINIT function in emitter " & F : EXIT SELECT
216  EmitIF = ini(r, P) : EmitTyp = EXTERNAL
217  END SELECT
218 #ENDIF
219  RETURN r
220 END FUNCTION
221 
222 
223 
234 FUNCTION Options.scanFiles(BYREF Patt AS STRING, BYREF Path AS STRING) AS STRING
235  STATIC AS STRING p
236  VAR path_l = LEN(p), f = ""
237  IF LEN(Path) THEN p &= Path & SLASH
238 
239  IF InRecursiv > 0 THEN
240  VAR res = 0, n = DIR("*", fbDirectory, res), t = ""
241  WHILE LEN(n)
242  IF res = fbDirectory ANDALSO n <> "." ANDALSO n <> ".." THEN t &= n & NL
243  n = DIR()
244  WEND
245 
246  VAR a = 1, e = a, l = LEN(t)
247  WHILE a < l
248  e = INSTR(a, t, NL)
249  n = MID(t, a, e - a)
250  IF 0 = CHDIR(n) THEN f &= scanFiles(Patt, n) : CHDIR ("..")
251  a = e + 1
252  WEND
253  END IF
254 
255  VAR n = DIR(Patt), f_l = LEN(f)
256  WHILE LEN(n)
257  f &= p & n & NL
258  n = DIR()
259  WEND
260 
261  IF RunMode = FILE_MODE ANDALSO f_l > LEN(f) ANDALSO checkDir(OutPath & p) THEN f = ""
262  p = LEFT(p, path_l)
263  RETURN f
264 END FUNCTION
265 
266 
267 
277 FUNCTION Options.addPath(BYREF P1 AS STRING, BYREF P2 AS STRING) AS STRING
278  IF LEN(P1) ANDALSO RIGHT(P1, 1) <> SLASH THEN P1 &= SLASH
279  IF 0 = LEN(P2) ORELSE P2 = "." THEN RETURN P1
280  IF RIGHT(P2, 1) <> SLASH THEN P2 &= SLASH
281 #IFDEF __FB_UNIX__
282  IF P2[0] = ASC("/") THEN RETURN P2
283 #ELSE
284  IF MID(P2, 2, 1) = ":" THEN RETURN P2
285 #ENDIF
286  VAR i = LEN(P1), s = 1
287  WHILE MID(P2, s, 3) = *DirUp
288  i = INSTRREV(P1, SLASH, i - 1) : IF 0 = i THEN RETURN MID(P2, s)
289  s += 3
290  WEND
291  IF MID(P2, s, 2) = MID(*DirUp, 2) THEN s += 2
292  RETURN LEFT(P1, i) & MID(P2, s)
293 END FUNCTION
294 
295 
296 
305 FUNCTION Options.checkDir(BYREF P AS STRING) AS INTEGER
306  VAR a = 1, e = a, l = LEN(P), cupa = CURDIR()
307 #IFDEF __FB_UNIX__
308  IF LEFT(P, 1) = "/" THEN a = 2 : CHDIR("/")
309 #ELSE
310  IF MID(P, 2, 1) = ":" THEN a = 4 : CHDIR(LEFT(P, 3))
311 #ENDIF
312 
313  DO
314  e = INSTR(a, P, SLASH) : IF e = 0 THEN e = l + 1
315  VAR n = MID(P, a, e - a)
316  IF 0 = CHDIR(n) THEN a = e + 1 : CONTINUE DO
317  MKDIR(n)
318  IF 0 = CHDIR(n) THEN a = e + 1 : CONTINUE DO
319  EXIT DO
320  LOOP UNTIL a > l : CHDIR(cupa) : RETURN IIF(a > l, 0, 1)
321 END FUNCTION
322 
323 
324 
331 SUB Options.FileModi()
332  StartPath = CURDIR()
333  VAR cupa = StartPath
334 
335  IF 0 = LEN(InFiles) THEN ' InFiles defaults
336  SELECT CASE AS CONST RunMode
337  CASE SYNT_MODE, LIST_MODE : InFiles = !"Doxyfile\n"
338  CASE ELSE : InFiles = !"*.bas\n*.bi\n"
339  END SELECT
340  END IF
341 
342  IF 0 = LEN(OutPath) ANDALSO RunMode = FILE_MODE THEN
343  OutPath = ".." & SLASH ' def. OutPath in file mode
344  SELECT CASE AS CONST EmitTyp ' + emitter specific extension
345  CASE C_SOURCE : OutPath &= "c_src"
346  CASE SYNTAX_REPAIR : OutPath &= "fb_html"
347  CASE ELSE : OutPath &= "src"
348  END SELECT
349  END IF
350  OutPath = addPath(cupa, OutPath)
351 
352  IF RunMode = DEF_MODE THEN
353  Ocha = FREEFILE
354  OPEN CONS FOR OUTPUT AS #Ocha
355  END IF
356 
357  IF EmitIF->CTOR_ THEN EmitIF->CTOR_(@THIS)
358  VAR a = 0 _ ' Start character of next file name / pattern
359  , i = a _ ' Counter for characters
360  , inslsh = 0 _ ' Flag, set when filename name contains a path
361  , inpat = 0 _ ' Flag, set when name is a pattern
362  , l = LEN(InFiles) - 1 ' Length of input queue (number of characters)
363 
364  DO
365  SELECT CASE AS CONST InFiles[i]
366  CASE 0 : EXIT DO
367  CASE ASC("*"), ASC("?") : inpat = 1
368  CASE ASC(SLASH) : inslsh = i
369  CASE ASC(!"\n")
370  IF 0 = inpat THEN
371  doFile(MID(InFiles, a + 1, i - a))
372  ELSE
373  VAR in_pattern = ""
374  IF inslsh THEN
375  VAR path = MID(InFiles, a + 1, inslsh - a)
376  IF CHDIR(path) THEN
377  ERROUT("couldn't change dir to " & path)
378  ELSE
379  IF InTree THEN StartPath = addPath(cupa, path)
380  in_pattern = scanFiles(MID(InFiles, inslsh + 2, i - inslsh - 1), "")
381  END IF
382  ELSE
383  in_pattern = scanFiles(MID(InFiles, a + 1, i - a), "")
384  END IF
385 
386  VAR aa = 1, ee = aa, ll = LEN(in_pattern)
387  WHILE aa < ll
388  ee = INSTR(aa + 1, in_pattern, !"\n")
389  doFile(MID(in_pattern, aa, ee - aa))
390  aa = ee + 1
391  WEND
392  IF inslsh THEN CHDIR(cupa) : StartPath = cupa : inslsh = 0
393  inpat = 0
394  END IF : a = i + 1
395  END SELECT : i += 1
396  LOOP
397 
398  IF EmitIF->DTOR_ THEN EmitIF->DTOR_(@THIS)
399  SELECT CASE AS CONST RunMode
400  CASE LIST_MODE : IF Ocha THEN CLOSE #Ocha : MSG_LINE(LFN_FILE) : MSG_CONT("written")
401  CASE ELSE : IF Ocha THEN CLOSE #Ocha
402  END SELECT
403  MSG_END("")
404 END SUB
405 
406 
407 
414 SUB Options.doFile(BYREF Fnam AS STRING)
415  SELECT CASE AS CONST RunMode
416  CASE DEF_MODE
417  MSG_LINE(Fnam)
418  Pars->File_(Fnam, InTree)
419  IF LEN(Pars->ErrMsg) THEN MSG_CONT(Pars->ErrMsg)
420  CASE SYNT_MODE
421  IF LCASE(RIGHT(Fnam, 4)) = ".bas" ORELSE _
422  LCASE(RIGHT(Fnam, 3)) = ".bi" THEN
423  MSG_LINE(Fnam)
424  Pars->File_(Fnam, InTree)
425  IF LEN(Pars->ErrMsg) THEN MSG_CONT(Pars->ErrMsg)
426  ELSE
427  VAR nix = NEW Highlighter(Pars)
428  nix->doDoxy(Fnam)
429  DELETE nix
430  END IF
431  CASE LIST_MODE
432  IF LCASE(RIGHT(Fnam, 4)) = ".bas" ORELSE _
433  LCASE(RIGHT(Fnam, 3)) = ".bi" THEN
434  IF 0 = Ocha THEN
435  MSG_LINE(OutPath & LFN_FILE)
436  Ocha = startLFN(OutPath)
437  IF 0 = Ocha THEN MSG_CONT("error (couldn't write)") : EXIT SUB
438  MSG_CONT("opened")
439  END IF
440  MSG_LINE(Fnam)
441  Pars->File_(Fnam, InTree)
442  IF LEN(Pars->ErrMsg) THEN MSG_CONT(Pars->ErrMsg)
443  EXIT SUB
444  END IF
445 
446  VAR doxy = NEW DoxyUDT(Fnam) _
447  , recu = InRecursiv _
448  , oldo = Ocha _
449  , patt = ""
450 
451  MSG_LINE(Fnam)
452  IF 0 = doxy->Length THEN
453  MSG_CONT(doxy->Errr) : DELETE doxy
454  MSG_LINE("Doxyfile")
455  IF CHDIR(Fnam) THEN MSG_CONT("error (couldn't change directory)") : EXIT SUB
456  doxy = NEW DoxyUDT("Doxyfile")
457  IF 0 = doxy->Length THEN MSG_CONT(doxy->Errr) : DELETE doxy : EXIT SUB
458  END IF
459 
460  InRecursiv = IIF(doxy->Tag(RECURSIVE) = "YES", 1, 0)
461  VAR in_path = addPath(StartPath, doxy->Tag(INPUT_TAG))
462  DELETE doxy
463  IF CHDIR(in_path) THEN
464  MSG_CONT("error (couldn't change to " & in_path & ")")
465  ELSE
466  patt = scanFiles("*.bas", "") & scanFiles("*.bi", "")
467  IF 0 = LEN(patt) THEN
468  MSG_CONT("error (no input files in " & in_path & ")")
469  ELSE
470  MSG_CONT("scanned") _
471 
472  MSG_LINE(StartPath & LFN_FILE)
473  Ocha = startLFN(StartPath)
474  IF 0 = Ocha THEN
475  MSG_CONT("error (couldn't write)")
476  ELSE
477  MSG_CONT("opened")
478  VAR a = 1, e = a, l = LEN(patt)
479  WHILE a < l
480  e = INSTR(a + 1, patt, !"\n")
481  Pars->File_(MID(patt, a, e - a), InTree)
482  MSG_LINE(MID(patt, a, e - a)) : MSG_CONT("scanned")
483  a = e + 1
484  WEND
485  CLOSE #Ocha : MSG_LINE(StartPath & LFN_FILE) : MSG_CONT("written")
486  END IF
487  END IF
488  END IF
489 
490  CHDIR(StartPath)
491  Ocha = oldo
492  InRecursiv = recu
493 
494  CASE FILE_MODE
495  STATIC AS STRING out_name
496  VAR a = 1, i = INSTRREV(Fnam, ".")
497  out_name = LEFT(Fnam, i)
498 
499 #IFDEF __FB_UNIX__
500  IF LEFT(out_name, 1) = "/" THEN a = 2
501 #ELSE
502  IF MID(out_name, 2, 1) = ":" THEN a = 2 : out_name[1] = out_name[0]
503 #ENDIF
504  WHILE MID(out_name, a, 3) = *DirUp
505  a += 3
506  WEND
507  IF MID(out_name, a, 2) = MID(*DirUp, 2) THEN a += 2
508  out_name = MID(out_name, a)
509 
510  VAR path = OutPath & LEFT(out_name, INSTRREV(out_name, SLASH))
511  IF checkDir(path) THEN
512  ERROUT("couldn't create directory " & path)
513  ELSE
514  out_name = OutPath & out_name & *IIF(RIGHT(FNam, 3) = ".bi", @"h", @"c")
515  Ocha = FREEFILE
516  IF OPEN(out_name FOR OUTPUT AS #Ocha) THEN
517  ERROUT("couldn't write " & out_name)
518  ELSE
519  Pars->File_(Fnam, InTree)
520  CLOSE #Ocha
521  MSG_LINE(Fnam) : IF LEN(Pars->ErrMsg) THEN MSG_CONT(Pars->ErrMsg)
522  END IF
523  END IF
524  END SELECT
525 END SUB
526