1# 2# 3# Librairie de fonctions TCL pour la g�n�ration de tableaux 4# 5# Exemple d'utilisation 6# 7# set style { ... } 8# set data {} 9# for ... 10# lappend data [list pattern val1 val2 ... valn] 11# puts [::arrgen::output "html" $style $data] 12# 13# Ou : 14# 15# set style { ... } 16# if {[::arrgen::parse tabstyle $style msg] == -1} then { 17# puts stderr $msg 18# } 19# set data {} 20# for ... 21# lappend data [list pattern val1 val2 ... valn] 22# puts [::arrgen::output "html" tabstyle $data] 23# 24# Langage des styles 25# - global 26# - chars 27# <int> (normal | bold | italic)+ 28# - color 29# <hex> | transparent 30# - align 31# left | right | center | justify 32# - botbar 33# yes | no 34# - format 35# raw | cooked | lines | <procedure> 36# - columns 37# <int>+ 38# - csv 39# - separator 40# <character> 41# - latex 42# - linewidth 43# <float> 44# - bordersep 45# <float> 46# - pattern <nom> 47# - chars 48# <int> (normal | bold | italic)+ 49# - color 50# <hex> | transparent 51# - align 52# left | right | center | justify 53# - botbar 54# yes | no 55# - format 56# raw | cooked | lines | <procedure> 57# - topbar 58# yes | no 59# - title 60# yes | no 61# - vbar 62# yes | no 63# - column 64# - chars 65# <int> (normal | bold | italic)+ 66# - color 67# <hex> | transparent 68# - align 69# left | right | center | justify 70# - botbar 71# yes | no 72# - format 73# raw | cooked | lines | <procedure> 74# - multicolumn 75# <int> 76# 77# Historique 78# 2002/05/08 : pda : d�but de la conception 79# 2002/05/10 : pda : codage de l'analyse et des g�n�rations csv et html 80# 2002/05/11 : pda : codage de la g�n�ration latex 81# 2002/05/12 : pda : mise au point 82# 2003/08/08 : pda : somme des largeurs des colonnes ramen�e � 100 % 83# 2006/12/06 : pda : utilisation de CSS 84# 85 86package require webapp 87package provide arrgen 1.1 88 89namespace eval arrgen { 90 # 91 # Fonctions utilisables � l'ext�rieur du package 92 # 93 94 namespace export parse output debug \ 95 latex-string 96 97 # 98 # Liste avec valeurs possible : {errors syntax} 99 # 100 101 variable debuginfos {} 102 103 # 104 # Valeurs par d�faut et m�canisme d'h�ritage 105 # 106 107 variable defaults 108 array set defaults { 109 inherit-defaults-global { 110 csv-separator 111 latex-linewidth latex-bordersep 112 charsize charfont color align botbar format 113 } 114 115 csv-separator , 116 latex-linewidth 175 117 latex-bordersep 2.3 118 119 charsize 12 120 charfont normal 121 color transparent 122 align left 123 botbar 0 124 format ::arrgen::output-cooked 125 126 inherit-defaults-pattern { ncols title topbar } 127 inherit-global-pattern { charsize charfont color align botbar format } 128 129 ncols 0 130 title 0 131 topbar 0 132 133 vbar 0 134 135 inherit-defaults-column { span } 136 inherit-pattern-column { charsize charfont color align botbar format } 137 138 span 1 139 140 } 141 142 # 143 # Caract�res � ignorer en latex 144 # 145 146 variable latex_ignore 147 148 # 149 # Cha�ne de format pour utiliser CSS : classes � utiliser en 150 # fonction de la taille de la fonte. 151 # Si la cha�ne est vide, le format classique ("font size=") est utilis�. 152 # 153 154 variable css_size "tab-text%d" 155} 156 157 158############################################################################## 159# Activation du debug 160############################################################################## 161 162proc ::arrgen::debug {infos} { 163 set ::arrgen::debuginfos $infos 164} 165 166############################################################################## 167# Proc�dure principale du package 168############################################################################## 169 170# 171# Proc�dure principale 172# 173# Entr�e : 174# - param�tres : 175# - format : html/latex/csv 176# - style : le style proprement dit, ou le tableau d�j� analys� 177# - data : les donn�es 178# - variables globales : 179# - debuginfo : les informations de debug souhait�es 180# Sortie : 181# - valeur de retour : valeur convertie en tableau, ou message d'erreur 182# 183# Note : voir la sp�cification du style dans l'en-t�te du package 184# 185# Historique : 186# 2002/05/10 : pda : conception 187# 188 189proc ::arrgen::output {format style data} { 190 global errorInfo 191 192 if {[llength $style] == 1} then { 193 upvar $style tab 194 } else { 195 if {[::arrgen::parse tab $style msg] == -1} then { 196 puts stderr "Error: $msg" 197 return $msg 198 } 199 } 200 201 set rp [catch {::arrgen::output-format $format tab $data} m] 202 set savedinfo $errorInfo 203 204 if {[lsearch $::arrgen::debuginfos errors] != -1 && $rp != 0} then { 205 set m $savedinfo 206 } 207 return $m 208} 209 210proc ::arrgen::output-format {format tab data} { 211 upvar $tab t 212 213 # 214 # Caract�res � ignorer en format latex 215 # 216 set ::arrgen::latex_ignore "" 217 foreach {min max} {0 8 11 31 127 160} { 218 for {set i $min} {$i <= $max} {incr i} { 219 append ::arrgen::latex_ignore [format %c $i] 220 } 221 } 222 223 # 224 # Obtention du format de sortie 225 # 226 set kwd [::arrgen::get-kwd $format "format" \ 227 { {html html} {latex latex} {pdf latex} {csv csv} } ] 228 229 # 230 # G�n�ration et renvoi du r�sultat 231 # 232 return [::arrgen::output-$kwd t $data] 233} 234 235############################################################################## 236# Analyse syntaxique du style 237############################################################################## 238 239# 240# Analyse syntaxique du style 241# 242# Entr�e : 243# - param�tres : 244# - tab : tableau � remplir, contenant le style en retour 245# - style : le style proprement dit 246# - msg : message d'erreur en retour 247# Sortie : 248# - valeur de retour : 0 si tout s'est bien pass�, ou -1 en cas d'erreur 249# - param�tre tableau : le tableau rempli 250# - param�tre msg : le message d'erreur en cas d'erreur 251# 252# Note : voir la sp�cification du style dans l'en-t�te du package 253# 254# Historique : 255# 2002/05/10 : pda : conception 256# 257 258proc ::arrgen::parse {tab style msg} { 259 upvar $tab t 260 upvar $msg m 261 global ::arrgen::debuginfos 262 global errorInfo 263 264 catch {unset t} 265 set r 0 266 set rp [catch {::arrgen::parse-style t $style} m] 267 set savedinfo $errorInfo 268 269 if {[lsearch $::arrgen::debuginfos syntax] != -1} then { 270 foreach f [lsort [array names t]] { 271 puts stderr [format "| %-40s | %-30s |" $f $t($f)] 272 } 273 } 274 275 if {[lsearch $::arrgen::debuginfos errors] != -1 && $rp != 0} then { 276 set m $savedinfo 277 } 278 279 if {$rp != 0} then { 280 set r -1 281 } else { 282 set r 0 283 } 284 return $r 285} 286 287# 288# Proc�dures d'analyse des �l�ments du style 289# 290# Entr�e : 291# - param�tres : 292# - tab : tableau en cours de remplissage 293# - style : la partie du style � analyser 294# - msg : message d'erreur en retour 295# Sortie : 296# - valeur de retour : aucune 297# - erreur : s'il y a eu erreur 298# - param�tre tab : le tableau en cours de remplissage 299# 300# Historique : 301# 2002/05/10 : pda : conception 302# 303 304proc ::arrgen::parse-style {tab style} { 305 upvar $tab t 306 307 while {[llength $style] > 0} { 308 set kwd [lindex $style 0] 309 set arg [lindex $style 1] 310 set n 1 311 312 set kwd [::arrgen::get-kwd $kwd "top" \ 313 { 314 {global global} {global global} 315 {pattern pattern} {motif pattern} 316 } ] 317 318 switch -- $kwd { 319 global { 320 ::arrgen::parse-global t $arg 321 } 322 pattern { 323 ::arrgen::parse-pattern t [lindex $style 2] $arg 324 set n 2 325 } 326 } 327 set style [lreplace $style 0 $n] 328 } 329} 330 331######################################## 332# Global 333######################################## 334 335proc ::arrgen::parse-global {tab style} { 336 upvar $tab t 337 338 # 339 # Valeurs par d�faut 340 # 341 ::arrgen::inherit ::arrgen::defaults "" t "" \ 342 $::arrgen::defaults(inherit-defaults-global) 343 344 # 345 # Analyse de la liste 346 # 347 set ctxt "global" 348 349 while {[llength $style] > 0} { 350 set kwd [lindex $style 0] 351 set arg [lindex $style 1] 352 353 set kwd [::arrgen::get-kwd $kwd $ctxt \ 354 { 355 {chars chars} {caracteres chars} 356 {color color} {couleur color} 357 {align align} {alignement align} 358 {botbar botbar} {trait-horizontal botbar} 359 {format format} {donnees-formatees format} 360 {columns columns} {colonnes columns} 361 {csv csv} 362 {latex latex} 363 } ] 364 365 ::arrgen::parse-$kwd t $arg "" $ctxt 366 set style [lreplace $style 0 1] 367 } 368} 369 370# 371# Remplit : 372# (rien) 373# 374 375proc ::arrgen::parse-ignore {tab style idx ctxt} { 376} 377 378# 379# Remplit : 380# tab(charsize) : <taille des caract�res> 381# tab(charfont) : normal|bold|bold-italic|italic 382# ou : 383# tab(pattern-PPP-charsize) : <taille des caract�res> 384# tab(pattern-PPP-charfont) : normal|bold|bold-italic|italic 385# ou : 386# tab(pattern-PPP-col-CCC-charsize) : <taille des caract�res> 387# tab(pattern-PPP-col-CCC-charfont) : normal|bold|bold-italic|italic 388# 389 390proc ::arrgen::parse-chars {tab style idx ctxt} { 391 upvar $tab t 392 393 set x(normal) 0 394 set x(bold) 0 395 set x(italic) 0 396 397 foreach s $style { 398 set kwd [::arrgen::get-kwd $s $ctxt \ 399 { 400 {normal normal} {normal normal} 401 {bold bold} {gras bold} 402 {italic italic} {italique italic} 403 {[0-9]+ int} 404 } ] 405 406 if {[string equal $kwd int]} then { 407 set t(${idx}charsize) $s 408 } else { 409 set x($kwd) 1 410 } 411 } 412 413 switch -glob -- "$x(normal)$x(bold)$x(italic)" { 414 000 { } 415 001 { set t(${idx}charfont) "italic" } 416 010 { set t(${idx}charfont) "bold" } 417 011 { set t(${idx}charfont) "bold-italic" } 418 100 { set t(${idx}charfont) "normal" } 419 1* { 420 ::arrgen::invalid-keyword "combination normal/bold/italic" \ 421 "chars" {normal bold italic} 422 } 423 } 424} 425 426# 427# Remplit 428# tab(color) : <color> 429# ou : 430# tab(pattern-PPP-color) : <color> 431# ou : 432# tab(pattern-PPP-col-CCC-color) : <color> 433# 434 435proc ::arrgen::parse-color {tab style idx ctxt} { 436 upvar $tab t 437 438 set kwd [::arrgen::get-kwd $style $ctxt \ 439 { 440 {transparent transparent} 441 {[0-9A-Fa-f]+ hex} 442 } ] 443 444 switch -- $kwd { 445 transparent { 446 set t(${idx}color) $style 447 } 448 hex { 449 set t(${idx}color) [string toupper $style] 450 } 451 } 452} 453 454# 455# Remplit : 456# tab(align) <left/center/right/justify> 457# ou : 458# tab(pattern-PPP-align) <left/center/right/justify> 459# ou : 460# tab(pattern-PPP-col-CCC-align) <left/center/right/justify> 461# 462 463proc ::arrgen::parse-align {tab style idx ctxt} { 464 upvar $tab t 465 466 set t(${idx}align) [::arrgen::get-kwd $style "$ctxt, align" \ 467 { 468 {left left} {gauche left} 469 {center center} {centre center} 470 {right right} {droit right} 471 {justify justify} 472 } ] 473} 474 475# 476# Remplit : 477# tab(botbar) <0/1> 478# ou : 479# tab(pattern-PPP-botbar) <0/1> 480# ou : 481# tab(pattern-PPP-col-CCC-botbar) <0/1> 482# 483 484proc ::arrgen::parse-botbar {tab style idx ctxt} { 485 upvar $tab t 486 487 set t(${idx}botbar) [::arrgen::get-yesno $style "$ctxt, botbar"] 488} 489 490 491# 492# Remplit : 493# tab(ncols) : <nb de columns> 494# tab(col-CCC-width) : <largeur de la colonne CCC en %> 495# 496 497proc ::arrgen::parse-columns {tab style idx ctxt} { 498 upvar $tab t 499 500 set ncols 0 501 set total 0 502 foreach c $style { 503 incr ncols 504 set t(col-$ncols-width) [::arrgen::get-int $c "global, column $ncols size"] 505 incr total $c 506 } 507 508 set t(ncols) $ncols 509 510 # 511 # Ancienne version : test strict d'�galit� � 100 % 512 # 513 514# if {$total != 100} then { 515# error "Size of all $ncols columns is '$total', should be 100" 516# } 517 518 # 519 # Nouvelle version : on ram�ne � 100 % 520 # 521 522 if {$total != 100} then { 523 set ncols 0 524 set ntotal 0 525 foreach c $style { 526 incr ncols 527 set w $t(col-$ncols-width) 528 set nw [expr "round (100.0 * double($w) / $total)"] 529 set t(col-$ncols-width) $nw 530 incr ntotal $nw 531 } 532 if {$ntotal != 100} then { 533 incr t(col-$ncols-width) [expr 100-$ntotal] 534 } 535 } 536} 537 538######################################## 539# CSV specific parameters 540######################################## 541 542proc ::arrgen::parse-csv {tab style idx ctxt} { 543 upvar $tab t 544 545 while {[llength $style] > 0} { 546 set kwd [lindex $style 0] 547 set arg [lindex $style 1] 548 549 set kwd [::arrgen::get-kwd $kwd $ctxt \ 550 { 551 {separator csv-separator} 552 } ] 553 554 ::arrgen::parse-$kwd t $arg "" $ctxt 555 set style [lreplace $style 0 1] 556 } 557} 558 559# 560# Remplit : 561# tab(csv-separator) <char> 562# 563 564proc ::arrgen::parse-csv-separator {tab style idx ctxt} { 565 upvar $tab t 566 567 if {[string length $style] != 1} then { 568 error "CSV separator must be exactly one character" 569 } 570 571 set t(${idx}csv-separator) $style 572} 573 574######################################## 575# LaTeX specific parameters 576######################################## 577 578proc ::arrgen::parse-latex {tab style idx ctxt} { 579 upvar $tab t 580 581 while {[llength $style] > 0} { 582 set kwd [lindex $style 0] 583 set arg [lindex $style 1] 584 585 set kwd [::arrgen::get-kwd $kwd $ctxt \ 586 { 587 {linewidth latex-linewidth} 588 {bordersep latex-bordersep} 589 } ] 590 591 ::arrgen::parse-$kwd t $arg "" $ctxt 592 set style [lreplace $style 0 1] 593 } 594} 595 596# 597# Remplit : 598# tab(latex-linewidth) <float> 599# 600 601proc ::arrgen::parse-latex-linewidth {tab style idx ctxt} { 602 upvar $tab t 603 604 set t(${idx}latex-linewidth) [expr double($style)] 605} 606 607# 608# Remplit : 609# tab(latex-bordersep) <float> 610# 611 612proc ::arrgen::parse-latex-bordersep {tab style idx ctxt} { 613 upvar $tab t 614 615 set t(${idx}latex-bordersep) [expr double($style)] 616} 617 618######################################## 619# Pattern 620######################################## 621 622# 623# Remplit : 624# tab(patterns) ajoute le nom du motif 625# tab(pattern-PPP-ncols) <nb de colonnes du motif PPP> 626# tab(pattern-PPP-col-CCC-vbar) <0/1> 627# 628 629proc ::arrgen::parse-pattern {tab style name} { 630 upvar $tab t 631 632 if {! [regexp {^[-A-Za-z0-9]+$} $name]} then { 633 error "Invalid syntax for pattern '$name'" 634 } 635 636 lappend t(patterns) $name 637 set idx "pattern-$name-" 638 639 # 640 # Valeurs par d�faut du motif 641 # 642 643 if {! [info exists t(charsize)]} then { 644 error "Section 'global' not found" 645 } 646 647 ::arrgen::inherit ::arrgen::defaults "" t $idx \ 648 $::arrgen::defaults(inherit-defaults-pattern) 649 ::arrgen::inherit t "" t $idx \ 650 $::arrgen::defaults(inherit-global-pattern) 651 652 set t(${idx}col-0-vbar) $::arrgen::defaults(vbar) 653 654 # 655 # Analyse du motif 656 # 657 658 set ctxt "pattern '$name'" 659 660 while {[llength $style] > 0} { 661 set kwd [lindex $style 0] 662 set arg [lindex $style 1] 663 664 set kwd [::arrgen::get-kwd $kwd $ctxt \ 665 { 666 {chars chars} {caracteres chars} 667 {color color} {couleur color} 668 {align align} {alignement align} 669 {botbar botbar} {trait-horizontal botbar} 670 {format format} {donnees-formatees format} 671 {topbar topbar} {trait-dessus topbar} 672 {title title} 673 {vbar vbar} {trait-vertical vbar} 674 {column column} {colonne column} 675 676 {repetition ignore} 677 {afficher ignore} 678 } ] 679 680 ::arrgen::parse-$kwd t $arg $idx $ctxt 681 682 set style [lreplace $style 0 1] 683 } 684 685 set lastcol $t(${idx}ncols) 686 for {set c 0} {$c <= $lastcol} {incr c} { 687 if {! [info exists t(${idx}col-$c-vbar)]} then { 688 set t(${idx}col-$c-vbar) $::arrgen::defaults(vbar) 689 } 690 } 691 692 set ncol 0 693 for {set c 1} {$c <= $lastcol} {incr c} { 694 incr ncol $t(${idx}col-$c-span) 695 } 696 697 if {$ncol != $t(ncols)} then { 698 error "Invalid number of columns ($ncol) in pattern '$name'" 699 } 700} 701 702# 703# Remplit : 704# tab(pattern-PPP-topbar) <0/1> 705# 706 707proc ::arrgen::parse-topbar {tab style idx ctxt} { 708 upvar $tab t 709 710 set t(${idx}topbar) [::arrgen::get-yesno $style "$ctxt, topbar"] 711} 712 713 714# 715# Remplit : 716# tab(pattern-PPP-title) <0/1> 717# 718 719proc ::arrgen::parse-title {tab style idx ctxt} { 720 upvar $tab t 721 722 set t(${idx}title) [::arrgen::get-yesno [lindex $style 0] $ctxt] 723} 724 725# 726# Remplit : 727# tab(pattern-PPP-col-CCC-vbar) <0/1> 728# 729 730proc ::arrgen::parse-vbar {tab style idx ctxt} { 731 upvar $tab t 732 733 set colnum $t(${idx}ncols) 734 set t(${idx}col-$colnum-vbar) [::arrgen::get-yesno $style "$ctxt, vbar"] 735} 736 737######################################## 738# Column 739######################################## 740 741# 742# idx = pattern-PPP 743# 744# Remplit : 745# tab(pattern-PPP-ncols) <nb de colonnes du motif PPP> 746# 747 748proc ::arrgen::parse-column {tab style idx ctxt} { 749 upvar $tab t 750 751 incr t(${idx}ncols) 752 set colnum $t(${idx}ncols) 753 set colidx ${idx}col-$colnum- 754 755 append ctxt ", column $colnum" 756 757 # 758 # Valeurs par d�faut de la colonne 759 # 760 761 ::arrgen::inherit ::arrgen::defaults "" t $colidx \ 762 $::arrgen::defaults(inherit-defaults-column) 763 ::arrgen::inherit t $idx t $colidx \ 764 $::arrgen::defaults(inherit-pattern-column) 765 766 # 767 # Analyse des arguments 768 # 769 770 while {[llength $style] > 0} { 771 set kwd [lindex $style 0] 772 set arg [lindex $style 1] 773 774 set kwd [::arrgen::get-kwd $kwd $ctxt \ 775 { 776 {chars chars} {caracteres chars} 777 {color color} {couleur color} 778 {align align} {alignement align} 779 {botbar botbar} {trait-horizontal botbar} 780 {multicolumn multicolumn} {multi-colonnes multicolumn} 781 {multicolumns multicolumn} 782 {format format} {donnees-formatees format} 783 } ] 784 785 ::arrgen::parse-$kwd t $arg $colidx $ctxt 786 set style [lreplace $style 0 1] 787 } 788} 789 790# 791# Remplit : 792# tab(pattern-PPP-col-CCC-span) <int> 793# 794 795proc ::arrgen::parse-multicolumn {tab style idx ctxt} { 796 upvar $tab t 797 798 set t(${idx}span) [::arrgen::get-int $style "$ctxt, multicolumn"] 799} 800 801# 802# Remplit : 803# tab(pattern-PPP-col-CCC-format) <nom de proc�dure> 804# (avec deux proc�dures pr�cod�es : raw et cooked) 805# 806 807proc ::arrgen::parse-format {tab style idx ctxt} { 808 upvar $tab t 809 810 set kwd [::arrgen::get-kwd $style "$ctxt, align" \ 811 { 812 {cooked cooked} 813 {raw raw} 814 {lines lines} 815 {oui raw} {non cooked} 816 {[-a-zA-Z0-9]+ proc} 817 } ] 818 switch $kwd { 819 proc { set v [list proc $style] } 820 default { set v "::arrgen::output-$kwd" } 821 } 822 set t(${idx}format) $v 823} 824 825######################################## 826# Utilitaires 827######################################## 828 829proc ::arrgen::get-yesno {val ctxt} { 830 return [::arrgen::get-kwd $val $ctxt \ 831 { 832 {oui 1} {yes 1} {1 1} {non 0} {no 0} {0 0} 833 } ] 834} 835 836proc ::arrgen::get-kwd {val ctxt lval} { 837 set ak {} 838 foreach v $lval { 839 set re [lindex $v 0] 840 lappend ak $re 841 if {[regexp "^$re$" $val]} then { 842 return [lindex $v 1] 843 } 844 } 845 ::arrgen::invalid-keyword $val $ctxt $ak 846} 847 848proc ::arrgen::get-int {val ctxt} { 849 if {! [regexp {^[0-9]+} $val]} then { 850 error "Invalid integer '$val' in context '$ctxt'" 851 } 852 return $val 853} 854 855proc ::arrgen::invalid-keyword {kwd ctxt defval} { 856 set shouldbe "" 857 if {[llength $defval] > 0} then { 858 set defval [join $defval "|"] 859 set shouldbe " : should be $defval" 860 } 861 error "Invalid keyword '$kwd' in context '$ctxt'$shouldbe" 862} 863 864proc ::arrgen::inherit {tabtop topctxt tabcur curctxt fields} { 865 upvar $tabtop ttop 866 upvar $tabcur tcur 867 868 foreach f $fields { 869 if {[info exists ttop($topctxt$f)]} then { 870 set tcur($curctxt$f) $ttop($topctxt$f) 871 } else { 872 error "Internal : bad inherit field '$topctxt$f' -> '$curctxt$f'" 873 } 874 } 875} 876 877############################################################################## 878# Fonctions auxiliaires de g�n�ration 879############################################################################## 880 881# 882# Effectue quelques v�rifications �l�mentaires sur la ligne du tableau 883# 884# Entr�e : 885# - param�tres : 886# - tab : le tableau contenant le style 887# - lineno : num�ro de la ligne courante 888# - line : la ligne courante (y compris le motif) 889# Sortie : 890# - valeur de retour : - 891# 892# Historique : 893# 2002/05/10 : pda : conception 894# 895 896proc ::arrgen::check-pattern-nbcols {tab lineno line} { 897 upvar $tab t 898 899 set pattern [lindex $line 0] 900 901 if {[lsearch -exact $t(patterns) $pattern] == -1} then { 902 error "Line $lineno: pattern '$pattern' not found" 903 } 904 905 set ncols [expr [llength $line] - 1] 906 if {$ncols != $t(pattern-$pattern-ncols)} then { 907 error "Line $lineno: invalid nb of columns ($ncols) for pattern '$pattern'" 908 } 909} 910 911# 912# Indique s'il faut une bordure au tableau 913# 914# Entr�e : 915# - param�tres : 916# - tab : tableau contenant le style 917# Sortie : 918# - valeur de retour : 0 ou 1 919# 920# Note : HTML ne disposant pas de moyen pour d�finir la bordure de chaque 921# case, on d�finit, par convention, que s'il y a au moins un trait 922# ext�rieur vertical (trait avant la case la plus � gauche, ou apr�s la 923# case la plus � droite), on met une bordure. 924# 925# Historique : 926# 2002/05/11 : pda : conception 927# 2002/05/14 : pda : conception 928# 929 930proc ::arrgen::any-vbar {tab} { 931 upvar $tab t 932 933 set r 0 934 foreach p $t(patterns) { 935 set idx "pattern-$p-" 936 set ncols $t(${idx}ncols) 937 if {$t(${idx}col-0-vbar) || $t(${idx}col-$ncols-vbar)} then { 938 set r 1 939 break 940 } 941 } 942 return $r 943} 944 945############################################################################## 946# G�n�ration csv 947############################################################################## 948 949# 950# G�n�ration du tableau en format CSV 951# 952# Entr�e : 953# - param�tres : 954# - tab : tableau contenant le style 955# - data : les donn�es 956# Sortie : 957# - valeur de retour : valeur convertie en tableau 958# 959# Historique : 960# 2002/05/10 : pda : conception 961# 962 963proc ::arrgen::output-csv {tab data} { 964 upvar $tab t 965 966 set lineno 0 967 set csv "" 968 foreach line $data { 969 incr lineno 970 ::arrgen::check-pattern-nbcols t $lineno $line 971 set idx "pattern-[lindex $line 0]-" 972 append csv [::arrgen::output-csv-line t $idx [lreplace $line 0 0]] 973 } 974 return $csv 975} 976 977# 978# G�n�ration d'une ligne CSV du tableau 979# 980# Entr�e : 981# - param�tres : 982# - tab : tableau contenant le style 983# - idx : index du motif dans le tableau tab 984# - line : la ligne compos�e d'une liste des colonnes 985# Sortie : 986# - valeur de retour : ligne convertie en ligne de tableau 987# 988# Historique : 989# 2002/05/10 : pda : conception 990# 991 992proc ::arrgen::output-csv-line {tab idx line} { 993 upvar $tab t 994 995 set csvlist {} 996 set icol 0 997 foreach val $line { 998 incr icol 999 1000 set needquote 0 1001 if {[regsub -all {"} $val {""} csvval] > 0} then { 1002 set needquote 1 1003 } 1004 if {[regexp $t(csv-separator) $csvval]} then { 1005 set needquote 1 1006 } 1007 if {[regexp {[\n\r]} $csvval]} then { 1008 set needquote 1 1009 } 1010 if {$needquote} then { 1011 set csvval "\"$csvval\"" 1012 } 1013 1014 lappend csvlist $csvval 1015 1016 for {set i 2} {$i < $t(${idx}col-$icol-span)} {incr i} { 1017 lappend csvlist {} 1018 } 1019 } 1020 append csv "[join $csvlist $t(csv-separator)]\n" 1021} 1022 1023############################################################################## 1024# G�n�ration html 1025############################################################################## 1026 1027# 1028# G�n�ration du tableau en format HTML 1029# 1030# Entr�e : 1031# - param�tres : 1032# - tab : tableau contenant le style 1033# - data : les donn�es 1034# Sortie : 1035# - valeur de retour : valeur convertie en tableau 1036# 1037# Historique : 1038# 2002/05/10 : pda : conception 1039# 1040 1041proc ::arrgen::output-html {tab data} { 1042 upvar $tab t 1043 1044 if {[::arrgen::any-vbar t]} then { 1045 set border " BORDER=2 CELLPADDING=5 CELLSPACING=1" 1046 } else { 1047 set border "" 1048 } 1049 set html "<table width=\"100%\"$border>\n" 1050 1051 set lineno 0 1052 foreach line $data { 1053 incr lineno 1054 ::arrgen::check-pattern-nbcols t $lineno $line 1055 set idx "pattern-[lindex $line 0]-" 1056 append html [::arrgen::output-html-line t $idx [lreplace $line 0 0]] 1057 } 1058 1059 append html "</table>\n" 1060 1061 return $html 1062} 1063 1064# 1065# G�n�ration d'une ligne HTML du tableau 1066# 1067# Entr�e : 1068# - param�tres : 1069# - tab : tableau contenant le style 1070# - idx : index du motif dans le tableau tab 1071# - line : la ligne compos�e d'une liste des colonnes 1072# Sortie : 1073# - valeur de retour : ligne convertie en ligne de tableau 1074# 1075# Historique : 1076# 2002/05/10 : pda : conception 1077# 2002/05/18 : pda : ajout du param�tre align -> jusitfy 1078# 1079 1080proc ::arrgen::output-html-line {tab idx line} { 1081 upvar $tab t 1082 1083 set html "" 1084 set icol 0 1085 set realcol 0 1086 foreach val $line { 1087 incr icol 1088 incr realcol 1089 1090 set colidx "${idx}col-$icol-" 1091 1092 # Alignement et justification 1093 switch $t(${colidx}align) { 1094 left { set align " align=left" } 1095 center { set align " align=center" } 1096 right { set align " align=right" } 1097 justify { set align "" } 1098 } 1099 1100 # Multi-colonnes 1101 set span $t(${colidx}span) 1102 set width $t(col-$realcol-width) 1103 for {set i 1} {$i < $span} {incr i} { 1104 incr realcol 1105 incr width $t(col-$realcol-width) 1106 } 1107 if {$span > 1} then { 1108 set colspan " colspan=\"$span\"" 1109 } else { 1110 set colspan "" 1111 } 1112 1113 # Largeur 1114 set width " width=\"$width%\"" 1115 1116 # Couleur 1117 if {[string equal $t(${colidx}color) "transparent"]} then { 1118 set color "" 1119 } else { 1120 set color " bgcolor=\"#$t(${colidx}color)\"" 1121 } 1122 1123 # taille 1124 set class "" 1125 if {! [string equal $::arrgen::css_size ""]} then { 1126 set css [format $::arrgen::css_size $t(${colidx}charsize)] 1127 set class [format " class=\"$css\""] 1128 } 1129 1130 1131 # D�but de la colonne 1132 append html "<td$width$colspan$align$color$class>" 1133 1134 set font [::arrgen::html-font $t(${colidx}charsize) $t(${colidx}charfont)] 1135 append html "[lindex $font 0]\n" 1136 1137 if {[string length [string trim $val]] == 0} then { 1138 set val " " 1139 } else { 1140 set fmt $t(${colidx}format) 1141 set val [$fmt html $t(${colidx}align) $val] 1142 } 1143 1144 append html "$val\n" 1145 1146 # Fin de la colonne 1147 append html "[lindex $font 1]\n" 1148 append html "</td>\n" 1149 } 1150 return "<tr>\n$html</tr>\n" 1151} 1152 1153# 1154# Correspondance entre les sp�cifications de police et le code html 1155# 1156# Entr�e : 1157# - param�tres : 1158# - size : taille de police telle qu'elle figure dans le style 1159# - font : police telle qu'elle figure dans le style 1160# Sortie : 1161# - valeur de retour : liste � deux �l�ments {a b} o� "a" est le 1162# code � ins�rer avant le texte, et "b" le code � ins�rer apr�s. 1163# 1164# Historique : 1165# 2002/05/10 : pda : conception 1166# 2006/12/06 : pda : support css 1167# 1168 1169proc ::arrgen::html-font {size font} { 1170 # 1171 # Taille de la fonte 1172 # 1173 1174 if {[string equal $::arrgen::css_size ""]} then { 1175 if {$size <= 8} then { 1176 set s "1" 1177 } elseif {$size <= 10} then { 1178 set s "2" 1179 } elseif {$size <= 12} then { 1180 set s "3" 1181 } elseif {$size <= 14} then { 1182 set s "4" 1183 } elseif {$size <= 16} then { 1184 set s "5" 1185 } elseif {$size <= 18} then { 1186 set s "6" 1187 } elseif {$size <= 20} then { 1188 set s "7" 1189 } elseif {$size <= 22} then { 1190 set s "8" 1191 } else { 1192 set s "9" 1193 } 1194 set size1 "<font size=\"$s\">" 1195 set size2 "</font>" 1196 } else { 1197 set size1 "" 1198 set size2 "" 1199 } 1200 1201 # 1202 # Style 1203 # 1204 1205 switch $font { 1206 normal { set style1 "" ; set style2 "" } 1207 bold { set style1 "<b>" ; set style2 "</b>" } 1208 italic { set style1 "<i>" ; set style2 "</i>" } 1209 bold-italic { set style1 "<b><i>" ; set style2 "</i></b>" } 1210 } 1211 1212 return [list "$size1$style1" "$style2$size2"] 1213} 1214 1215############################################################################## 1216# G�n�ration latex 1217############################################################################## 1218 1219# 1220# G�n�ration du tableau en format LATEX 1221# 1222# Entr�e : 1223# - param�tres : 1224# - tab : tableau contenant le style 1225# - data : les donn�es 1226# Sortie : 1227# - valeur de retour : valeur convertie en tableau 1228# 1229# Historique : 1230# 2002/05/10 : pda : conception 1231# 1232 1233proc ::arrgen::output-latex {tab data} { 1234 upvar $tab t 1235 1236 ::arrgen::latex-colwidth t 1237 ::arrgen::latex-botbar t 1238 1239 set latex "" 1240 1241 # 1242 # Faut-il des bordures horizontales en haut et en bas de 1243 # chaque page du tableau ? 1244 # 1245 1246 set title "" 1247 if {[::arrgen::any-vbar t]} then { 1248 append latex "\\tabletail \{\\hline\}\n" 1249 append latex "\\tablehead \{\\hline\}\n" 1250 } else { 1251 append latex "\\tabletail \{\}\n" 1252 append latex "\\tablehead \{\}\n" 1253 } 1254 append latex "\\tablefirsthead \{\}\n" 1255 append latex "\\tablelasttail \{\}\n" 1256 1257 # 1258 # Pr�paration de l'en-t�te, qu'on ne sortira qu'� la premi�re 1259 # ligne affichable. 1260 # 1261 set cols [string repeat "c" $t(ncols)] 1262 set header "\\begin \{supertabular\} \{$cols\}\n" 1263 set headerprinted 0 1264 1265 set lineno 0 1266 set nlines [llength $data] 1267 foreach line $data { 1268 incr lineno 1269 ::arrgen::check-pattern-nbcols t $lineno $line 1270 set idx "pattern-[lindex $line 0]-" 1271 1272 set l [::arrgen::output-latex-line t $idx [lreplace $line 0 0]] 1273 1274 # 1275 # Est-ce que cette ligne est une ligne sp�ciale (i.e. � r�p�ter) ? 1276 # 1277 1278 if {$t(${idx}title)} then { 1279 append title $l 1280 append latex "\\tablefirsthead \{$title\}" 1281 append latex "\\tablehead \{$title\}" 1282 } else { 1283 if {! $headerprinted} then { 1284 append latex $header 1285 set headerprinted 1 1286 } 1287 append latex $l 1288 } 1289 } 1290 1291 if {$headerprinted} then { 1292 append latex "\\end \{supertabular\}\n" 1293 } 1294 1295 return $latex 1296} 1297 1298# 1299# Calcul des tailles de toutes les colonnes possibles du tableau. 1300# 1301# Entr�e : 1302# - param�tres : 1303# - tab : tableau contenant le style 1304# Sortie : 1305# - valeur de retour : - 1306# - param�tre tab : 1307# t(pattern-PPP-col-CCC-latexwidth) : taille � mettre avec \linewidth 1308# 1309# Note : 1310# Le texte dans une cellule de tableau latex est bord� par 1311# un petit espace E de part et d'autre. Cet espace E = 2,3 mm. 1312# 1313# 60 % 40 % 1314# | <------------------------------> | <--------------------> | 1315# | | | 1316# | E T1 E E T2 E | 1317# | <--> <--------------------> <--> | <--> <----------> <--> | 1318# | | 1319# | E T12 (multicolonne sur 1 et 2) E | 1320# | <--> <---------------------------------------------> <--> | 1321# 1322# Toutes les dimensions doivent �tre proportionnelles � 1323# \linewidth. Seul E (2,3 mm) ne peut �tre d�riv� de \linewidth 1324# exactement. C'est pour cela qu'on prend une approximation : 1325# si \linewidth = 175 mm, E = I \linewidth, avec I = 2.3/175 1326# 1327# Donc, la largeur du texte T dans une colonne C est calcul�e 1328# empiriquement � partir de : 1329# - L = largeur de toutes les colonnes constituant C 1330# (notamment en cas de multicolonnage) 1331# Exemple L1 = 60%, L2 = 40%, L12 = 100% 1332# - B = largeur de la bordure = 2 I 1333# d'o� T = (L/100 - B) * \linewidth 1334# 1335# Historique : 1336# 2002/05/12 : pda : conception 1337# 2002/05/18 : pda : ajout du param�tre align -> jusitfy 1338# 1339 1340proc ::arrgen::latex-colwidth {tab} { 1341 upvar $tab t 1342 1343 set B [expr 2 * ($t(latex-bordersep) / $t(latex-linewidth))] 1344 1345 foreach p $t(patterns) { 1346 set ncols $t(pattern-$p-ncols) 1347 set realcol 1 1348 set mcol 1 1349 for {set mcol 1} {$mcol <= $ncols} {incr mcol} { 1350 set span $t(pattern-$p-col-$mcol-span) 1351 set L 0 1352 for {set i 0} {$i < $span} {incr i} { 1353 incr L $t(col-$realcol-width) 1354 incr realcol 1355 } 1356 set t(pattern-$p-col-$mcol-latexwidth) [expr ($L / 100.0) - $B] 1357 } 1358 } 1359} 1360 1361# 1362# Calcul de tous les traits en dessous des colonnes 1363# 1364# Entr�e : 1365# - param�tres : 1366# - tab : tableau contenant le style 1367# Sortie : 1368# - valeur de retour : - 1369# - param�tre tab : 1370# t(pattern-PPP-latexbotbar) : {{min max} {max max} ...} 1371# avec min et max les param�tres pour \cline 1372# et min = -1 si \hline 1373# 1374# Historique : 1375# 2002/05/12 : pda : conception 1376# 2002/05/25 : pda : correction d'un bug si max = realcol - 1 1377# 1378 1379proc ::arrgen::latex-botbar {tab} { 1380 upvar $tab t 1381 1382 foreach p $t(patterns) { 1383 set botidx pattern-$p-latexbotbar 1384 set t($botidx) {} 1385 1386 set begin -1 1387 set realcol 1 1388 set ncols $t(pattern-$p-ncols) 1389 1390 for {set mcol 1} {$mcol <= $ncols} {incr mcol} { 1391 set lastrealcol [expr $realcol - 1] 1392 1393 if {$t(pattern-$p-col-$mcol-botbar)} then { 1394 # une barre en dessous de la colonne 1395 if {$begin <= 0} then { 1396 # d�but d'un cline 1397 set begin $realcol 1398 } 1399 } else { 1400 # pas de barre en dessous de la colonne 1401 if {$begin > 0} then { 1402 lappend t($botidx) [list $begin $lastrealcol] 1403 set begin -1 1404 } 1405 } 1406 incr realcol $t(pattern-$p-col-$mcol-span) 1407 } 1408 1409 if {$begin == 1} then { 1410 lappend t($botidx) {-1 -1} 1411 } elseif {$begin > 1} then { 1412 lappend t($botidx) [list $begin [expr $realcol - 1]] 1413 } 1414 } 1415} 1416 1417# 1418# G�n�ration d'une ligne LATEX du tableau 1419# 1420# Entr�e : 1421# - param�tres : 1422# - tab : tableau contenant le style 1423# - idx : index du motif dans le tableau tab 1424# - line : la ligne compos�e d'une liste des colonnes 1425# Sortie : 1426# - valeur de retour : ligne convertie en ligne de tableau 1427# 1428# Historique : 1429# 2002/05/10 : pda : conception 1430# 1431 1432proc ::arrgen::output-latex-line {tab idx line} { 1433 upvar $tab t 1434 1435 set latex "" 1436 1437 # 1438 # Le trait au dessus n'est en principe que pour la premi�re 1439 # ligne, ou alors pour la premi�re ligne qui suivrait d'autres 1440 # lignes sans trait dessous. 1441 # 1442 if {$t(${idx}topbar)} then { 1443 append latex "\\hline\n" 1444 } 1445 1446 # 1447 # Parcours des cellules de la ligne 1448 # 1449 1450 set icol 0 1451 foreach val $line { 1452 set prevcol $icol 1453 incr icol 1454 set colidx "${idx}col-$icol-" 1455 1456 # 1457 # S�parateur de colonnes 1458 # 1459 if {$icol > 1} then { 1460 append latex " & " 1461 } 1462 1463 # 1464 # Alignement de la cellule 1465 # 1466 set align $t(${colidx}align) 1467 switch $align { 1468 left { set aligncmd "\\raggedright " } 1469 center { set aligncmd "\\centering " } 1470 right { set aligncmd "\\raggedleft " } 1471 justify { set aligncmd "" } 1472 } 1473 1474 # 1475 # Traits verticaux de chaque cot� de la cellule 1476 # 1477 set colbefore "" 1478 if {$t(${idx}col-$prevcol-vbar)} then { 1479 set colbefore "|" 1480 } 1481 set colafter "" 1482 if {$t(${idx}col-$icol-vbar)} then { 1483 set colafter "|" 1484 } 1485 1486 # 1487 # D�but de la colonne 1488 # 1489 set width $t(${colidx}latexwidth) 1490 set span $t(${colidx}span) 1491 append latex "\\multicolumn \{$span\}" 1492 append latex " \{${colbefore}p\{$width\\linewidth\}${colafter}\}" 1493 append latex " \{" 1494 1495 # 1496 # Police 1497 # 1498 set font [::arrgen::latex-font $t(${colidx}charsize) $t(${colidx}charfont)] 1499 append latex [lindex $font 0] 1500 append latex $aligncmd 1501 1502 # 1503 # Le texte 1504 # 1505 set fmt $t(${colidx}format) 1506 append latex [$fmt latex $align $val] 1507 1508 # 1509 # Fin de la colonne 1510 # 1511 append latex [lindex $font 1] 1512 append latex "\}\n" 1513 } 1514 1515 # 1516 # Fin de la ligne 1517 # 1518 1519 append latex "\\tabularnewline" 1520 1521 # 1522 # Recherche des traits horizontaux � mettre : 1523 # - soit une s�rie de cline 1524 # - soit un seul hline 1525 # 1526 1527 foreach botbar $t(${idx}latexbotbar) { 1528 set first [lindex $botbar 0] 1529 set last [lindex $botbar 1] 1530 1531 if {$first == -1} then { 1532 append latex " \\hline" 1533 } else { 1534 append latex " \\cline \{$first-$last\}" 1535 } 1536 } 1537 1538 return "$latex\n" 1539} 1540 1541# 1542# Correspondance entre les sp�cifications de police et le code latex 1543# 1544# Entr�e : 1545# - param�tres : 1546# - size : taille de police telle qu'elle figure dans le style 1547# - font : police telle qu'elle figure dans le style 1548# Sortie : 1549# - valeur de retour : liste � deux �l�ments {a b} o� "a" est le 1550# code � ins�rer avant le texte, et "b" le code � ins�rer apr�s. 1551# 1552# Historique : 1553# 2002/05/10 : pda : conception 1554# 1555 1556proc ::arrgen::latex-font {size font} { 1557 # 1558 # Taille de la fonte 1559 # 1560 1561 if {$size <= 8} then { 1562 set s "\\scriptsize" 1563 } elseif {$size <= 10} then { 1564 set s "\\footnotesize" 1565 } elseif {$size <= 12} then { 1566 set s "\\normalsize" 1567 } elseif {$size <= 14} then { 1568 set s "\\large" 1569 } elseif {$size <= 16} then { 1570 set s "\\Large" 1571 } elseif {$size <= 20} then { 1572 set s "\\LARGE" 1573 } else { 1574 set s "\\huge" 1575 } 1576 1577 # 1578 # Style. On n'a pas vraiment besoin de style2, mais on 1579 # laisse par souci d'homog�n��t� avec la version html. 1580 # 1581 1582 set it "\\itshape" 1583 set bf "\\bfseries" 1584 switch $font { 1585 normal { set style1 "" ; set style2 "" } 1586 bold { set style1 "$bf " ; set style2 "" } 1587 italic { set style1 "$it " ; set style2 "" } 1588 bold-italic { set style1 "$bf$it " ; set style2 "" } 1589 } 1590 1591 return [list "$s $style1" "$style2"] 1592} 1593 1594# 1595# D�barasse un texte de tous les caract�res sp�ciaux de latex 1596# 1597# Entr�e : 1598# - param�tres : 1599# - s : cha�ne � traiter 1600# - variable globale ::arrgen::latex_ignore 1601# suite de caract�res � ignorer 1602# Sortie : 1603# - valeur de retour : la cha�ne trait�e 1604# 1605# Historique : 1606# 2002/05/11 : pda : conception 1607# 1608 1609proc ::arrgen::latex-string {s} { 1610 1611 set patterns { 1612 \\\\ SENTINELLE1 1613 1614 [_&%#\{\}] \\\\& 1615 \\~ {\\~\ } 1616 \\^ {\\^\ } 1617 \\$ \\\\$ 1618 [��] $^\\circ$ 1619 � << 1620 � >> 1621 � \\EUR\{\} 1622 \\?` {? `} 1623 !` {! `} 1624 1625 SENTINELLE1 $\\backslash$ 1626 } 1627 regsub -all -- SENTINELLE1 $patterns [format %c 1] patterns 1628 1629 foreach {re sub} $patterns { 1630 regsub -all -- $re $s $sub s 1631 } 1632 1633 regsub -all -- "\[$::arrgen::latex_ignore\]" $s "" s 1634 1635 return $s 1636} 1637 1638 1639############################################################################## 1640# Proc�dures de formattage sp�cialis�es 1641############################################################################## 1642 1643# 1644# Proc�dure de formattage pour le format "raw" : aucune transformation. 1645# Utilis�e pour mettre dans un tableau des URL ou du code sp�cifique. 1646# 1647# Entr�e : 1648# - param�tres : 1649# - format : l'un des formats de sortie (csv, html, latex) 1650# - align : l'un des alignements (left, center, right, justify) 1651# - val : la case de tableau � formatter 1652# Sortie : 1653# - valeur de retour : la case de tableau convertie au format 1654# 1655# Historique : 1656# 2002/05/10 : pda : conception 1657# 2002/05/18 : pda : ajout du param�tre align 1658# 1659 1660proc ::arrgen::output-raw {format align val} { 1661 return $val 1662} 1663 1664# 1665# Proc�dure de formattage pour le format "cooked" : tous les 1666# caract�res sp�ciaux sont substitu�s le cas �ch�ant. 1667# Utilis�e pour mettre dans un tableau du texte qui doit �tre 1668# formatt� en un seul paragraphe. 1669# 1670# Entr�e : 1671# - param�tres : 1672# - format : l'un des formats de sortie (csv, html, latex) 1673# - align : l'un des alignements (left, center, right, justify) 1674# - val : la case de tableau � formatter 1675# Sortie : 1676# - valeur de retour : la case de tableau convertie au format 1677# 1678# Historique : 1679# 2002/05/10 : pda : conception 1680# 2002/05/18 : pda : ajout du param�tre align 1681# 1682 1683proc ::arrgen::output-cooked {format align val} { 1684 switch $format { 1685 csv { } 1686 html { 1687 set val [::webapp::html-string $val] 1688 } 1689 latex { 1690 set val [::arrgen::latex-string $val] 1691 } 1692 } 1693 return $val 1694} 1695 1696# 1697# Proc�dure de formattage pour le format "lines" : tous les 1698# caract�res sp�ciaux sont substitu�s le cas �ch�ant, et les 1699# sauts de ligne et de paragraphe sont pr�serv�s. 1700# 1701# Entr�e : 1702# - param�tres : 1703# - format : l'un des formats de sortie (csv, html, latex) 1704# - align : l'un des alignements (left, center, right, justify) 1705# - val : la case de tableau � formatter 1706# Sortie : 1707# - valeur de retour : la case de tableau convertie au format 1708# 1709# Historique : 1710# 2002/05/10 : pda : conception 1711# 2002/05/18 : pda : ajout du param�tre align 1712# 1713 1714proc ::arrgen::output-lines {format align val} { 1715 switch $format { 1716 csv { } 1717 html { 1718 set val [::webapp::html-string $val] 1719 regsub -all -- "\n\n+" $val "<p>" val 1720 if {! [string equal $align "justify"]} then { 1721 regsub -all -- "\n" $val "<br>" val 1722 } 1723 } 1724 latex { 1725 set val [::arrgen::latex-string $val] 1726 regsub -all -- "^(\[ \]*\n)+" $val {} val 1727 regsub -all -- "\n(\[ \]*\n)+" $val {\\par } val 1728 regsub -all -- "\n" $val "\\\\\\\\ \{\}\n" val 1729 } 1730 } 1731 return $val 1732} 1733