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