started to fix the manuals for EBuf. Implemented a
[neuro.git] / docs / neuroman.tcl
blob1d1d641eff6d1d1ce490469ab73f4236767c0787
1 # copyright neuroponic 2006
2 # author : Nicholas Niro
3 # by using this piece of software, you accept that it
4 # has no warranty at all, use it at your own risk.
6 # permission is hereby granted to modify and distribute
7 # this script as long as the original authoring is kept.
14 # documentation section, the syntax of the configuration file
15 # and the syntax of the comments in the header files.
17 # configuration file syntax
19 # the configuration file requires 5 lines
20 # the first line is the name of the program/library
21 # the firs line is the section number
22 # here are all the sections with a description but you will
23 # generally use the section 3.
24 # Section
25 # 1 User commands
26 # 2 System calls, that is, functions provided by the kernel.
27 # 3 Subroutines, that is, library functions.
28 # 4 Devices, that is, special files in the /dev directory.
29 # 5 File format descriptions, e.g. /etc/passwd.
30 # 6 Games, self-explanatory.
31 # 7 Miscellaneous, e.g. macro packages, conventions.
32 # 8 System administration tools that only root can execute.
33 # 9 Another
34 # n New documentation, that may be moved to a more appropriate section.
35 # l Local documentation referring to this particular system.
36 # the second line is the center footer
37 # the third line is the left footer
38 # and the last line is the center header
40 # here is an example configuration file
41 # 3
42 # 02 Sep 2006
43 # v0.44.0
44 # Libneuro Functions
48 # the syntax inside the header files
50 # first of all, the script will parse the comments that are
51 # just above a function prototype which starts with the extern keyword
52 # and it will only parse those with an extra star ie /**
53 # so to make this script work good you need to have this minimum:
54 #/**
55 # *
56 # *
57 # */
58 #extern void somefunc(int foo, int bar);
60 # the actual stuff that will be put in the man page will need to be enclosed
61 # between the /** and the */ this is how the script will know the end of the
62 # things to parse.
64 # the script will also fetch data from the extern prototype too, it will
65 # get the function name, return type, variable types and names it will parse
66 # until it goes to the ending ';' and it will ignore any ( and ) characters.
68 # inside the /** */ comments, a special "language" has to be used which uses
69 # commands or variables. commands/variables always start with the character '@'
70 # for example : @description
71 # the script will parse all the current data (the text) into the last "command"
72 # issued.
73 # heres the complete list of those commands/variables and what they do :
75 # take note that those commands can be entered in any order.
79 # @name -- the name the man page file name will be, necessary for all except
80 # the functions which automatically defaults to the function name.
81 # If this variable is present for a function prototype then it will
82 # override the function name with this name.
83 # @sdescri -- this is the small description, the summary that should be about 1
84 # sentence.
85 # @description -- this is the exhaustive description, it can be of any length you want.
86 # @param -- this command is special, you can not just write @param , you also have
87 # to put the param's "direction" (input output or both) in the form
88 # @param[...] (see below) You don't need to specify which function
89 # argument the param goes to, it goes sequentially and remember to put a
90 # description for each @param[...].
91 # @param[in] -- the input type see @param
92 # @param[out] -- the output type see @param
93 # @param[io] -- both input and output see @param
94 # @related -- text after this (which should be functions or such) will be put in the see also
95 # section.
96 # @examples -- text after this is put in the code examples section.
97 # @returnval -- text after this is put in the return value section.
98 # @errors -- text after this is put in the error codes section.
102 # -- constants --
103 # put the version here
104 set version "2.1.3"
106 # -- global variables --
108 set individual 0
109 set use_config 0
110 set files ""
111 set config ""
113 proc showHelp { } {
114 echo "Usage : neuroman \[OPTIONS\] ... \[FILES\]"
115 echo "A very simple tcl header file parser to the man format."
116 echo "The documentation on how to format the comments before"
117 echo "the functions is inside this script."
118 echo " -c file input the configuration file"
119 echo " -i,--individual saves each functions from FILES into their own man"
120 echo " pages instead of outputing to standard output."
121 echo " -v,--version output the version of neuroman"
122 echo " -h,--help output this help message"
123 echo
124 echo "report bugs to neuroman-bugs@neuroponic.com"
127 proc showVersion { } {
128 global version
129 echo "neuroman version $version"
132 proc handleArgs { } {
133 global argc
134 global argv
135 global individual
136 global files
137 global config
138 global use_config
139 set got_config 0
140 if {$argc == 0} {
141 showHelp
142 return 0
143 } else {
145 #we check and handle the arguments
146 foreach elem $argv {
147 if {$elem == "-h" || $elem == "--help"} {
148 showHelp
149 return 0
150 } elseif {$elem == "-v" || $elem == "--version"} {
151 showVersion
152 return 0
153 } elseif {$elem == "-i" || $elem == "--individual"} {
154 set individual 1
155 } elseif {$elem == "-c"} {
156 set got_config 1
157 } elseif {$got_config == 1} {
158 set got_config 0
159 set config $elem
160 set use_config 1
161 } else {
162 if {[string index $elem 0] == "-"} {
163 echo "Invalid argument $elem"
164 echo "use --help to see the list of valid arguments."
165 } else {
166 set files [linsert $files 1 "$elem"]
171 return 1
174 return 0
178 # this function parses a C function prototype to remove its leading
179 # and ending brackets.
180 # it will not touch brackets that are not leading and ending.
181 proc arrangeFunction {function} {
182 set t 0
183 set i 0
184 #set total [llength $function]
185 #set found_start 0
186 #set found_end 0
187 #set coord_end 0
189 # gets rid of all the commas
190 #while {$t < [string length $function]} {
191 # set t [string first "," $function $t]
193 # if {$t == -1} {
194 # break;
195 # } else {
196 #echo $t
197 # set function [string replace $function $t $t " "]
199 # incr t
202 # we find the first opening bracket
203 set t [string first "(" $function]
205 # if we found one, we remove it
206 if {$t > 0} {
207 set function [string replace $function $t $t " "]
210 # we find the last opening bracket
211 set t [string last ")" $function]
213 # if we found one, we remove it
214 if {$t > 0} {
215 set function [string replace $function $t $t " "]
219 # now we will kind of hack a way to assemble ()() function pointers
220 # into an whole
221 set t 0
222 set found_begin 0
223 set found_end 0
224 set coord_begin 0
225 set coord_end 0
226 while {$t < [string length $function]} {
227 set t [string first "(" $function $t]
229 if {$t == -1} {
230 break
231 } elseif {$found_begin == 0} {
232 #echo $t
233 #set function [string replace $function [expr $t - 1] [expr $t - 1] "\{"]
234 #set coord_begin $t
235 set found_begin 1
236 set found_end 0
240 set t [string first ")" $function $t]
242 if {$t == -1} {
243 break
244 } elseif {$found_end == 1} {
245 #echo $t
246 #set function [string replace $function [expr $t + 1] [expr $t + 1] "\}"]
247 set found_begin 0
248 } else {
249 incr found_end
254 #puts $function
256 # we get rid of the beginning extern if any
257 if {[lindex $function 0] == "extern"} {
258 set function [lrange $function 1 end]
261 return $function
264 proc pushData {storage toadd extra} {
265 upvar $storage buffer
266 upvar $extra xtra
268 if {$storage == ""} {
269 return
272 if {$xtra == ""} {
273 set buffer $toadd
274 } else {
275 set buffer "$buffer $xtra {$toadd}"
277 set xtra ""
281 proc parseComment {comment name sdescri ldescri options returnval example errors related} {
282 upvar $name cname
283 upvar $sdescri small_d
284 upvar $ldescri long_d
285 upvar $options opt
286 upvar $returnval retv
287 upvar $example exmp
288 upvar $errors err
289 upvar $related rela
291 set ctype ""
292 set buffer ""
293 set extra ""
295 foreach word $comment {
297 #puts $word
299 #set word [string trim $word \"*\"]
301 if {$word == "@name"} {
302 pushData $ctype $buffer extra
304 set ctype cname
306 set buffer ""
307 } elseif {$word == "@sdescri"} {
308 pushData $ctype $buffer extra
310 set ctype small_d
312 set buffer ""
313 } elseif {$word == "@description"} {
314 pushData $ctype $buffer extra
316 set ctype long_d
318 set buffer ""
319 } elseif {$word == "@param\[in\]"} {
320 pushData $ctype $buffer extra
322 set ctype opt
323 set extra 0
325 set buffer ""
326 } elseif {$word == "@param\[out\]"} {
327 pushData $ctype $buffer extra
329 set ctype opt
330 set extra 1
332 set buffer ""
333 } elseif {$word == "@param\[io\]"} {
334 pushData $ctype $buffer extra
336 set ctype opt
337 set extra 2
339 set buffer ""
340 } elseif {$word == "@related"} {
341 pushData $ctype $buffer extra
343 set ctype rela
345 set buffer ""
346 } elseif {$word == "@examples"} {
347 pushData $ctype $buffer extra
349 set ctype exmp
351 set buffer ""
352 } elseif {$word == "@returnval"} {
353 pushData $ctype $buffer extra
355 set ctype retv
357 set buffer ""
358 } elseif {$word == "@errors"} {
359 pushData $ctype $buffer extra
361 set ctype err
363 set buffer ""
364 } else {
365 set buffer "$buffer $word"
369 pushData $ctype $buffer extra
371 # we clean the small buffers of any * characters
372 # from the comment syntax
373 Clean_String cname
374 Clean_String small_d
375 Clean_String long_d
376 Clean_String opt
377 Clean_String retv
378 Clean_String exmp
379 Clean_String err
380 Clean_String rela
383 proc GetStringWord { str current} {
384 #returns the word it fetched
385 #current needs to be the variable itself, not the data
386 upvar $current a
387 set slen [string length $str]
388 set sepchar " "
389 set outword ""
390 set initial $a
392 while {$a < $slen} {
393 set c [string index $str $a]
395 if {$c != " "} {
396 set outword "$outword$c"
397 #echo "outword : $outword initial $initial current $a char : $c"
398 } else {
399 break;
402 incr a
405 incr a
406 return $outword
409 proc Clean_String {str} {
410 upvar $str tochange
411 set new_string ""
412 set temp ""
414 # \\052 == '*'
415 # \\\\175 == '\}' and \c\}
417 regsub -all " \\052( |\n|$)" $tochange {} new_string
419 set temp $new_string
420 # we get rid of any * right before a '\}'
421 regsub -all " \\052(\})" $temp "\}" new_string
423 set temp $new_string
425 # we get rid of the very annoying space that gets
426 # added at the very beginning for every paragraphs.
427 # we replace by the full string and add a \b character
428 # at the end to get rid of the space.
429 regsub -all "\(\\\\n \)*\\\\n " $temp "&\b" new_string
431 set temp $new_string
432 # we also get rid of any trailing spaces
433 regsub -all -line "^ " $temp "" new_string
436 set tochange $new_string
439 proc genMan_Unique {comment} {
440 global individual
441 global config
442 set name ""
443 set msmall_description ""
444 set mdescription ""
445 set moptions ""
446 set mreturnv ""
447 set mexamples ""
448 set merrors ""
449 set mseealso ""
450 set config_i [parseConfig $config]
453 # by default we output to stdout (default screen)
454 set fp stdout
456 # we get rid of the /* character in the string
457 set comment [string trim $comment "/*"]
459 # populate our variables
460 parseComment $comment name msmall_description mdescription moptions mreturnv mexamples merrors mseealso
462 if {$name == ""} {
463 puts "Error : missing a @name element from a comment"
464 return
467 if {$individual == 1} {
468 # we get rid of any ending spaces
469 regsub "\( \)*$" $name "" name
470 # we trim the function's name of any leading * in case
471 # it returns a pointer -- example : char *somefunction()
472 set fp [open "[string trim $name \"*\"].[lindex $config_i 0]" w]
473 #set fp [open "$name.[lindex $config 0]" w]
476 puts $fp ".TH $name [lindex $config_i 0] \"[lindex $config_i 1]\" \"[lindex $config_i 2]\" \"[lindex $config_i 3]\""
477 puts $fp ".SH NAME"
479 if {[llength $msmall_description] > 0} {
480 puts $fp ".TP"
481 puts $fp "[string trim $name \"*\"]"
482 puts $fp "\- $msmall_description"
483 } else {
484 puts $fp "[string trim $name \"*\"]"
487 if {[llength $mdescription] > 0} {
488 puts $fp ".SH DESCRIPTION"
489 puts $fp [subst "$mdescription"]
492 if {[llength $mreturnv] > 0 && [lindex $function 0] != ""} {
493 puts $fp ".SH RETURN VALUES"
494 puts $fp "$mreturnv"
497 if {[string length $mexamples] > 0} {
498 puts $fp ".SH EXAMPLE(S)"
500 puts $fp [subst $mexamples]
503 if {[llength $merrors] > 0} {
504 puts $fp ".SH ERRORS"
505 puts $fp "$merrors"
508 if {[llength $mseealso] > 0} {
509 puts $fp ".SH SEE ALSO"
510 puts $fp "$mseealso"
514 if {$individual == 1} {
515 close $fp
521 proc genMan {comment function} {
522 global individual
523 global config
524 set name ""
525 set msmall_description ""
526 set mdescription ""
527 set moptions ""
528 set mreturnv ""
529 set mexamples ""
530 set merrors ""
531 set mseealso ""
532 set config_i [parseConfig $config]
534 # we get rid of any { or } characters
535 set function [eval "concat $function"]
537 # by default we output to stdout (default screen)
538 set fp stdout
540 # arranges the function data so its easy to handle
541 set function [arrangeFunction $function]
543 # we get rid of the /* character in the string
544 set comment [string trim $comment "/*"]
546 # populate our variables
547 parseComment $comment name msmall_description mdescription moptions mreturnv mexamples merrors mseealso
549 if {$name == ""} {
550 if {[lindex $function 1] == ""} {
551 # an error
552 return
554 set name [lindex $function 1]
558 if {$individual == 1} {
559 # we trim the function's name of any leading * in case
560 # it returns a pointer -- example : char *somefunction()
561 set fp [open "[string trimleft $name \"*\"].[lindex $config_i 0]" w]
564 puts $fp ".TH $name [lindex $config_i 0] \"[lindex $config_i 1]\" \"[lindex $config_i 2]\" \"[lindex $config_i 3]\""
565 puts $fp ".SH NAME"
567 if {[llength $msmall_description] > 0} {
568 puts $fp ".TP"
569 puts $fp "[string trim $name \"*\"]"
570 puts $fp "\- [subst $msmall_description]"
571 } else {
572 puts $fp "[string trim $name \"*\"]"
576 #echo $function
577 if {[lindex $function 0] != ""} {
578 puts $fp ".SH SYNOPSIS"
579 puts $fp "[lindex $function 0] $name\([lrange $function 2 [expr [llength $function] - 2]]\)"
582 if {[string length $mdescription] > 0} {
583 puts $fp ".SH DESCRIPTION"
584 puts $fp [subst $mdescription]
587 # The arguments... beats me why I initially called that
588 # options...
589 if {[llength $moptions] > 0 && [lindex $function 0] != ""} {
590 set ototal [llength $moptions]
591 set i 1
592 set cfunc 3
594 puts $fp ".SH ARGUMENTS"
596 while {$i < $ototal} {
597 set ctype [lindex $moptions [expr "$i - 1"]]
598 set t 0
599 set is_funcptr 0
601 if {$ctype == 0} {
602 set type "(input)"
603 } elseif {$ctype == 1} {
604 set type "(output)"
605 } else {
606 set type "(input and output)"
609 #set nfunc [string trim [lindex $function $cfunc] "*"]
610 set nfunc [lindex $function $cfunc]
612 # we check to see if the current argument is a pointer to
613 # a function and if yes, we do something special to include
614 # all its arguments
615 if {[string index $nfunc 0] == "("} {
616 set is_funcptr 1
619 if {$is_funcptr == 1} {
620 set go_on 1
621 set found_one 0
623 set str $nfunc
624 while { $go_on == 1 } {
625 set cur [string last ")" $str]
627 # this is a special case where the function pointer
628 # has no arguments at all.
629 # like : void (*callback)()
630 if {$cur > 0} {
631 if {[lindex $function [expr $cur - 1]] == "("} {
632 break;
633 } elseif {$found_one == 1} {
634 break;
635 } else {
636 incr found_one
640 incr cfunc
641 set str [lindex $function $cfunc]
643 set nfunc [linsert $nfunc [llength $nfunc] $str]
644 #echo "SPECIAL $nfunc -> $str"
649 # we remove the last comma if we find one
650 set t [string last "," $nfunc]
652 #echo "cur $cfunc last [llength $function]"
653 if {$t > 0 && [expr [llength $function] - 1] > $cfunc} {
654 set nfunc [string replace $nfunc $t $t " "]
657 puts $fp ".TP"
658 puts $fp ".BI \"$nfunc \" $type"
659 puts $fp "[lindex $moptions $i]\n"
661 incr cfunc 2
663 incr i 2
667 if {[llength $mreturnv] > 0 && [lindex $function 0] != ""} {
668 puts $fp ".SH RETURN VALUES"
669 puts $fp "$mreturnv"
672 if {[string length $mexamples] > 0} {
673 puts $fp ".SH EXAMPLE(S)"
674 puts $fp [subst $mexamples]
677 if {[llength $merrors] > 0} {
678 puts $fp ".SH ERRORS"
679 puts $fp "$merrors"
682 if {[llength $mseealso] > 0} {
683 puts $fp ".SH SEE ALSO"
684 puts $fp "$mseealso"
691 if {$individual == 1} {
692 close $fp
698 # "/**" gather -> "**/" stop gather
699 # OR "*/" stop gather and look for anything except "/**"
700 # after a "/**" "*/" combination (next line)
701 # look for "extern" gather2 -> ";" stop gather2 dump in function ...
703 # the part action can include :
704 # none : none yet (put that when nothing is needed anymore)
705 # gather : starts buffering inside the buffer part. And starts matching in the
706 # end_string_list list.
707 # childonly : we got a match in the end_string_list so we process only in it
708 # process_data : tells the algo that the current branch got a complete set of
709 # matching patterns so it can now be processed. If this action
710 # is choosen, the extra part is used to know which function to
711 # call with what arguments.
712 # gather_line : exactly like gather but it doesn't match anything, it stops after
713 # a line change. It uses the extra part for the function to call.
714 # it also uses the current_action element to the current line number.
716 # the end_string part is a list with a list of strings that can be matched.
717 # and the next element is the child elements exactly like the MATCH list.
719 # buffer is the current buffer which is filled only when the begin_string is
720 # matched. Filling it only ends when a match is found inside end_string_list
722 # begin_string_list action buffer current_action extra end_string_list
724 # take note that the general order is important for correct dependencies
725 # the more dependencies a match has, the more it is to the end.
726 proc MATCH_format {} {
728 set MATCH_Handled_Test "{\"houba\" gather_line \"\" none \"genMan_Test\" {} }"
730 set MATCH_Handled_Comment_End_Unique "{\"**/\" process_data \"\" none \"genMan_Unique\" {} }"
732 set MATCH_Function_Prototype_End "{\";\" process_data \"\" none \"genMan\" {}}"
734 set MATCH_Function_Prototype "{\"extern\" gather \"\" none \"\" {\
735 $MATCH_Function_Prototype_End} }"
737 set MATCH_Handled_Comment_End "{\"*/\" childonly \"\" none \"\" {\
738 $MATCH_Function_Prototype} }"
741 set MATCH_Handled_Comment_Start "{\"/**\" gather \"\" none \"\" {\
742 $MATCH_Handled_Comment_End_Unique \
743 $MATCH_Handled_Comment_End} }"
746 set MATCH_list "$MATCH_Handled_Comment_Start $MATCH_Handled_Test"
748 #set i 0
749 #foreach parent $MATCH_list {
750 # MATCH_process "/**" MATCH_list "" $parent $i
752 #puts "$parent"
754 # incr i
757 #MATCH_process "/**" MATCH_list
758 #MATCH_process "hello" MATCH_list
759 #MATCH_process "*/" MATCH_list
760 #MATCH_process "extern" MATCH_list
761 #MATCH_process ";" MATCH_list
763 #puts "---> $MATCH_list"
765 #MATCH_resetProcess MATCH_list 0 0
767 return $MATCH_list
770 proc MATCH_process {stringtm thelist} {
771 upvar $thelist tlist
772 set i 0
773 set depth 0
774 set num 0
776 #puts "$tlist\n"
777 #puts "fetched whole \"[Fetch_Cascade_Whole $tlist 5 {0} 0 1]\""
778 #puts "fetched data \"[Fetch_Cascade_Data $tlist 5 0 {0 1} 1]\""
780 #puts "\nChanging data"
781 #set tlist [Set_Cascade_Data $tlist 5 3 "childonly" {0 1 0 0} 3]
782 #puts "fetched modified data \"[Fetch_Cascade_Data $tlist 5 3 {0 1 0 0} 3]\""
784 #puts "STRING -> $stringtm"
786 MATCH_loopProcess $stringtm tlist 0 0
789 proc MATCH_resetProcess {thelist num depth} {
790 upvar $thelist tlist
792 #puts "will process num $num depth $depth"
794 while {1 != 2} {
795 set cData [Fetch_Cascade_Whole $tlist 5 $num $depth 1]
797 #puts $cData
799 if {$cData == -1 || $cData == ""} {
800 break;
803 foreach elem $cData {
804 set child_num 0
806 # we reset the buffer elemenet
807 set tlist [Set_Cascade_Data $tlist 5 2 "" $num $depth]
809 # we reset the current_action element
810 set tlist [Set_Cascade_Data $tlist 5 3 "none" $num $depth]
814 set child_num $num
816 lappend child_num 0
819 #puts "child num : $child_num -- depth [expr $depth + 1]"
821 MATCH_resetProcess tlist $child_num [expr $depth + 1]
823 lset num $depth [expr [lindex $num $depth] + 1]
828 proc MATCH_loopProcess {stringtm thelist num depth} {
829 upvar $thelist tlist
831 #puts "will process num $num depth $depth string $stringtm"
833 while {1 != 2} {
834 set cData [Fetch_Cascade_Whole $tlist 5 $num $depth 1]
836 #puts $cData
838 if {$cData == -1 || $cData == ""} {
839 break;
842 foreach elem $cData {
843 set child_num 0
845 #puts [Fetch_Cascade_Data $tlist 5 0 $num $depth]
846 set _err [MATCH_subprocess $stringtm tlist $num $depth]
848 if {$_err == 0} {
849 # we call a subsequent child
851 #lset num $depth [expr [lindex $num $depth] + 1]
853 set child_num $num
855 lappend child_num 0
858 #puts "child num : $child_num -- depth [expr $depth + 1]"
860 if {[MATCH_loopProcess $stringtm tlist $child_num [expr $depth + 1]] == 1} {
861 return 1
864 #puts "finished child run"
866 # we don't need to run on the next nodes
867 return 0
868 } elseif {$_err == 2} {
869 return 1
870 } else {
871 lset num $depth [expr [lindex $num $depth] + 1]
875 break
879 # this function calls itself
880 # if the current node needs to call subsequent childs, it will return 0
881 # if not, it will return 1
882 proc MATCH_subprocess {stringtm thelist num depth} {
883 upvar $thelist tlist
884 set node [Fetch_Cascade_Whole $tlist 5 $num $depth]
886 #puts "node [lindex $node 0] string $stringtm"
888 switch [lindex $node 3] {
889 none {
890 foreach string_match [lindex $node 0] {
891 #puts -nonewline "trying to see if $stringtm is $string_match "
893 if {[ParseString $string_match $stringtm] == 1} {
894 set output $tlist
896 #puts " <- MATCH \n"
898 switch [lindex $node 1] {
900 none {
901 return 1
904 gather {
905 set tlist [Set_Cascade_Data $tlist 5 3 "gather" $num $depth]
909 childonly {
910 set tlist [Set_Cascade_Data $tlist 5 3 "childonly" $num $depth]
912 set tlist [Set_Cascade_Data $tlist 5 3 "childonly" [lrange $num 0 [expr $depth - 1]] [expr $depth - 1]]
914 return 2
917 process_data {
918 set i 0
919 set buf ""
920 # this is the "last" command set for a list of matches, thats why we reset the list
921 # need to call the extra element with the necessary arguments
923 while {$i < $depth} {
925 if {[Fetch_Cascade_Data $tlist 5 1 [lrange $num 0 $i] $i] == "gather"} {
926 lappend buf [Fetch_Cascade_Data $tlist 5 2 [lrange $num 0 $i] $i]
929 incr i
931 #puts $tlist
932 #puts $buf
934 eval "[lindex $node 4] $buf"
936 #puts "we reset the process"
938 MATCH_resetProcess tlist 0 0
940 return 2
943 gather_line {
944 # don't know yet how to handle this one
946 return 1
952 #puts "initial gathering action [lindex $node 0] -> $stringtm"
954 set buf [lindex $node 2]
956 lappend buf $stringtm
958 set tlist [Set_Cascade_Data $tlist 5 2 $buf $num $depth]
960 # we only need one match
961 return 2
962 } else {
963 #puts "\n"
967 return 1
970 gather {
971 #puts "gathering action [lindex $node 0] -> $stringtm"
973 set buf [lindex $node 2]
975 lappend buf $stringtm
977 set tlist [Set_Cascade_Data $tlist 5 2 $buf $num $depth]
980 return 0
983 childonly {
984 #puts "child only state [lindex $node 0]"
986 return 0
989 process_data {
990 puts "process data state? this is an error buddy!"
993 gather_line {
994 puts "gather line state? this is an error buddy!"
998 return 1
1001 # sets a single data in a list/sublist corresponding to depth
1002 # and number pattern
1003 proc Set_Cascade_Data {alist sublist_num elem data num_in depth} {
1004 set i 0
1005 set num $num_in
1006 set child ""
1008 set i [expr $depth + 1]
1010 while {$i > 0} {
1011 set i [expr $i - 1]
1013 set current [Fetch_Cascade_Whole $alist $sublist_num $num $i]
1014 set whole [Fetch_Cascade_Whole $alist $sublist_num $num $i 1]
1016 if {$i == $depth} {
1017 lset current $elem $data
1018 } elseif {$child != ""} {
1019 #puts "$sublist_num --> $current -- $child"
1020 set current [lreplace $current $sublist_num $sublist_num $child]
1023 lset whole [lindex $num_in $i] $current
1026 #puts "$i -- $current"
1027 #puts "$whole"
1029 set child $whole
1031 #set tempo [lreplace [Fetch_Cascade_Whole $alist $sublist_num $num $i 1] [lindex $num 0] [lindex $num 0] $current]
1032 #puts "$whole TEST --_-_->> [lindex $whole [lindex $num_in $i]]"
1034 set num [lrange $num 0 end-1]
1035 #puts "DEBUG -- $num"
1037 return $whole
1040 # in a cascading list/sublist variable, output a full list corresponding
1041 # to a certain depth and a number pattern.
1042 proc Fetch_Cascade_Whole {alist sublist_num num_in depth {relative 0}} {
1043 set i 0
1044 set num ""
1046 # we first reverse the num variable
1047 set i [llength $num_in]
1049 foreach item $num_in {
1050 set num [linsert $num 0 $item]
1053 set i 0
1055 #puts "Whole output : number -- [lindex $num $depth]"
1057 foreach item $alist {
1058 #puts "THERES #[llength $alist] elements total! ?$relative?"
1059 #puts "$i - [lindex $num $depth]"
1061 if {$i == [lindex $num $depth]} {
1063 #puts "PROCESSING -- $item"
1066 if {$depth == 0} {
1067 if {$relative == 0} {
1068 return $item
1069 } else {
1070 return $alist
1072 } else {
1073 return [Fetch_Cascade_Whole [lindex $item $sublist_num] $sublist_num $num_in [expr $depth - 1] $relative]
1077 incr i
1080 return -1
1083 # in a cascading list/sublist variable, output a single element
1084 # corresponding to a certain depth and a number pattern.
1085 proc Fetch_Cascade_Data {alist sublist_num elem num_in depth} {
1088 set output [Fetch_Cascade_Whole $alist $sublist_num $num_in $depth]
1090 if {$output != -1} {
1091 if {$elem >= 0 && $elem < [llength $output]} {
1092 return [lindex $output $elem]
1096 return -1
1099 proc parseFile {file config} {
1100 # gather 1 is used to gather the comment
1101 # data
1102 set gather1 ""
1103 # gather 2 is used to gather principally
1104 # function prototypes and in the future,
1105 # more.
1106 set gather2 ""
1107 # contains the current line number for use
1108 # by the code to know when a line changed
1109 set current_line 0
1110 #global MATCH_list
1112 #puts [subst $MATCH_list]
1114 set matchform [MATCH_format]
1117 # we loop line by line, string by string and character by character
1119 # we continue until eof to loop line by line
1120 while {[eof $file] == 0} {
1121 set line [gets $file]
1122 set a 0
1124 # count the number of characters in the line
1125 set line_len [string length $line]
1127 # loop string by string in the current line
1128 while {$a < $line_len} {
1129 set str [GetStringWord $line a]
1131 MATCH_process $str matchform
1134 # we increment the current number of lines
1135 incr current_line
1139 # returns 0 if theres no matching strings
1140 # and 1 if there is
1141 proc ParseString {string_indep string_depen} {
1142 # current matching characters
1143 set match 0
1144 set i 0
1145 set len [string length $string_depen]
1147 #puts "Checking String \"$string_indep\" over \"$string_depen\""
1149 # loop character by character in the current string
1150 while {$i < $len} {
1151 set char [string index $string_depen $i]
1152 set indep [string index $string_indep $match]
1154 #puts "depen $char indep $indep"
1156 if {$char == $indep} {
1157 incr match
1158 } else {
1160 # special case where we check the former character with this one to see
1161 # if it matches... if it matches, it means we might have a redundant
1162 # character which was primarily matched.
1164 # example : our indep string is */ and our input string is **/
1165 # without this code, the first * is matched then it checks the
1166 # second * over with / but it won't match and it restarts the check.
1167 # | |
1168 # */ **/ 1
1169 # | |
1170 # */ **/ 0 (so the algo restarts)
1171 # | |
1172 # */ **/ 0 (see, this is a bit false because it was
1173 # reset and thus the string wasn't matched.)
1175 if {$match > 0 && $char == [string index $string_indep [expr $match - 1]]} {
1176 set match 1
1177 } else {
1178 set match 0
1182 if {$match == [string length $string_indep]} {
1183 return 1
1186 incr i
1189 return 0
1192 proc parseConfig {file} {
1193 global use_config
1195 if { $use_config == 0} {
1196 # we output a default stock config
1197 set conf {{3} {"center footer"} {"left footer"} {"center header"}}
1198 return $conf
1199 } else {
1200 # we parse the configuration from the file
1201 set conf ""
1203 set fp [open $file r]
1205 while {[eof $fp] == 0} {
1206 set conf "$conf {[gets $fp]}"
1209 close $fp
1211 return $conf
1215 proc handleFiles {} {
1216 global files
1217 global individual
1218 global use_config
1219 global config
1221 if {$use_config == 1} {
1222 # we first check if the configuration file exists
1223 set fp [open $config r]
1224 close $fp
1227 # we check to see if the files exist or not
1228 foreach elem $files {
1229 set fp [open $elem r]
1231 close $fp
1234 # now we need to open each of them and parse their content
1235 foreach elem $files {
1236 set fp [open $elem r]
1238 parseFile $fp [parseConfig $config]
1240 close $fp
1244 proc main { } {
1245 set err [handleArgs]
1248 if {$err == 0} {
1249 exit
1252 handleFiles
1255 main