diff --git a/Makefile.in b/Makefile.in index c98c445..d82a0f3 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,25 +1,46 @@ SRC ?= haskelltut +# Let's allow different implementations to be tested. +BINPIC ?= pic +BINREFER ?= refer +BINSOELIM ?= soelim +BINPRECONV ?= preconv +BINEQN ?= eqn +BINGHIGHLIGHT ?= ./bin/ghighlight +BINBUSGRAP ?= ./bin/busgrap.pl +BINGRAP ?= grap +BINROFF ?= groff +export BINPIC BINREFER BINSOELIM BINPRECONV BINEQN BINGHIGHLIGHT BINBUSGRAP BINGRAP BINROFF + ODIR ?= . BIBLIOGRAPHY ?= bibliography +BIBLIOGRAPHY_PROCESSED ?= /tmp/bib ALLSRC = $(shell find . -name "*.ms") SOELIM_OPTS ?= -SOELIM = soelim $(SOELIM_OPTS) +SOELIM = $(BINSOELIM) $(SOELIM_OPTS) + +# Custom script, currently to replace unbreakable spaces by \SP. +CUSTOM_OPTS ?= +CUSTOM ?= ./bin/custom $(CUSTOM_OPTS) + +#CUSTOM_BIS_OPTS ?= +#CUSTOM_BIS ?= ./bin/utf8-to-ms.sh $(CUSTOM_BIS_OPTS) PRECONV_OPTS ?= -e utf-8 -PRECONV = preconv $(PRECONV_OPTS) +PRECONV = $(BINPRECONV) $(PRECONV_OPTS) EQN_OPTS ?= -Tpdf -EQN = eqn $(EQN_OPTS) +EQN = $(BINEQN) $(EQN_OPTS) # source-highlight stuff # GH_INTRO: instructions before each source code provided by source-highlight # GH_OUTRO: ------------ after ---- ------ ---- -------- -- ---------------- # GH_INTRO/GH_OUTRO: values are separated by ';' # -GH_INTRO := .b1;.nr DI 0;.DS I;.fam C +CODE_FONT_FAMILY ?= C +GH_INTRO := .b1;.nr DI 0;.DS I;.fam $(CODE_FONT_FAMILY) GH_OUTRO := .fam;.DE;.b2 # export GH_INTRO @@ -31,20 +52,24 @@ export SHOPTS # ghighlight brings `source-highlight` to troff GHIGHLIGHT_OPTS ?= -GHIGHLIGHT = ./bin/ghighlight $(GHIGHLIGHT_OPTS) +GHIGHLIGHT = $(BINGHIGHLIGHT) $(GHIGHLIGHT_OPTS) + +# BUSGRAP brings pie charts to troff +BUSGRAP_OPTS ?= +BUSGRAP = $(BINBUSGRAP) $(BUSGRAP_OPTS) GRAP_OPTS ?= -GRAP = grap $(GRAP_OPTS) +GRAP = $(BINGRAP) $(GRAP_OPTS) PIC_OPTS ?= -Tpdf -PIC = pic $(PIC_OPTS) +PIC = $(BINPIC) $(PIC_OPTS) # -P => move ponctuation after reference # -S => label and bracket-label options # -e => accumulate (use a reference section) # -p bib => bibliography file -REFER_OPTS ?= -PS -e -p $(BIBLIOGRAPHY) -REFER = refer $(REFER_OPTS) +REFER_OPTS ?= -PS -e -p $(BIBLIOGRAPHY_PROCESSED) +REFER = $(BINREFER) $(REFER_OPTS) # -k => iconv conversion (did it ever worked?) # -ms => ms macro @@ -58,20 +83,29 @@ REFER = refer $(REFER_OPTS) # TODO: no change with or without the following options -P -e # This has to be inverstigated: how to make PDFs look nice in browsers? # -P -e => provide "-e" to gropdf to embed fonts -GROFF_OPTS ?= -ms -t -Tpdf -U -mspdf -mpdfmark -M ./bin -P -e -GROFF = groff $(GROFF_OPTS) +ROFF_OPTS ?= -ms -t -Tpdf -U -mspdf -mpdfmark -M ./bin -P -e +ROFF = $(BINROFF) $(ROFF_OPTS) -$(SRC).pdf: +$(BIBLIOGRAPHY_PROCESSED): $(BIBLIOGRAPHY) + @# Let's process the bibliography file + @echo "Let's process the bibliography file" + $(PRECONV) < $(BIBLIOGRAPHY) > $(BIBLIOGRAPHY_PROCESSED) + +$(SRC).pdf: $(BIBLIOGRAPHY_PROCESSED) + sleep 0.1 $(SOELIM) < $(SRC).ms |\ + $(CUSTOM) |\ + $(BUSGRAP) |\ $(PRECONV) |\ + $(REFER) |\ $(EQN) |\ $(GHIGHLIGHT) |\ $(GRAP) |\ $(PIC) |\ - $(REFER) |\ - $(GROFF) > $(ODIR)/$@ + $(PRECONV) |\ + $(ROFF) > $(ODIR)/$@ # Keep options in memory for the recursive 'make' call export SOELIM_OPTS PRECONV_OPTS EQN_OPTS GHIGHLIGHT_OPTS GRAP_OPTS PIC_OPTS REFER_OPTS serve: - find . -name "*.ms" | entr gmake -B $(SRC).pdf + find . | entr gmake $(SRC).pdf diff --git a/bin/busgrap.pl b/bin/busgrap.pl new file mode 100755 index 0000000..ae250b5 --- /dev/null +++ b/bin/busgrap.pl @@ -0,0 +1,2684 @@ +#!/usr/bin/perl -w +# +# busgraph.pl : Produce Business Graphs in troff format +# Deri James : 5th February 2015 +# + +# Copyright (C) 2015 Free Software Foundation, Inc. +# Written by Deri James +# +# This file is part of groff. +# +# groff is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# groff is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +use strict; + + +my @CMDS=( + ['FRAME','c','pi/graph',"6c\t5c"], + ['ORIGIN','c','pi/graph',''], + ['DARKER','','pi/graph',.8], + ['BORDER','p','pi/graph',0], + ['BRDCOLOUR','#','pi/graph','black'], + ['JUST','','pi/graph','left'], + ['FT','p','pi/graph','HR'], + ['PS','p','pi/graph','10'], + ['VS','p','pi/graph','+10%'], + ['TEXTCOLOUR','#','pi/graph','black'], + ['BGCOLOUR','#','pi/graph',''], + ['WALLCOLOUR','#','graph',''], + ['LINECOLOUR','#','pi/graph','black'], + ['THICKNESS','p','pi/graph','.2'], + ['TYPE','','pi','pi'], + ['3D','c','pi','0'], + ['COLOURED','bool','pi/graph','no'], + ['XRAD','c','pi','2c'], + ['YRAD','c','pi','2c'], + ['HOLE','','pi','0'], + ['OTHERS','','pi',2.05], + ['VDECIMALS','','pi',0], + ['PDECIMALS','','pi',1], + ['PDECIMALS','','graph',''], + ['LABEL','','pi','$text ($percent%)'], + ['KEYBOX','bool','pi/graph','no'], + ['BOXFRAME','c','pi/graph',''], # xoffs, yoffs, width, depth + ['BOXHEADS','','pi',"Name\tValue\t%"], + ['BOXHEADS','','graph',''], + ['BOXLABELS','','pi/graph',"\$text\t\$value\t\$percent"], + ['BOXTABS','','pi/graph',"0cL 2.8cR 4cR"], + ['FLOW','bool','pi/graph','no'], + ['CAPTION','','pi/graph',''], + ['SCOLOURS','#','pi/graph',"#bfad94\t#2a586f\t#dbd6ce\t#568da3\t#a17759\t#c1d4de\t#74c9aa\t#dee1b6\t#e1b866\t#bf5434\t#373c42\tgrey80"], + # SCOLOURS:#bfad94 #2a586f #dbd6ce #568da3 #a17759 #c1d4de #74c9aa #dee1b6 #e1b866 #bf5434 #373c42 grey80 + # ['SCOLOURS','#','pi/graph',"cyan\tmagenta\tyellow\tpaleturquoise1\tgrey6\tgreen\tpeachpuff\tcornflowerblue\tpink2\tdarkgoldenrod\tdarkolivegreen1\tdarkturquoise"], + ['NEGCOLOUR','#','graph',''], + ['POSCOLOUR','#','graph',''], + ['HGRID','bool','graph','no'], + ['VGRID','bool','graph','no'], + ['SERIES','undef','pi/graph',''], + ['SYMSIZE','p','graph',2], + ['FLOOR','undef','graph',''], + ['HORIZONTAL','bool','graph','no'], + ['SYNC','bool','graph','no'], + ['SORT','bool','pi','n'], + ['SHADOW','bool','pi','no'], + ['SFILE','','pi/graph',''], + ['STEPS','undef','graph',''], + ['PDFBOOKMARK','','pi/graph',0], +); + +my %colours=( + 'black' => 'rgb #000000', + 'grey' => 'rgb #bebebe', + 'dimgrey' => 'rgb #696969', + 'lightgray' => 'rgb #d3d3d3', + 'lightslategrey' => 'rgb #778899', + 'slategray' => 'rgb #708090', + 'slategray1' => 'rgb #c6e2ff', + 'slategray2' => 'rgb #b9d3ee', + 'slategray3' => 'rgb #9fb6cd', + 'slategray4' => 'rgb #6c7b8b', + 'slategrey' => 'rgb #708090', + 'grey0' => 'rgb #000000', + 'grey1' => 'rgb #030303', + 'grey2' => 'rgb #050505', + 'grey3' => 'rgb #080808', + 'grey4' => 'rgb #0a0a0a', + 'grey5' => 'rgb #0d0d0d', + 'grey6' => 'rgb #0f0f0f', + 'grey7' => 'rgb #121212', + 'grey8' => 'rgb #141414', + 'grey9' => 'rgb #171717', + 'grey10' => 'rgb #1a1a1a', + 'grey11' => 'rgb #1c1c1c', + 'grey12' => 'rgb #1f1f1f', + 'grey13' => 'rgb #212121', + 'grey14' => 'rgb #242424', + 'grey15' => 'rgb #262626', + 'grey16' => 'rgb #292929', + 'grey17' => 'rgb #2b2b2b', + 'grey18' => 'rgb #2e2e2e', + 'grey19' => 'rgb #303030', + 'grey20' => 'rgb #333333', + 'grey21' => 'rgb #363636', + 'grey22' => 'rgb #383838', + 'grey23' => 'rgb #3b3b3b', + 'grey24' => 'rgb #3d3d3d', + 'grey25' => 'rgb #404040', + 'grey26' => 'rgb #424242', + 'grey27' => 'rgb #454545', + 'grey28' => 'rgb #474747', + 'grey29' => 'rgb #4a4a4a', + 'grey30' => 'rgb #4d4d4d', + 'grey31' => 'rgb #4f4f4f', + 'grey32' => 'rgb #525252', + 'grey33' => 'rgb #545454', + 'grey34' => 'rgb #575757', + 'grey35' => 'rgb #595959', + 'grey36' => 'rgb #5c5c5c', + 'grey37' => 'rgb #5e5e5e', + 'grey38' => 'rgb #616161', + 'grey39' => 'rgb #636363', + 'grey40' => 'rgb #666666', + 'grey41' => 'rgb #696969', + 'grey42' => 'rgb #6b6b6b', + 'grey43' => 'rgb #6e6e6e', + 'grey44' => 'rgb #707070', + 'grey45' => 'rgb #737373', + 'grey46' => 'rgb #757575', + 'grey47' => 'rgb #787878', + 'grey48' => 'rgb #7a7a7a', + 'grey49' => 'rgb #7d7d7d', + 'grey50' => 'rgb #7f7f7f', + 'grey51' => 'rgb #828282', + 'grey52' => 'rgb #858585', + 'grey53' => 'rgb #878787', + 'grey54' => 'rgb #8a8a8a', + 'grey55' => 'rgb #8c8c8c', + 'grey56' => 'rgb #8f8f8f', + 'grey57' => 'rgb #919191', + 'grey58' => 'rgb #949494', + 'grey59' => 'rgb #969696', + 'grey60' => 'rgb #999999', + 'grey61' => 'rgb #9c9c9c', + 'grey62' => 'rgb #9e9e9e', + 'grey63' => 'rgb #a1a1a1', + 'grey64' => 'rgb #a3a3a3', + 'grey65' => 'rgb #a6a6a6', + 'grey66' => 'rgb #a8a8a8', + 'grey67' => 'rgb #ababab', + 'grey68' => 'rgb #adadad', + 'grey69' => 'rgb #b0b0b0', + 'grey70' => 'rgb #b3b3b3', + 'grey71' => 'rgb #b5b5b5', + 'grey72' => 'rgb #b8b8b8', + 'grey73' => 'rgb #bababa', + 'grey74' => 'rgb #bdbdbd', + 'grey75' => 'rgb #bfbfbf', + 'grey76' => 'rgb #c2c2c2', + 'grey77' => 'rgb #c4c4c4', + 'grey78' => 'rgb #c7c7c7', + 'grey79' => 'rgb #c9c9c9', + 'grey80' => 'rgb #cccccc', + 'grey81' => 'rgb #cfcfcf', + 'grey82' => 'rgb #d1d1d1', + 'grey83' => 'rgb #d4d4d4', + 'grey84' => 'rgb #d6d6d6', + 'grey85' => 'rgb #d9d9d9', + 'grey86' => 'rgb #dbdbdb', + 'grey87' => 'rgb #dedede', + 'grey88' => 'rgb #e0e0e0', + 'grey89' => 'rgb #e3e3e3', + 'grey90' => 'rgb #e5e5e5', + 'grey91' => 'rgb #e8e8e8', + 'grey92' => 'rgb #ebebeb', + 'grey93' => 'rgb #ededed', + 'grey94' => 'rgb #f0f0f0', + 'grey95' => 'rgb #f2f2f2', + 'grey96' => 'rgb #f5f5f5', + 'grey97' => 'rgb #f7f7f7', + 'grey98' => 'rgb #fafafa', + 'grey99' => 'rgb #fcfcfc', + 'grey100' => 'rgb #ffffff', + 'aliceblue' => 'rgb #f0f8ff', + 'blueviolet' => 'rgb #8a2be2', + 'cadetblue' => 'rgb #5f9ea0', + 'cadetblue1' => 'rgb #98f5ff', + 'cadetblue2' => 'rgb #8ee5ee', + 'cadetblue3' => 'rgb #7ac5cd', + 'cadetblue4' => 'rgb #53868b', + 'cornflowerblue' => 'rgb #6495ed', + 'darkslateblue' => 'rgb #483d8b', + 'darkturquoise' => 'rgb #00ced1', + 'deepskyblue' => 'rgb #00bfff', + 'deepskyblue1' => 'rgb #00bfff', + 'deepskyblue2' => 'rgb #00b2ee', + 'deepskyblue3' => 'rgb #009acd', + 'deepskyblue4' => 'rgb #00688b', + 'dodgerblue' => 'rgb #1e90ff', + 'dodgerblue1' => 'rgb #1e90ff', + 'dodgerblue2' => 'rgb #1c86ee', + 'dodgerblue3' => 'rgb #1874cd', + 'dodgerblue4' => 'rgb #104e8b', + 'lightblue' => 'rgb #add8e6', + 'lightblue1' => 'rgb #bfefff', + 'lightblue2' => 'rgb #b2dfee', + 'lightblue3' => 'rgb #9ac0cd', + 'lightblue4' => 'rgb #68838b', + 'lightcyan' => 'rgb #e0ffff', + 'lightcyan1' => 'rgb #e0ffff', + 'lightcyan2' => 'rgb #d1eeee', + 'lightcyan3' => 'rgb #b4cdcd', + 'lightcyan4' => 'rgb #7a8b8b', + 'lightskyblue' => 'rgb #87cefa', + 'lightskyblue1' => 'rgb #b0e2ff', + 'lightskyblue2' => 'rgb #a4d3ee', + 'lightskyblue3' => 'rgb #8db6cd', + 'lightskyblue4' => 'rgb #607b8b', + 'lightslateblue' => 'rgb #8470ff', + 'lightsteelblue' => 'rgb #b0c4de', + 'lightsteelblue1' => 'rgb #cae1ff', + 'lightsteelblue2' => 'rgb #bcd2ee', + 'lightsteelblue3' => 'rgb #a2b5cd', + 'lightsteelblue4' => 'rgb #6e7b8b', + 'mediumaquamarine' => 'rgb #66cdaa', + 'mediumblue' => 'rgb #0000cd', + 'mediumslateblue' => 'rgb #7b68ee', + 'mediumturquoise' => 'rgb #48d1cc', + 'midnightblue' => 'rgb #191970', + 'navyblue' => 'rgb #000080', + 'paleturquoise' => 'rgb #afeeee', + 'paleturquoise1' => 'rgb #bbffff', + 'paleturquoise2' => 'rgb #aeeeee', + 'paleturquoise3' => 'rgb #96cdcd', + 'paleturquoise4' => 'rgb #668b8b', + 'powderblue' => 'rgb #b0e0e6', + 'royalblue' => 'rgb #4169e1', + 'royalblue1' => 'rgb #4876ff', + 'royalblue2' => 'rgb #436eee', + 'royalblue3' => 'rgb #3a5fcd', + 'royalblue4' => 'rgb #27408b', + 'skyblue' => 'rgb #87ceeb', + 'skyblue1' => 'rgb #87ceff', + 'skyblue2' => 'rgb #7ec0ee', + 'skyblue3' => 'rgb #6ca6cd', + 'skyblue4' => 'rgb #4a708b', + 'slateblue' => 'rgb #6a5acd', + 'slateblue1' => 'rgb #836fff', + 'slateblue2' => 'rgb #7a67ee', + 'slateblue3' => 'rgb #6959cd', + 'slateblue4' => 'rgb #473c8b', + 'steelblue' => 'rgb #4682b4', + 'steelblue1' => 'rgb #63b8ff', + 'steelblue2' => 'rgb #5cacee', + 'steelblue3' => 'rgb #4f94cd', + 'steelblue4' => 'rgb #36648b', + 'aquamarine' => 'rgb #7fffd4', + 'aquamarine1' => 'rgb #7fffd4', + 'aquamarine2' => 'rgb #76eec6', + 'aquamarine3' => 'rgb #66cdaa', + 'aquamarine4' => 'rgb #458b74', + 'azure' => 'rgb #f0ffff', + 'azure1' => 'rgb #f0ffff', + 'azure2' => 'rgb #e0eeee', + 'azure3' => 'rgb #c1cdcd', + 'azure4' => 'rgb #838b8b', + 'blue' => 'rgb #0000ff', + 'blue1' => 'rgb #0000ff', + 'blue2' => 'rgb #0000ee', + 'blue3' => 'rgb #0000cd', + 'blue4' => 'rgb #00008b', + 'cyan' => 'rgb #00ffff', + 'cyan1' => 'rgb #00ffff', + 'cyan2' => 'rgb #00eeee', + 'cyan3' => 'rgb #00cdcd', + 'cyan4' => 'rgb #008b8b', + 'navy' => 'rgb #000080', + 'turquoise' => 'rgb #40e0d0', + 'turquoise1' => 'rgb #00f5ff', + 'turquoise2' => 'rgb #00e5ee', + 'turquoise3' => 'rgb #00c5cd', + 'turquoise4' => 'rgb #00868b', + 'darkslategray' => 'rgb #2f4f4f', + 'darkslategray1' => 'rgb #97ffff', + 'darkslategray2' => 'rgb #8deeee', + 'darkslategray3' => 'rgb #79cdcd', + 'darkslategray4' => 'rgb #528b8b', + 'rosybrown' => 'rgb #bc8f8f', + 'rosybrown1' => 'rgb #ffc1c1', + 'rosybrown2' => 'rgb #eeb4b4', + 'rosybrown3' => 'rgb #cd9b9b', + 'rosybrown4' => 'rgb #8b6969', + 'saddlebrown' => 'rgb #8b4513', + 'sandybrown' => 'rgb #f4a460', + 'beige' => 'rgb #f5f5dc', + 'brown' => 'rgb #a52a2a', + 'brown1' => 'rgb #ff4040', + 'brown2' => 'rgb #ee3b3b', + 'brown3' => 'rgb #cd3333', + 'brown4' => 'rgb #8b2323', + 'burlywood' => 'rgb #deb887', + 'burlywood1' => 'rgb #ffd39b', + 'burlywood2' => 'rgb #eec591', + 'burlywood3' => 'rgb #cdaa7d', + 'burlywood4' => 'rgb #8b7355', + 'chocolate' => 'rgb #d2691e', + 'chocolate1' => 'rgb #ff7f24', + 'chocolate2' => 'rgb #ee7621', + 'chocolate3' => 'rgb #cd661d', + 'chocolate4' => 'rgb #8b4513', + 'peru' => 'rgb #cd853f', + 'tan' => 'rgb #d2b48c', + 'tan1' => 'rgb #ffa54f', + 'tan2' => 'rgb #ee9a49', + 'tan3' => 'rgb #cd853f', + 'tan4' => 'rgb #8b5a2b', + 'darkgreen' => 'rgb #006400', + 'darkkhaki' => 'rgb #bdb76b', + 'darkolivegreen' => 'rgb #556b2f', + 'darkolivegreen1' => 'rgb #caff70', + 'darkolivegreen2' => 'rgb #bcee68', + 'darkolivegreen3' => 'rgb #a2cd5a', + 'darkolivegreen4' => 'rgb #6e8b3d', + 'darkseagreen' => 'rgb #8fbc8f', + 'darkseagreen1' => 'rgb #c1ffc1', + 'darkseagreen2' => 'rgb #b4eeb4', + 'darkseagreen3' => 'rgb #9bcd9b', + 'darkseagreen4' => 'rgb #698b69', + 'forestgreen' => 'rgb #228b22', + 'greenyellow' => 'rgb #adff2f', + 'lawngreen' => 'rgb #7cfc00', + 'lightseagreen' => 'rgb #20b2aa', + 'limegreen' => 'rgb #32cd32', + 'mediumseagreen' => 'rgb #3cb371', + 'mediumspringgreen' => 'rgb #00fa9a', + 'mintcream' => 'rgb #f5fffa', + 'olivedrab' => 'rgb #6b8e23', + 'olivedrab1' => 'rgb #c0ff3e', + 'olivedrab2' => 'rgb #b3ee3a', + 'olivedrab3' => 'rgb #9acd32', + 'olivedrab4' => 'rgb #698b22', + 'palegreen' => 'rgb #98fb98', + 'palegreen1' => 'rgb #9aff9a', + 'palegreen2' => 'rgb #90ee90', + 'palegreen3' => 'rgb #7ccd7c', + 'palegreen4' => 'rgb #548b54', + 'seagreen' => 'rgb #2e8b57', + 'seagreen1' => 'rgb #54ff9f', + 'seagreen2' => 'rgb #4eee94', + 'seagreen3' => 'rgb #43cd80', + 'seagreen4' => 'rgb #2e8b57', + 'springgreen' => 'rgb #00ff7f', + 'springgreen1' => 'rgb #00ff7f', + 'springgreen2' => 'rgb #00ee76', + 'springgreen3' => 'rgb #00cd66', + 'springgreen4' => 'rgb #008b45', + 'yellowgreen' => 'rgb #9acd32', + 'chartreuse' => 'rgb #7fff00', + 'chartreuse1' => 'rgb #7fff00', + 'chartreuse2' => 'rgb #76ee00', + 'chartreuse3' => 'rgb #66cd00', + 'chartreuse4' => 'rgb #458b00', + 'green' => 'rgb #00ff00', + 'green1' => 'rgb #00ff00', + 'green2' => 'rgb #00ee00', + 'green3' => 'rgb #00cd00', + 'green4' => 'rgb #008b00', + 'khaki' => 'rgb #f0e68c', + 'khaki1' => 'rgb #fff68f', + 'khaki2' => 'rgb #eee685', + 'khaki3' => 'rgb #cdc673', + 'khaki4' => 'rgb #8b864e', + 'darkorange' => 'rgb #ff8c00', + 'darkorange1' => 'rgb #ff7f00', + 'darkorange2' => 'rgb #ee7600', + 'darkorange3' => 'rgb #cd6600', + 'darkorange4' => 'rgb #8b4500', + 'darksalmon' => 'rgb #e9967a', + 'lightcoral' => 'rgb #f08080', + 'lightsalmon' => 'rgb #ffa07a', + 'lightsalmon1' => 'rgb #ffa07a', + 'lightsalmon2' => 'rgb #ee9572', + 'lightsalmon3' => 'rgb #cd8162', + 'lightsalmon4' => 'rgb #8b5742', + 'peachpuff' => 'rgb #ffdab9', + 'peachpuff1' => 'rgb #ffdab9', + 'peachpuff2' => 'rgb #eecbad', + 'peachpuff3' => 'rgb #cdaf95', + 'peachpuff4' => 'rgb #8b7765', + 'bisque' => 'rgb #ffe4c4', + 'bisque1' => 'rgb #ffe4c4', + 'bisque2' => 'rgb #eed5b7', + 'bisque3' => 'rgb #cdb79e', + 'bisque4' => 'rgb #8b7d6b', + 'coral' => 'rgb #ff7f50', + 'coral1' => 'rgb #ff7256', + 'coral2' => 'rgb #ee6a50', + 'coral3' => 'rgb #cd5b45', + 'coral4' => 'rgb #8b3e2f', + 'honeydew' => 'rgb #f0fff0', + 'honeydew1' => 'rgb #f0fff0', + 'honeydew2' => 'rgb #e0eee0', + 'honeydew3' => 'rgb #c1cdc1', + 'honeydew4' => 'rgb #838b83', + 'orange' => 'rgb #ffa500', + 'orange1' => 'rgb #ffa500', + 'orange2' => 'rgb #ee9a00', + 'orange3' => 'rgb #cd8500', + 'orange4' => 'rgb #8b5a00', + 'salmon' => 'rgb #fa8072', + 'salmon1' => 'rgb #ff8c69', + 'salmon2' => 'rgb #ee8262', + 'salmon3' => 'rgb #cd7054', + 'salmon4' => 'rgb #8b4c39', + 'sienna' => 'rgb #a0522d', + 'sienna1' => 'rgb #ff8247', + 'sienna2' => 'rgb #ee7942', + 'sienna3' => 'rgb #cd6839', + 'sienna4' => 'rgb #8b4726', + 'deeppink' => 'rgb #ff1493', + 'deeppink1' => 'rgb #ff1493', + 'deeppink2' => 'rgb #ee1289', + 'deeppink3' => 'rgb #cd1076', + 'deeppink4' => 'rgb #8b0a50', + 'hotpink' => 'rgb #ff69b4', + 'hotpink1' => 'rgb #ff6eb4', + 'hotpink2' => 'rgb #ee6aa7', + 'hotpink3' => 'rgb #cd6090', + 'hotpink4' => 'rgb #8b3a62', + 'indianred' => 'rgb #cd5c5c', + 'indianred1' => 'rgb #ff6a6a', + 'indianred2' => 'rgb #ee6363', + 'indianred3' => 'rgb #cd5555', + 'indianred4' => 'rgb #8b3a3a', + 'lightpink' => 'rgb #ffb6c1', + 'lightpink1' => 'rgb #ffaeb9', + 'lightpink2' => 'rgb #eea2ad', + 'lightpink3' => 'rgb #cd8c95', + 'lightpink4' => 'rgb #8b5f65', + 'mediumvioletred' => 'rgb #c71585', + 'mistyrose' => 'rgb #ffe4e1', + 'mistyrose1' => 'rgb #ffe4e1', + 'mistyrose2' => 'rgb #eed5d2', + 'mistyrose3' => 'rgb #cdb7b5', + 'mistyrose4' => 'rgb #8b7d7b', + 'orangered' => 'rgb #ff4500', + 'orangered1' => 'rgb #ff4500', + 'orangered2' => 'rgb #ee4000', + 'orangered3' => 'rgb #cd3700', + 'orangered4' => 'rgb #8b2500', + 'palevioletred' => 'rgb #db7093', + 'palevioletred1' => 'rgb #ff82ab', + 'palevioletred2' => 'rgb #ee799f', + 'palevioletred3' => 'rgb #cd6889', + 'palevioletred4' => 'rgb #8b475d', + 'violetred' => 'rgb #d02090', + 'violetred1' => 'rgb #ff3e96', + 'violetred2' => 'rgb #ee3a8c', + 'violetred3' => 'rgb #cd3278', + 'violetred4' => 'rgb #8b2252', + 'firebrick' => 'rgb #b22222', + 'firebrick1' => 'rgb #ff3030', + 'firebrick2' => 'rgb #ee2c2c', + 'firebrick3' => 'rgb #cd2626', + 'firebrick4' => 'rgb #8b1a1a', + 'pink' => 'rgb #ffc0cb', + 'pink1' => 'rgb #ffb5c5', + 'pink2' => 'rgb #eea9b8', + 'pink3' => 'rgb #cd919e', + 'pink4' => 'rgb #8b636c', + 'red' => 'rgb #ff0000', + 'red1' => 'rgb #ff0000', + 'red2' => 'rgb #ee0000', + 'red3' => 'rgb #cd0000', + 'red4' => 'rgb #8b0000', + 'tomato' => 'rgb #ff6347', + 'tomato1' => 'rgb #ff6347', + 'tomato2' => 'rgb #ee5c42', + 'tomato3' => 'rgb #cd4f39', + 'tomato4' => 'rgb #8b3626', + 'darkorchid' => 'rgb #9932cc', + 'darkorchid1' => 'rgb #bf3eff', + 'darkorchid2' => 'rgb #b23aee', + 'darkorchid3' => 'rgb #9a32cd', + 'darkorchid4' => 'rgb #68228b', + 'darkviolet' => 'rgb #9400d3', + 'lavenderblush' => 'rgb #fff0f5', + 'lavenderblush1' => 'rgb #fff0f5', + 'lavenderblush2' => 'rgb #eee0e5', + 'lavenderblush3' => 'rgb #cdc1c5', + 'lavenderblush4' => 'rgb #8b8386', + 'mediumorchid' => 'rgb #ba55d3', + 'mediumorchid1' => 'rgb #e066ff', + 'mediumorchid2' => 'rgb #d15fee', + 'mediumorchid3' => 'rgb #b452cd', + 'mediumorchid4' => 'rgb #7a378b', + 'mediumpurple' => 'rgb #9370db', + 'mediumpurple1' => 'rgb #ab82ff', + 'mediumpurple2' => 'rgb #9f79ee', + 'mediumpurple3' => 'rgb #8968cd', + 'mediumpurple4' => 'rgb #5d478b', + 'lavender' => 'rgb #e6e6fa', + 'magenta' => 'rgb #ff00ff', + 'magenta1' => 'rgb #ff00ff', + 'magenta2' => 'rgb #ee00ee', + 'magenta3' => 'rgb #cd00cd', + 'magenta4' => 'rgb #8b008b', + 'maroon' => 'rgb #b03060', + 'maroon1' => 'rgb #ff34b3', + 'maroon2' => 'rgb #ee30a7', + 'maroon3' => 'rgb #cd2990', + 'maroon4' => 'rgb #8b1c62', + 'orchid' => 'rgb #da70d6', + 'orchid1' => 'rgb #ff83fa', + 'orchid2' => 'rgb #ee7ae9', + 'orchid3' => 'rgb #cd69c9', + 'orchid4' => 'rgb #8b4789', + 'plum' => 'rgb #dda0dd', + 'plum1' => 'rgb #ffbbff', + 'plum2' => 'rgb #eeaeee', + 'plum3' => 'rgb #cd96cd', + 'plum4' => 'rgb #8b668b', + 'purple' => 'rgb #a020f0', + 'purple1' => 'rgb #9b30ff', + 'purple2' => 'rgb #912cee', + 'purple3' => 'rgb #7d26cd', + 'purple4' => 'rgb #551a8b', + 'thistle' => 'rgb #d8bfd8', + 'thistle1' => 'rgb #ffe1ff', + 'thistle2' => 'rgb #eed2ee', + 'thistle3' => 'rgb #cdb5cd', + 'thistle4' => 'rgb #8b7b8b', + 'violet' => 'rgb #ee82ee', + 'antiquewhite' => 'rgb #faebd7', + 'antiquewhite1' => 'rgb #ffefdb', + 'antiquewhite2' => 'rgb #eedfcc', + 'antiquewhite3' => 'rgb #cdc0b0', + 'antiquewhite4' => 'rgb #8b8378', + 'floralwhite' => 'rgb #fffaf0', + 'ghostwhite' => 'rgb #f8f8ff', + 'navajowhite' => 'rgb #ffdead', + 'navajowhite1' => 'rgb #ffdead', + 'navajowhite2' => 'rgb #eecfa1', + 'navajowhite3' => 'rgb #cdb38b', + 'navajowhite4' => 'rgb #8b795e', + 'oldlace' => 'rgb #fdf5e6', + 'whitesmoke' => 'rgb #f5f5f5', + 'gainsboro' => 'rgb #dcdcdc', + 'ivory' => 'rgb #fffff0', + 'ivory1' => 'rgb #fffff0', + 'ivory2' => 'rgb #eeeee0', + 'ivory3' => 'rgb #cdcdc1', + 'ivory4' => 'rgb #8b8b83', + 'linen' => 'rgb #faf0e6', + 'seashell' => 'rgb #fff5ee', + 'seashell1' => 'rgb #fff5ee', + 'seashell2' => 'rgb #eee5de', + 'seashell3' => 'rgb #cdc5bf', + 'seashell4' => 'rgb #8b8682', + 'snow' => 'rgb #fffafa', + 'snow1' => 'rgb #fffafa', + 'snow2' => 'rgb #eee9e9', + 'snow3' => 'rgb #cdc9c9', + 'snow4' => 'rgb #8b8989', + 'wheat' => 'rgb #f5deb3', + 'wheat1' => 'rgb #ffe7ba', + 'wheat2' => 'rgb #eed8ae', + 'wheat3' => 'rgb #cdba96', + 'wheat4' => 'rgb #8b7e66', + 'white' => 'rgb #ffffff', + 'blanchedalmond' => 'rgb #ffebcd', + 'darkgoldenrod' => 'rgb #b8860b', + 'darkgoldenrod1' => 'rgb #ffb90f', + 'darkgoldenrod2' => 'rgb #eead0e', + 'darkgoldenrod3' => 'rgb #cd950c', + 'darkgoldenrod4' => 'rgb #8b6508', + 'lemonchiffon' => 'rgb #fffacd', + 'lemonchiffon1' => 'rgb #fffacd', + 'lemonchiffon2' => 'rgb #eee9bf', + 'lemonchiffon3' => 'rgb #cdc9a5', + 'lemonchiffon4' => 'rgb #8b8970', + 'lightgoldenrod' => 'rgb #eedd82', + 'lightgoldenrod1' => 'rgb #ffec8b', + 'lightgoldenrod2' => 'rgb #eedc82', + 'lightgoldenrod3' => 'rgb #cdbe70', + 'lightgoldenrod4' => 'rgb #8b814c', + 'lightgoldenrodyellow' => 'rgb #fafad2', + 'lightyellow' => 'rgb #ffffe0', + 'lightyellow1' => 'rgb #ffffe0', + 'lightyellow2' => 'rgb #eeeed1', + 'lightyellow3' => 'rgb #cdcdb4', + 'lightyellow4' => 'rgb #8b8b7a', + 'palegoldenrod' => 'rgb #eee8aa', + 'papayawhip' => 'rgb #ffefd5', + 'cornsilk' => 'rgb #fff8dc', + 'cornsilk1' => 'rgb #fff8dc', + 'cornsilk2' => 'rgb #eee8cd', + 'cornsilk3' => 'rgb #cdc8b1', + 'cornsilk4' => 'rgb #8b8878', + 'gold' => 'rgb #ffd700', + 'gold1' => 'rgb #ffd700', + 'gold2' => 'rgb #eec900', + 'gold3' => 'rgb #cdad00', + 'gold4' => 'rgb #8b7500', + 'goldenrod' => 'rgb #daa520', + 'goldenrod1' => 'rgb #ffc125', + 'goldenrod2' => 'rgb #eeb422', + 'goldenrod3' => 'rgb #cd9b1d', + 'goldenrod4' => 'rgb #8b6914', + 'moccasin' => 'rgb #ffe4b5', + 'yellow' => 'rgb #ffff00', + 'yellow1' => 'rgb #ffff00', + 'yellow2' => 'rgb #eeee00', + 'yellow3' => 'rgb #cdcd00', + 'yellow4' => 'rgb #8b8b00', +); + +my ($ln,%grph,@data,$colno,%sz,$buf,%defcol); +my $InBG=0; + +my $piestart; +my $pi=3.1459*2; +my ($fh,$fn); + +my @qname=('Jan-Mar','Apr-Jun','Jul-Sep','Oct-Dec'); +my @hname=('Jan-Jun','Jul-Dec'); +my @mname=('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'); +my ($stats,$ymarg,$xmarg,%stats); +$stats=\%stats; + +while (<>) +{ + chomp; + s/\r$//; + + if (m'^\.\s*BGS\s*(\w*)') + { + my $type=($1)?$1:'pi'; + if ($type ne 'FRAME') + { + $InBG=1; + %grph=(); + @data=(); + %stats=(); + $grph{TYPE}->[0]=lc($type); + $buf=""; + next; + } + } + + if ($InBG and $_ eq '.BGE') + { + $InBG=0; + $buf.=".fl\n"; + BuildGraph(); + next; + } + + if (!$InBG) + { + print "$_\n"; + next; + } + + s/^\s+//; + next if substr($_,0,1) eq '#'; + $ln++; + + if (m/^(.+?):(.*)/) + { + my $cmd=uc($1); + my (@args)=split("\t",$2); + + my $cptr; + my $dup=0; + + foreach my $c (@CMDS) + { + if ($cmd eq substr($c->[0],0,length($cmd)) and index("/$c->[2]/","/$grph{TYPE}->[0]/") >= 0) + { + $cptr=$c,$c->[4]=$ln if $dup == 0; + $dup++; + } + } + + Log(1,"Command '$cmd' not understood") if $dup == 0; + Log(0,"Command '$cmd' is ambiguous - '$cptr->[0]' used") if $cmd ne 'SERIES' and $dup > 1; + + $cmd=$cptr->[0]; + + if ($cmd eq 'SERIES') + { + LoadSeries(\@args); + } + elsif ($cmd eq 'SFILE') + { + if (open(F,"<$args[0]")) + { + while () + { + chomp; + s/\r$//; + s/^\s+//; + s/^S.*?://; + + my (@r)=split("\t"); + LoadSeries(\@r); + } + + close(F); + } + else + { + Log(1,"Failed to open Series File '$args[0]'"); + } + } + else + { + Log(0,$ln,"Redefined command '$cmd'") if exists($grph{$cmd}); + $grph{$cmd}=\@args; + } + } +} + +exit 0; + +sub LoadSeries +{ + my $args=shift; + + if ($grph{TYPE}->[0] eq 'pi') + { + my ($nm,$val)=(@{$args}); + + my $valn=$val; + $valn=~s'\\.(\(..|\[.*\])''g; + $valn=~s/[^-0-9.]//g; + $valn=0 if $valn eq ''; + $grph{NEGPIE}=1 if $valn < 0; + push(@data,[$valn,$nm,undef,$val]); + } + else + { + my ($sno,$txt,@data); + ($sno,$txt,@data)=(@{$args}); + $sno=1,$grph{BACKGROUND}=1 if uc($sno) eq 'B'; + $sno-- if $sno=~m/^\d+$/ and $sno > 0; + foreach my $d (@data) {$d=~s/\((.+)\)/-$1/} + LoadData($sno,$txt,\@data); + } +} + +sub BuildGraph +{ + # All Commands now read, assign defaults for any missing + + my $type='pi'; + $type=lc($grph{TYPE}->[0]) if exists($grph{TYPE}); + + foreach my $c (@CMDS) + { + # Log(0,"Cmd=$c->[0]"); + if (index($c->[2],$type) >= 0) + { + my $cmd=$c->[0]; + + if (!exists($grph{$cmd}) and $c->[1] ne 'undef') + { + my (@args)=split("\t",$c->[3]); + $args[0]='' if $#args==-1; + $grph{$cmd}=\@args; + } + + # Add default scaling factors + + my $scale=$c->[1]; + + if ($scale ne '' and exists($grph{$cmd})) + { + my $ct=-1; + + foreach my $v (@{$grph{$cmd}}) + { + if ($scale eq '#' and $v ne '') + { + # colours + + $v=lc($v); + + if (substr($v,0,1) eq '#') + { + $v=defcol("rgb $v"); + } + elsif ($v=~m/(rgb|cmyk|cmy|gray|grey)\s+(.*)/) + { + $v=defcol("$1 $2"); + } + elsif (exists($colours{$v})) + { + $v=defcol($colours{$v}); + } + else + { + Log(0,"Colour names ($v) not found"); + } + + if ($cmd eq 'SCOLOURS') + { + $grph{CONTRAST}->[++$ct]=contrast($v); + } + } + elsif ($scale eq 'bool') + { + $v=lc($v); + + if (substr($v,0,1) eq 'y') + { + $v=1; + } + elsif (substr($v,0,1) eq 'n') + { + $v=0; + } + } + else + { + if ($v=~m/^\s*([-0-9.+]+)\s*$/) + { + $v="$1$scale" if $scale ne 'undef'; + } + } + } + } + + # Now convert all values to points + + if (exists($grph{$cmd})) + { + foreach my $v (@{$grph{$cmd}}) + { + if ($scale ne '#' and $scale ne '' and $scale ne 'undef') + { + if ($v=~m/([\d.]+)([cimp])/i) + { + my $num=$1; + my $mul=$2; + + $v=ToPoints($num,$mul,$c->[4]); + } + } + } + } + } + } + + # If no ORIGIN or relative - centre it + + if ($grph{TYPE}->[0] eq 'pi') + { + foreach my $i (0..1) + { + $grph{ORIGIN}->[$i]=0 if !$grph{ORIGIN}->[$i]; + + if ($grph{ORIGIN}->[$i]=~m/^[+-]/ or $grph{ORIGIN}->[$i] == 0) + { + $grph{ORIGIN}->[$i]+=int($grph{FRAME}->[$i]/2); + } + } + } + + # VS may be a percentage of PS + + if ($grph{VS}->[0]=~m/(\+|\-)?(\d+)%/) + { + my $p=$grph{PS}->[0]; + my $d=$p*$2/100; + $d*=-1 if $1 and $1 eq '-'; + $grph{VS}->[0]=$p+$d; + } + + # Drop Shadow? + + $grph{SHADE}=[]; + + if ($grph{SHADOW}->[0]) + { + my $bg=$grph{BGCOLOUR}->[0] || 'rgb_#ffffff'; + + my ($coltype,$arg)=split('_',$bg,2); + my (@c)=GetComponents($arg); + my @add; + my $start; + + if ($coltype eq 'cmyk') + { + $start=0xffff; + } + elsif ($coltype eq 'cmy') + { + $start=0xffff; + } + elsif ($coltype eq 'grey') + { + $start=0; + } + elsif ($coltype eq 'rgb') + { + $start=0; + } + + foreach my $c (@c) + { + push(@add,($c-$start)/10); + } + + foreach my $j (1..10) + { + foreach my $i (0..$#c) + { + $c[$i]-=$add[$i]; + $c[$i]=0xffff if $c[$i] > 0xffff; + $c[$i]=0 if $c[$i] < 0; + } + + push(@{$grph{SHADE}},defcol("$coltype #".join('',map(sprintf("%02x",$_>>8),@c)))); + } + } + + # Graph floor + + if (exists($grph{FLOOR}) and $grph{FLOOR}->[0]=~/^C/) + { + substr($grph{FLOOR}->[0],0,1)=''; + $grph{FLOORFLAG}->[0]='C'; + } + else + { + $grph{FLOORFLAG}->[0]=''; + } + + # Frigging with horizontal bar graphs + + if ($grph{HORIZONTAL}->[0]) + { + # First make all series bar type + + foreach my $s (@{$stats->{BAR}}) {$s=1;} + + # Now alter data to $label~col1^col2... + + foreach my $s (0..$#{$stats->{DATA}}) + { + my $d=$stats->{DATA}->[$s]; + my $v=shift(@{$d}); + my $t=join('^',@{$d}); + $stats->{NAME}->[$s].="~$t"; + $stats->{DATA}->[$s]=[$v]; + } + } + # Now find out width of any text + +# my $tmpnm="busgraph-$$"; +# my $tmpdir='/tmp'; +# +# if (exists($ENV{GROFF_TMPDIR})) +# { +# $tmpdir=$ENV{GROFF_TMPDIR}; +# } +# else +# { +# $tmpdir=$ENV{TMPDIR} if exists($ENV{TMPDIR}); +# } +# +# my $seq='0000'; +# +# do +# { +# $fn="$tmpdir/$tmpnm"; +# $fn.="-$seq" if $seq ne '0000'; +# $seq++; +# } until (! -e "$fn.dat"); +# +# open($fh,">$fn.dat") or die "Failed to open '$fn.dat'"; +# +# print $fh ".ps $grph{PS}->[0]\n"; +# print $fh ".vs $grph{VS}->[0]\n"; +# print $fh ".ft $grph{FT}->[0]\n"; +# +# FindLen('I::','I'); +# FindLen('II::','II'); +# my $ser=0; +# +# foreach my $s (@data) +# { +# my $txt=$s->[1]; +# my (@wds)=split(' ',$txt); +# $ser++; +# FindLen("S:$ser:TOT",$s->[1]); +# +# my $wd=0; +# +# foreach my $w (@wds) +# { +# $wd++; +# +# FindLen("S:${ser}:${wd}",$w); +# } +# } +# +# close($fh); +# +# LoadLengths("$fn.dat"); + + $buf.=".nr GRP:ll \\n[.ll]\n.ev GRP\n.ad l\n.ft $grph{FT}->[0]\n.fam ".substr($grph{FT}->[0],0,-1)."\n.ps $grph{PS}->[0]\n.vs 0\n\\M[$grph{TEXTCOLOUR}->[0]]\\c\n"; + + if ($grph{PDFBOOKMARK}->[0] and $grph{CAPTION}->[0]) + { + $buf.=".pdfbookmark $grph{PDFBOOKMARK}->[0] ".($type eq 'pi'?'Pie':'Chart').": $grph{CAPTION}->[0]\n"; + } + + if ($grph{JUST}->[0] eq 'left') + { + $buf.=".nr GRP:lefx 0\n"; + } + elsif ($grph{JUST}->[0] eq 'centre') + { + $buf.=".nr GRP:lefx \\n[GRP:ll]u/2-($grph{FRAME}->[0]p/2)\n"; + } + else + { + $buf.=".nr GRP:lefx \\n[GRP:ll]u-$grph{FRAME}->[0]p\n"; + } + + if ($grph{TYPE}->[0] eq 'pi') + { + Do_Pie(); + } + else + { + Do_Graph(); + } + + if ($grph{FLOW}->[0] and $grph{JUST}->[0] ne 'centre') + { + $buf.=".de GRP:skip\n.if \\\\n[.d]<\\\\n[GRP:mk]u+$grph{FRAME}->[1]p .sp |\\\\n[GRP:mk]u+$grph{FRAME}->[1]p\n..\n"; + + if ($grph{JUST}->[0] eq 'left') + { + $buf.=".sp |\\n[GRP:mk]u\n.nr GRP:JPos \\n[GRP:mk]u+$grph{FRAME}->[1]p-.9v\n.de GRP:Just\n'in -($grph{FRAME}->[0]p+8p)\n'sp \\\\n[.trunc]u\n.wh \\n[GRP:JPos]u\n..\n.wh \\n[GRP:JPos]u GRP:Just\n.in $grph{FRAME}->[0]p+8p\n"; + } + elsif ($grph{JUST}->[0] eq 'right') + { + $buf.=".sp |\\n[GRP:mk]u\n.nr GRP:JPos \\n[GRP:mk]u+$grph{FRAME}->[1]p-.9v\n.de GRP:Just\n.ll +($grph{FRAME}->[0]p+8p)\n'sp \\\\n[.trunc]u\n.wh \\n[GRP:JPos]u\n..\n.wh \\n[GRP:JPos]u GRP:Just\n.ll -($grph{FRAME}->[0]p+8p)\n"; + } + } + else + { + $buf.=".sp |\\n[GRP:mk]u+$grph{FRAME}->[1]p\n"; + } + + + + print ".BGS FRAME $grph{FRAME}->[0]p $grph{FRAME}->[1]p\n"; + print $buf; + print ".BGE\n"; +} + +sub Log +{ + my $crit=shift; + my $msg=shift; + + print STDERR "busgrap: $msg\n"; + exit 1 if $crit; +} + +sub defcol +{ + my $col=shift; + return('') if $col eq ''; + my $colnm=$col; + $colnm=~tr[ ][_]; + # return($colnm) if exists($defcol{$colnm}); + + my ($coltype,$arg)=split(' ',$col,2); + my (@c)=GetComponents($arg); + + $buf.=".defcolor $colnm $coltype #".join('',map(sprintf("%02x",$_>>8),@c))."\n"; + + if ($coltype eq 'cmyk') + { + $c[3]+=0x10000*$grph{DARKER}->[0]; + } + elsif ($coltype eq 'cmy') + { + foreach my $c (@c) {$c/=$grph{DARKER}->[0];} + } + elsif ($coltype eq 'gray') + { + $c[0]-=0x10000*$grph{DARKER}->[0]; + } + elsif ($coltype eq 'rgb') + { + foreach my $c (@c) {$c*=$grph{DARKER}->[0];} + } + + foreach my $c (@c) + { + $c=0xffff if ($c > 0xffff); + $c=0 if ($c<0); + } + + $buf.=".defcolor ${colnm}DK $coltype #".join('',map(sprintf("%02x",$_>>8),@c))."\n"; + + $defcol{$colnm}=1; + return($colnm); +} + +sub contrast +{ + my $col=shift; + + my ($coltype,$arg)=split('_',$col,2); + my (@c)=GetComponents($arg); + + # (299*R + 587*G + 114*B) / 1000 + + if ($coltype eq "rgb") + { + return(((($c[0]>>8)*299 + ($c[1]>>8)*587 + ($c[2]>>8)*114)/1000)>128?'black':'white'); + } + elsif ($coltype eq "grey") + { + return(($c[0]>128)?'black':'white'); + } + + return(undef); +} + +sub GetComponents +{ + my $arg=shift; + + if ($arg=~m/([0-9.]+)f?\s+([0-9.]+)f?\s+([0-9.]+)f?/) + { + return($1*65535,$2*65535,$3*65535) + } + elsif ($arg=~m/(\d+)\s+(\d+)\s+(\d+)/) + { + return($1,$2,$3) + } + elsif (substr($arg,0,2) eq '##') + { + return(map(hex($_),$arg=~m/[0-9a-fA-F]{4}/g)); + } + elsif (substr($arg,0,1) eq '#') + { + return((map(hex($_) << 8,$arg=~m/[0-9a-fA-F]{2}/g))); + } + + Log(0,"Failed to convert colour component '$arg'"); + return(()); +} + +sub FindLen +{ + my $key=shift; + my $val=shift; + + print $fh ".nr tm \\w'$val'\n.tm $key:\\n[tm]:\\n[rst]:\\n[rsb]\n"; +} + +sub LoadLengths +{ + my $fn=shift; + + open(F,"groff $fn -Z 2>&1 |") or die "Can't run groff!\n"; + + while () + { + chomp; + + my (@r)=split(':'); + + $sz{$r[0]}->{$r[1]}->{$r[2]}=[@r[3..5]]; + } + + close(F) or die "Spawning groff failed!\n"; +} + +sub ToPoints +{ + my $num=shift; + my $unit=shift; + my $ln=shift; + + if ($unit eq 'i') + { + return($num*72); + } + elsif ($unit eq 'c') + { + return int($num*72/2.54); + } + elsif ($unit eq 'm') # millimetres + { + return int($num*72/25.4); + } + elsif ($unit eq 'p') + { + return($num); + } + elsif ($unit eq 'P') + { + return($num*6); + } + else + { + Log(1,$ln,"Unknown scaling factor '$unit'"); + } +} + +sub Do_Pie +{ + my $tot=0; + my $totval=''; + my $srt; + $piestart=$pi/8; + my $pieradx=$grph{XRAD}->[0]*1000; + my $pierady=$grph{YRAD}->[0]*1000; + my $pct=$grph{PDECIMALS}->[0]; + my $residual=$grph{OTHERS}->[0]; + my $key=$grph{KEYBOX}->[0]; + my $hole=$grph{HOLE}->[0]; + my $shadv=int((($pieradx+$pierady)/2)*.12); + my $shadh=int($shadv/2); + my $usey=$grph{FRAME}->[1]; + my $usex=$grph{FRAME}->[0]; + Log(1,0,"No Series data found") if $#data == -1; + + my (@wdgs)=(@data); + + if ($grph{SORT}->[0]) + { + foreach my $wdg (sort {$b->[0] <=> $a->[0]} @wdgs) + { + $tot+=$wdg->[0]; + push(@{$srt},$wdg); + } + } + else + { + foreach my $wdg (@wdgs) + { + $tot+=$wdg->[0]; + push(@{$srt},$wdg); + } + } + + my $totpctval=0; + + my $bot=scalar(@wdgs)-1; + my $label=$grph{LABEL}->[0]; + $label='' if $key; + return if $tot == 0; + return if $bot+1 < 1; + + foreach my $wdg (@{$srt}) + { + my $pctval=sprintf("%0.*f",abs(${pct}),$wdg->[0]*100/$tot); + $wdg->[2]=$pctval; + $totpctval+=$pctval; + } + + $srt->[0]->[2]+=(100-$totpctval); # "correction" to make percentages = 100 + + my $srt2; + my $bot2=$bot; + + # for (my $j=0; $j <= $bot2; $j++) + # { + # push(@{$srt2},$srt->[$j]); + # + # if ($j < $bot2) + # { + # push(@{$srt2},$srt->[$bot2--]); + # } + # } + # + # $srt=$srt2; + + my $residtxt=''; + + for (my $j=$bot; $j > 0; $j--) + { + next if !defined($srt->[$j]) or $key; + + if ($srt->[$j]->[2] < $residual) + { + my $i=$j; + my $t=$srt->[$j]->[2]; + my $tc=1; + + while ($i > 0 and (($t+$srt->[$i-1]->[2]) < ($residual*2)) or (($t+$srt->[$i-1]->[2])>=($residual*2) and ($srt->[$i-1]->[2] < $residual))) + { + $i--; + $t+=$srt->[$i]->[2]; + $tc++; + } + + if ($i < $j) + { + $residtxt.=', ' if $residtxt ne ''; + $residtxt.=FillTplt($grph{LABEL}->[0],$srt->[$i]->[1],$srt->[$i]->[3],$srt->[$i]->[2],$pct); + $srt->[$i]->[1]="Others"; + my $rt=''; + + foreach my $k ($i+1..$j) + { + $srt->[$i]->[2]+=$srt->[$k]->[2]; + $srt->[$i]->[0]+=$srt->[$k]->[0]; + $residtxt.=', ' if $residtxt ne ''; + $rt=FillTplt($grph{LABEL}->[0],$srt->[$k]->[1],$srt->[$k]->[3],$srt->[$k]->[2],$pct); + $rt=~s/ /\\ /g; + $residtxt.=$rt; + $srt->[$k]=undef; + } + + $srt->[$i]->[3]=$srt->[$i]->[0]; + } + } + } + + if (!$grph{NEGPIE}) + { + $buf.=".ne ${usey}p\n.nf\n.vs 0\n.mk GRP:mk\n"; + $buf.=".in \\n[GRP:lefx]u\n\\Z'\\D't $grph{THICKNESS}->[0]p'\\m[$grph{TEXTCOLOUR}->[0]]\\M[$grph{LINECOLOUR}->[0]]'\\c\n"; + + if ($grph{BGCOLOUR}->[0] ne '') + { + $buf.="\\Z@\\M[$grph{BGCOLOUR}->[0]]\\D'P ${usex}p 0 0 ${usey}p -${usex}p 0 0 -${usey}p'\\M[]@\\c\n"; + } + + if ($grph{BORDER}->[0]) + { + $buf.="\\Z@\\D't $grph{BORDER}->[0]p'@\\Z@\\m[$grph{BRDCOLOUR}->[0]]\\D'p ${usex}p 0 0 ${usey}p -${usex}p 0 0 -${usey}p'\\D't $grph{THICKNESS}->[0]p'\\m[]@\\c\n"; + } + + $buf.=".fl\n.vs $grph{VS}->[0]p\n"; + + if ($grph{CAPTION}->[0] ne '') + { + $buf.=".fi\n.ad c\n.ll ${usex}p+\\n[GRP:lefx]u\n\\s'+2p'$grph{CAPTION}->[0]\\s'-2p'\n.sp -1\n.ad\n.nf\n"; + } + + $buf.="\\v'$grph{ORIGIN}->[1]p'\\h'$grph{ORIGIN}->[0]p'\\c\n"; + my $lastfill=scalar(@{$grph{SHADE}})-1; + my $pie3d=$grph{'3D'}->[0]; + + if ($lastfill >= 1) + { + $buf.="\\v'${pie3d}p'"; + $buf.="\\Z@\\v'${shadv}u'\\h'${shadh}u-${pieradx}u'"; + foreach my $j (0..$lastfill-1) # must have at least 2 colours + { + $buf.="\\Z^\\M[".$grph{SHADE}->[$j]."]\\D'E ".(${pieradx}*2)."u ".(${pierady}*2)."u'^\\v'-".($shadv/$lastfill)."u'\\h'-".($shadh/$lastfill)."u'\\M[]"; + } + + $buf.="\\Z^\\h'-".($shadh/$lastfill)."u'\\M[".$grph{SHADE}->[$lastfill]."]\\D'E ".(${pieradx}*2)."u ".(${pierady}*2)."u'^\\M[]"; + $buf.="@\\c\n"; + $buf.="\\v'-${pie3d}p'\\c\n"; + } + + my $nooutline=($bot==0)?1:0; + $nooutline=1 if $grph{COLOURED}->[0]; + + if ($pie3d) + { + for (my $j=0; $j <= $bot; $j++) + { + next if !defined($srt->[$j]); + my ($val,$txt,$pctval)=(@{$srt->[$j]}); + + DoWedge3d(($val/$tot)*360,$grph{SCOLOURS}->[$j]."DK",$txt,$pieradx,$pierady,$nooutline,$grph{'3D'}->[0]) if $pct < 0 or $pctval > 0; + } + } + + for (my $j=0; $j <= $bot; $j++) + { + next if !defined($srt->[$j]); + my ($val,$txt,$pctval,$valtxt)=(@{$srt->[$j]}); + + $pctval=($pct>=0)?sprintf("%0.*f",abs(${pct}),$pctval):''; + + my $tmplt=FillTplt($grph{LABEL}->[0],$txt,$valtxt,$pctval,$pct); + + $txt=$tmplt if $pct >= 0; + $txt='' if $label eq ''; + + DoWedge(($val/$tot)*360,$grph{SCOLOURS}->[$j],$txt,$pieradx,$pierady,$nooutline,$grph{'3D'}->[0]) if $pct < 0 or $pctval > 0; + } + + if ($hole) + { + $piestart=$pi/8; + DoWedge(360,$grph{BGCOLOUR}->[0],'',$pieradx*$hole,$pierady*$hole,1,0); + } + + if ($residtxt ne '') + { + my $ry=int($grph{ORIGIN}->[1]+$grph{YRAD}->[0]+$grph{'3D'}->[0]+2); + # setupfield($fldp,0,1,0); + $buf.=".ll ".($grph{FRAME}->[0])."p\n"; + $buf.=".fi\n.ad c\n.sp ${ry}p+1.5v\nOthers includes: $residtxt\n.nf\n.ad l\n"; + } + + } + + if ($key and !$grph{NEGPIE}) + { + my $boxlabels=join("\t",@{$grph{BOXLABELS}}); + my $boxheads=join("\t",@{$grph{BOXHEADS}}); + my $boxtabs=join(' ',@{$grph{BOXTABS}}); + $buf.=".vs 0\n.sp |\\n[GRP:mk]u+$grph{BOXFRAME}->[1]p\n.in +$grph{BOXFRAME}->[0]p\n.ta $boxtabs\n.vs\n.in +(1m+4p)\n\\fB$boxheads\\fP\n.sp -.2\n.in -(1m+4p)\n"; + + for (my $j=0; $j <= $bot; $j++) + { + next if !defined($srt->[$j]); + my ($val,$txt,$pctval,$valtxt)=(@{$srt->[$j]}); + my $textcol=$grph{TEXTCOLOUR}->[0]; + my $linecol=$grph{LINECOLOUR}->[0]; + $linecol=$grph{SCOLOURS}->[$j] if $grph{COLOURED}->[0]; + $valtxt=FillTplt($boxlabels,$txt,$valtxt,$pctval,$pct); + + $buf.="\\M[$grph{SCOLOURS}->[$j]]\\m[$linecol]"; + $buf.="\\Z!\\D'P 0 1 1 0 0 -1'!" if $val > 0; + $buf.="\\D'p 0 1 1 0 0 -1'\\M[]\n.in +1m\n.in +4p\n.sp -.2v\n"; + $buf.="\\m[$textcol]$valtxt\\m[]\n.sp -.5\n.in -(1m+4p)\n"; + } + + # if ($totval and $bot > 0) + # { + # my $pctval=($pct>=0)?sprintf("%0.*f%%",abs(${pct}),100):''; + # $buf.=".in +1m\n'in +$fldk->{INDENT}->{LEFT}p\n'sp +.8v\nTotal\\c\n.in -1m\n.in -$fldk->{INDENT}->{LEFT}p\n'sp -1\n\t$totval\t$pctval\n"; + # } + } + + $buf.=".fl\n.ev\n"; + # print $buf; +} + +sub FillTplt +{ + my $tmplt=shift; + my $txt=shift; + my $valtxt=shift; + my $pctval=shift; + my $pct=shift; + + $tmplt=~s/\$text/$txt/ge; + $tmplt=~s/\$value/$valtxt/ge; + $tmplt=~s/\$percent/sprintf("%0.*f",abs($pct),$pctval)/ge; + + return($tmplt); +} + +sub PtoR +{ + my $theta=shift; + my $radx=shift; + my $rady=shift; + + my $y=-int(sin($theta)*$rady); + my $x=int(cos($theta)*$radx); + + return ($x,$y); +} + +sub rad +{ + my $deg=shift; + + return((($deg)/360)*$pi); +} + +sub deg +{ + my $rad=shift; + + return(($rad*360)/$pi); +} + +sub DoWedge +{ + my ($ox,$oy)=(0,0); + my $end=rad($_[0])+$piestart; + my $col=$_[1]; + my $txt=$_[2]; + my $pieradx=$_[3]; + my $pierady=$_[4]; + my $nooutline=$_[5]; + my $depth3d=$_[6]*1000; + my $step=.05; + my $points=''; + my $j; + + for ($j=$piestart; $j<=$end; $j+=$step) + { + # $j=$end if $end-$j < $step; + my ($x,$y)=PtoR($j,$pieradx,$pierady); + $x-=$ox; + $y-=$oy; + $points.="${x}u ${y}u "; + $ox+=$x; + $oy+=$y; + } + + if ($j < $end+$step) + { + $j=$end; + my ($x,$y)=PtoR($j,$pieradx,$pierady); + $x-=$ox; + $y-=$oy; + $points.="${x}u ${y}u "; + $ox+=$x; + $oy+=$y; + } + + $points.="-${ox}u -${oy}u'"; + $buf.="\\M[$col]\\D'P 0 0 $points\\M[]\\c\n"; + $buf.="\\m[$grph{LINECOLOUR}->[0]]\\D'p 0 0 $points\\m[]\\c\n" if !$nooutline; + $j=$piestart+(($end-$piestart)/2); + while ($j-$pi >= 0) {$j-=$pi;} + $piestart=$end; + return if $txt eq ''; + my ($x,$y)=PtoR($j,$pieradx*1.05,$pierady*1.15); + $depth3d=0 if !($j>=$pi/2 and $j < $pi); + $buf.=".nr wi \\w'$txt'\n"; + $buf.="\\Z@\\h'${x}u'\\v'${y}u+${depth3d}u'"; + $buf.="\\v'\\n[rsb]u'" if $y < -1000; + $buf.="\\v'\\n[rst]u'" if $y > 1000; + rjust($txt) if $x < -1000; + ljust($txt) if $x > 1000; + cjust($txt) if abs($x) <= 1000; + $buf.="@\\c\n"; + my($x1,$y1)=PtoR($j,$pieradx,$pierady); + $x-=$x1; + $y-=$y1; + $y1+=$depth3d; + $buf.="\\Z@\\h'${x1}u'\\v'${y1}u'\\D'l ${x}u ${y}u'@\\c\n"; +} + +sub DoWedge3d +{ + my ($ox,$oy)=(0,0); + my $end=rad($_[0])+$piestart; + my $col=$_[1]; + my $txt=$_[2]; + my $pieradx=$_[3]; + my $pierady=$_[4]; + my $nooutline=$_[5]; + my $depth3d=$_[6]*1000; + my $step=.05; + my $points=''; + my $j; + my $doing3d=0; + my $predark=''; + my $offs; + my $sx; + + for ($j=$piestart; $j<=$end; $j+=$step) + { + # $j=$end if $end-$j < $step; + my ($x,$y)=PtoR($j,$pieradx,$pierady); + if ($doing3d==0 and $j>=$pi/2 and $j < $pi) + { + $doing3d=1; + $offs=$y+$depth3d; + $ox=$x; + $oy=$y; + $sx=$x; + $predark="0u ${offs}u"; + } + elsif ($doing3d==1 and $j>=$pi) + { + $doing3d=2; + last; + } + elsif ($doing3d==1) + { + $x-=$ox; + $y-=$oy; + $points.="${x}u ${y}u "; + $ox+=$x; + $oy+=$y; + } + } + + if ($doing3d==1 and $j < $end+$step) + { + $j=$end; + my ($x,$y)=PtoR($j,$pieradx,$pierady); + $x-=$ox; + $y-=$oy; + $points.="${x}u ${y}u "; + $ox+=$x; + $oy+=$y; + } + + if ($doing3d) + { + $offs=$depth3d+$oy; + my $ex=$sx-$ox; + $points.="0 -${offs}u ${ex}u 0'\\h'-${sx}u"; + $buf.="\\M[$col]\\h'${sx}u'\\D'P $predark $points'\\M[]\\c\n"; + $buf.="\\h'${sx}u'\\m[$grph{LINECOLOUR}->[0]]\\D'p $predark $points'\\m[]\\c\n" if !$nooutline; + } + + $j=$piestart+(($end-$piestart)/2); + $piestart=$end; +} + +sub rjust +{ + my $txt=shift; + + $buf.="\\h'-\\n[wi]u'$txt"; +} + +sub ljust +{ + my $txt=shift; + + $buf.="$txt"; +} + +sub cjust +{ + my $txt=shift; + + $buf.="\\h'-\\n[wi]u/2u'$txt"; +} + +sub Do_Graph +{ + CalcData(); + PlotData(); +} + +sub LoadData +{ + my $s=shift; + my $nm=shift; + my $d=shift; + + if (uc($s) eq 'X') + { + push(@{$stats->{LABELS}},@{$d}); + } + elsif (uc($s) eq 'A') + { + push(@{$stats->{ANCHOR}},undef,@{$d}); + } + else + { + if (uc(substr($nm,0,4)) eq "BAR:") + { + $nm=substr($nm,4); + $stats->{BAR}->[$s]=1; + } + else + { + $stats->{BAR}->[$s]=0; + } + push(@{$stats->{DATA}->[$s]},@{$d}); + $stats->{NAME}->[$s]=$nm; + } +} + +sub CalcData +{ + my $pointsz=$grph{PS}->[0]; + my ($min,$max,$factor,$range,$diff,$steps,$step,$bars); + my $floorflag=$grph{FLOORFLAG}->[0]; + my $horizontal=$grph{HORIZONTAL}->[0]; + + $factor=0; + + foreach my $set (@{$stats->{DATA}}) + { + next if !defined($set); + $#{$set}=$#{$stats->{LABELS}}; + my @tset=@{$set}; + + while (@tset) + { + my $y=shift(@tset); + last if !defined($y); + next if $y eq '.'; + + if ($y =~ m/\.(\d+)$/) + { + $factor=length($1) if length($1) > $factor; + } + } + } + + $stats->{YFACTOR}=$factor; + my $floor=(exists($grph{FLOOR}))?$grph{FLOOR}->[0]*10**$factor:undef; + $min=$max=$floor if defined($floor); + + foreach my $set (@{$stats->{DATA}}) + { + next if !defined($set); + my @tset=@{$set}; + + while (@tset) + { + my $y=shift(@tset); + last if !defined($y); + next if $y eq '.'; + + $y*=10**$factor; + $min=$max=$y if !defined($min); + + $min=$y if $y < $min; + $max=$y if $y > $max; + } + } + + if (exists($stats->{ANCHOR})) + { + foreach my $y (@{$stats->{ANCHOR}}) + { + next if !defined($y); + next if $y eq '.'; + my $y2=$y*10**$factor; + $min=$y2 if !defined($min) or $y2 < $min; + $max=$y2 if !defined($max) or $y2 > $max; + } + } + + if ($floorflag eq 'C' and $floor >= $min and $floor <= $max) + { + my $diffmax=$max-$floor; + my $diffmin=$floor-$min; + + $max=$floor+$diffmin if $diffmax < $diffmin; + $min=$floor-$diffmax if $diffmax > $diffmin; + } + + $bars=0; + + foreach my $bar (@{$stats->{BAR}}) + { + next if !defined($bar); + $bar=1 if $horizontal; # Only bars can be horizontal + $bars++ if $bar; + } + + $bars++ if $bars; + + foreach my $xlab (@{$stats->{LABELS}}) + { + next if !defined($xlab); + + if ($xlab=~m/^([A-Z]{3,3})\-(\d+)/i) + { + $xlab=ucfirst(lc($1)).'~'.(($2<30)?$2+2000:($2>100)?$2:$2+1900); + } + elsif ($xlab=~m/^(\d+)Q(\d+)/) + { + $xlab=$qname[$1-1].'~'.(($2<30)?$2+2000:($2>100)?$2:$2+1900); + } + elsif ($xlab=~m/^(\d+)H(\d+)/) + { + $xlab=$hname[$1-1].'~'.(($2<30)?$2+2000:($2>100)?$2:$2+1900); + } + elsif ($xlab=~m/^(\d+)\/(\d+)/) + { + $xlab=$mname[$1-1].'~'.(($2<30)?$2+2000:($2>100)?$2:$2+1900); + } + } + + my @lbnd=(-1,-1,-1,-1); + my @lbvl=('','','',''); + my $lbrows=-1; + + # X labels can be split over multiple rows (1-4) + + foreach my $j (0..scalar(@{$stats->{LABELS}})-1) + { + my @vals=split('~',$stats->{LABELS}->[$j]); + + foreach my $i (0..3) + { + if (!defined($vals[$i])) + { + $stats->{LABND}->[$j]->[$i]=-1; + next; + } + + $lbrows=$i if $i > $lbrows; + + if ($vals[$i] ne $lbvl[$i]) + { + # Differs + $lbvl[$i]=$vals[$i]; + $lbnd[$i]=$j; + $stats->{LABND}->[$j]->[$i]=$j; + } + else + { + $stats->{LABND}->[$lbnd[$i]]->[$i]=$j if $lbnd[$i] > -1; + } + } + + $stats->{LABELS}->[$j]=\@vals; + } + + $min=$max=0 if !defined($min); + $range=$max-$min; + $range=10*10**$factor,$min--,$max++ if $range/10**$factor < .01; + $min/=10**$factor; + $max/=10**$factor; + $stats->{YRANGE}=$range; + $stats->{XLABS}=$lbrows+1; + + $steps=10; + $steps=$grph{STEPS}->[0] if exists($grph{STEPS}); + my $ticksz=$range/($steps-1); + my $x=ceil(log10($ticksz)-1); + my $pow10x=10**$x; + $ticksz=ceil($ticksz/$pow10x)*$pow10x/10**$factor; + my $lo2=$ticksz*round($min/$ticksz); + my $hi2=$ticksz*round($max/$ticksz); + $lo2-=$ticksz if $min < $lo2; + $hi2+=$ticksz if $max >= $hi2; + $steps=sprintf("%0f",($hi2-$lo2)/$ticksz); + $stats->{YMIN}=$lo2; + $stats->{YMAX}=$hi2; + $stats->{YSTEP}=$ticksz; + $stats->{YSTEPS}=$steps; + # print STDERR "Min=$min, Max=$max, Lo=$lo2, Hi=$hi2, Sz=",$ticksz,", Ticks=$steps\n"; + # for (my $j=$lo2; $j<=$hi2; $j+=$ticksz) {print STDERR "$j\n";} + # print STDERR "\n"; + + # # $range=10*10**$factor,$min--,$max++ if $range==0; + # $stats->{YRANGE}=$range; + # $stats->{XLABS}=$lbrows+1; + # + # $steps=10; + # my $maxstep=11; + # $maxstep=$grph{STEPS} if exists($grph{STEPS}); + # $step=-1; + # + # while ($steps > 9) + # { + # $step++; + # $steps=int($range/(10**$step)+1); + # } + # + # $step=10**$step; + # $step/=10, $steps*=10 if $steps < 2; + # $step/=5, $steps*=5 if $steps < 5 and $steps < $maxstep; + # $step/=2, $steps*=2 if $steps < 7 and $steps < $maxstep; + # $step*=2, $steps=int($steps/2) if $steps > $maxstep; + # + # $stats->{YMIN}=int($min/$step)*$step/10**$factor; + # $stats->{YMAX}=(int($max/$step)+1)*$step/10**$factor; + # $stats->{YSTEP}=$step/10**$factor; + # $stats->{YMIN}-=$stats->{YSTEP}, $steps++ if $min < $stats->{YMIN}; + # $stats->{YMAX}+=$stats->{YSTEP}, $steps++ if $max > $stats->{YMAX}; + # $stats->{YSTEPS}=$steps; + $factor=0; + if ($grph{PDECIMALS}->[0] ne '') + { + $factor=$grph{PDECIMALS}->[0]; + } + else + { + $factor=length($1) if ($stats->{YSTEP}=~m/\.(\d+)$/); + } + $stats->{YMAX}=sprintf("%.*f",$factor,$stats->{YMAX}); + $stats->{XSTEPS}=scalar(@{$stats->{LABELS}}); + $stats->{XSTEPS}=1 if $horizontal; + $stats->{BARS}=$bars; + + my $ylab=length($stats->{YMAX})+1; + # $ylab+=2 if $grph{PDECIMALS} >= 0; + $xmarg=$ylab/2*1.2*$pointsz+($pointsz*.4); + $ymarg=0; + + foreach my $j (0..$lbrows) + { + $ymarg+=$pointsz+$j+($pointsz*.1); + } + +} + +sub sgn +{ + return 1 if $_[0]>=0; + return -1; +} + +sub log10 +{ + my $n = shift; + return 0 if !$n; + return log($n)/log(10); +} + +sub ceil +{ + my $n=shift; + my $i=int($n); + return ($n==$i)?$n:$i+1; +} + +sub round +{ + my $n=shift; + return(sprintf("%.0f",$n)); +} + +sub PlotData +{ + my $width=$grph{FRAME}->[0]; + my $height=$grph{FRAME}->[1]; + my $pointsz=$grph{PS}->[0]; + my $gthickness=$grph{THICKNESS}->[0]; + my $thickness=$grph{BORDER}->[0]; + my $symsize=$grph{SYMSIZE}->[0]; + my $background=$grph{BACKGROUND}; + my $key=$grph{KEYBOX}->[0]; + my $bars=$stats->{BARS}; + my $floor=(exists($grph{FLOOR}))?$grph{FLOOR}->[0]:$stats->{YMIN}; + my $horizontal=$grph{HORIZONTAL}->[0]; + my $topmarg=$pointsz+2; + $topmarg+=$pointsz if $key;# and !$horizontal; + my ($xgrph,$ygrph,@sync); + my ($xof,$yof,$tm,$lm)=(0,0,0,0); + + if ($grph{ORIGIN}->[0] ne '') + { + $xof=$lm=$grph{ORIGIN}->[0]; + $yof=$tm=$grph{ORIGIN}->[1]; + + if ($#{$grph{ORIGIN}} == 3) + { + $xof=$width-$grph{ORIGIN}->[2]; + $yof=$height-$grph{ORIGIN}->[3]; + } + } + + if ($horizontal) + { + my $t=$width; + $width=$height; + $height=$t; + # $t=$xmarg; + # $xmarg=$ymarg; + # $ymarg=$t; + $ymarg=0; + $xmarg=$pointsz; + $ygrph=($height-$xmarg*2-$xof); + $xgrph=($width-$pointsz*2.8-$yof); + $xmarg+=$lm; + $ymarg+=$tm; + } + else + { + $ygrph=($height-$ymarg-$topmarg-$yof); + $xgrph=($width-$xmarg-$xof); + } + + return if $stats->{YSTEPS} == 0 or $stats->{XSTEPS} == 0 or ($bars==0 and $horizontal); + my $ydiv=sprintf("%.2f",$ygrph/$stats->{YSTEPS}); + my $xdiv=sprintf("%.2f",$xgrph/$stats->{XSTEPS}); + my $barwidth=($bars)?($xdiv*.8)/$bars:0; + my $lbrows=$stats->{XLABS}-1; + my $span=sprintf("%.2f",$stats->{YSTEP}*$stats->{YSTEPS}); + # print STDERR "ydiv=$ydiv, xdiv=$xdiv, span=$span, YSTEP=$stats->{YSTEP}, YSTEPS=$stats->{YSTEPS}\n"; + if ($span == 0) + { + Log(1,"WARN: span is zero"); + return; + }; + + # Move to origin + + my $thick=$symsize; + my $thick2=$thick*2; + my $y60=1*$thick; + my $x60=.866*$thick; + my $x60_2=$x60*2; + my $y60_2=$y60*2; + + no warnings; + + $buf.=<< "EOF"; +.ds series2 \\M[$grph{SCOLOURS}->[1]]\\h'-${thick}p'\\D'C ${thick2}p'\\h'-${thick}p'\\M[] +.ds series3 \\Z'\\M[$grph{SCOLOURS}->[2]]\\h'${thick}p'\\D'P -${thick}p ${thick}p -${thick}p -${thick}p ${thick}p -${thick}p'\\M[]' +.ds series4 \\Z'\\M[$grph{SCOLOURS}->[3]]\\h'${thick}p'\\v'-${thick}p'\\D'P 0p ${thick2}p -${thick2}p 0p 0p -${thick2}p'\\M[]' +.ds series1 \\Z'\\M[$grph{SCOLOURS}->[0]]\\v'-${thick}p'\\D'P ${thick}p ${thick2}p -${thick2}p 0p'\\M[]' +.ds series6 \\M[$grph{SCOLOURS}->[5]]\\h'-${thick}p'\\D'C ${thick2}p'\\h'-${thick}p'\\M[] +.ds series5 \\Z'\\M[$grph{SCOLOURS}->[4]]\\h'${x60}p'\\v'-${y60}p'\\D'P -${x60_2}p 0p ${x60}p ${y60_2}p'\\M[]' +EOF + + use warnings; + + + $buf.=".ne ${height}p\n.nf\n.mk GRP:mk\n"; + $buf.=".in \\n[GRP:lefx]u\n\\Z'\\D't $grph{THICKNESS}->[0]p'\\m[$grph{TEXTCOLOUR}->[0]]\\M[$grph{LINECOLOUR}->[0]]'\\c\n"; + + Swap(\$width,\$height) if $horizontal; + + if ($grph{BGCOLOUR}->[0] ne '') + { + $buf.="\\Z@\\M[$grph{BGCOLOUR}->[0]]\\D'P ${width}p 0 0 ${height}p -${width}p 0 0 -${height}p'\\M[]@\\c\n"; + } + + if ($grph{BORDER}->[0]) + { + $buf.="\\Z@\\D't $grph{BORDER}->[0]p'@\\Z@\\m[$grph{BRDCOLOUR}->[0]]\\D'p ${width}p 0 0 ${height}p -${width}p 0 0 -${height}p'\\D't $grph{THICKNESS}->[0]p'\\m[]@\\c\n"; + } + + Swap(\$width,\$height) if $horizontal; + + $buf.=".fl\n"; + + + + $buf.=".sp +".($grph{BORDER}->[0])."p\n"; + $buf.=".in +".($grph{BORDER}->[0])."p\n"; + $buf.=".ll +".($grph{FRAME}->[0]-$grph{BORDER}->[0]*2)."p\n"; + # $buf.=".nf\n"; + + + if ($horizontal) + { + # Move to origin (lower left corner) + + $buf.=".mk grph\n\\Z'\\D't ${thickness}p''\\v'${xgrph}p+${topmarg}p'\\h'${xmarg}p'\\c\n"; + + # Background + + $buf.="\\Z'\\M[$grph{WALLCOLOUR}->[0]]\\D'P 0p -${xgrph}p ${ygrph}p 0 0 ${xgrph}p'\\M[]'\\c\n" if $grph{WALLCOLOUR}->[0]; + + # Base Line + + $buf.="\\Z'\\D'l ${ygrph}p 0''\\c\n"; + + # Floor Line + + $buf.="\\Z'"; + + if ($stats->{YMIN} < $floor and $stats->{YMAX} >= $floor) + { + # zero is between min/max so draw axis on zero + $buf.="\\h'".abs($stats->{YMIN}-$floor)/$span*$ygrph."p'" + } + + $buf.="\\D'l 0 -${xgrph}p''\\c\n"; + + # Ticks on X-axis + + $buf.="\\Z'"; + + for my $j (0..$stats->{YSTEPS}) + { + $buf.="\\h'${ydiv}p'" if $j; + $buf.="\\v'".($pointsz*.1+$thickness/2)."p'\\D'l 0 -".($pointsz*.1)."p'\\v'-".($thickness/2)."p'"; + $buf.="\\Z!\\D'l 0 -".(${xgrph}-$thickness)."p'!" if $grph{VGRID}; + } + + $buf.="'\\c\n"; + + my $barno=0; + my $bardiv=d2($xgrph/($bars)); + $barwidth=d2($pointsz*2); + $barwidth=$bardiv*.8 if $barwidth > $bardiv*.8; + + foreach (my $i=scalar(@{$stats->{DATA}})-1; $i>=0; $i--) # For each series + { + my $set=$stats->{DATA}->[$i]; + next if !defined($set); + next if !$stats->{BAR}->[$i]; + my @tset=@{$set}; + my ($oy,$ay,$cx,$ox); + my ($lbl,$txt)=split('~',$stats->{NAME}->[$i]); + + $cx=$bardiv/2; + + $buf.=".nr wi \\w'$lbl'\n"; + my $baseline=($stats->{YMIN}<$floor)?((($stats->{YMIN}-$floor)/$span)*$ygrph):0; + # $oy=((($tset[$ox]-$stats->{YMIN})/$span)+$stats->{YMIN} )*$ygrph; + $oy=(($tset[0]-$stats->{YMIN})/$span)*$ygrph; + # $oy=((($tset[$ox]-$stats->{YMIN})/$span)-$stats->{YMIN})*$ygrph; + my $s=($i % 6) + 1; + + my $cx2=sprintf("%.2f",($barno*$bardiv)+($bardiv/2)-($barwidth/2)); + my $dep; + my $colo; + $sync[$i]=$topmarg+$xgrph-$cx-$cx2-$barwidth/2-$pointsz*.4; + $barno++; + + my $j=0; # Horizontal bars have multiple series with one value in each + next if !defined($tset[$j]); + next if $tset[$j] eq '.'; + my $y=(($tset[$j]-$stats->{YMIN})/$span)*$ygrph; + $dep=d2($oy+$baseline); + $dep=sgn($dep)*.5 if abs($dep) < 1; + if ($grph{NEGCOLOUR}->[0]) + { + $colo=($dep < 0)?$grph{NEGCOLOUR}->[$i]:$grph{SCOLOURS}->[$i]; + } + else + { + $colo=$grph{SCOLOURS}->[$i]; + } + # my $y=((($tset[$j]-$stats->{YMIN})/$span)+$stats->{YMIN} )*$ygrph; + # my $y=((($tset[$j]-$stats->{YMIN})/$span)-$stats->{YMIN})*$ygrph; + + my ($contrast,$contrastnd); + $contrast=$grph{CONTRAST}->[$i]; + if (defined($contrast)) + { + $contrast="\\m[$contrast]"; + $contrastnd="\\m[]"; + } + else + { + $contrast=$contrastnd=''; + } + + if ($dep < 0) + { + if ($pointsz < $barwidth) + { + $buf.=".ie \\n[wi]u+2p<".abs(${dep})."p .ds lb $contrast\\h'1p'$lbl$contrastnd\n"; + $buf.=".el .ds lb \\h'-\\n[wi]u-2p'$lbl\n"; + } + else + { + $buf.=".ds lb \\h'-\\n[wi]u-1p'$lbl\n"; + } + } + else + { + if ($pointsz < $barwidth) + { + $buf.=".ie \\n[wi]u+2p>".abs(${dep})."p .ds lb \\h'1p'$lbl\n"; + $buf.=".el .ds lb $contrast\\h'-\\n[wi]u-2p'$lbl$contrastnd\n"; + } + else + { + $buf.=".ds lb \\h'1p'$lbl\n"; + } + } + $buf.="\\Z'"; + $buf.="\\h'${oy}p'\\v'-${cx}p'"; + $buf.="\\m[$colo]" if $grph{COLOURED}->[0]; + + $buf.="\\Z~\\D't 0p'\\M[$colo]\\v'-${cx2}p'\\D'P 0 -${barwidth}p -${dep}p 0 0 ${barwidth}p ${dep}p 0'\\M[]\\D't ${thickness}p'~"; + $buf.="\\Z~\\v'-".($cx2+$barwidth/2-($pointsz*.4))."p'\\h'".(sgn($dep ))."p'"; + + $buf.="\\*[lb]"; + $buf.="~"; + # $buf.="\\Z~\\D't 0p'\\M[$colo]\\v'-${cx2}p'\\D'P ${barwidth}p 0p 0p ${dep}p -${barwidth}p 0p 0p -${dep}p'\\M[]\\D't ${thickness}p'~"; + # $buf.="\\v'-${cx}p'\\h'".sprintf("%.3f",$y-$oy)."p'"; + # $buf.="\\D'l ${cx}p ".sprintf("%.3f",$oy-$y)."p'"; + + $buf.="\\m[]" if $grph{COLOURED}->[0]; + $oy=$y; + + $dep=$oy+$baseline; + # if (exists($grph{POSCOLOUR})) + # { + # $colo=($dep < 0)?$grph{NEGCOLOUR}->{NAME}:$grph{POSCOLOUR}->{NAME} + # } + # else + # { + # $colo=$grph{COLOURS}->[$i]->{NAME}; + # } + # $buf.="\\Z~\\D't 0p'\\M[$colo]\\v'-${cx2}p'\\D'P 0 -${barwidth}p -${dep}p 0 0 ${barwidth}p ${dep}p 0'\\M[]\\D't ${thickness}p'~"; + + $buf.="'\\c\n"; + } + + # Now bottom labels + + my $y=$stats->{YMIN}; + my $factor=0; + my $pattern="%.*f"; + if ($grph{PDECIMALS}->[0] ne '') + { + # $pattern.='%%'; + $factor=$grph{PDECIMALS}->[0]; + } + else + { + $factor=length($1) if ($stats->{YSTEP}=~m/\.(\d+)$/); + $factor=1 if ($stats->{YMAX}-$stats->{YMIN}) < $stats->{YSTEPS}; + } + + $buf.="\\v'".($pointsz*1.2)."p'\\c\n"; + + foreach my $j (0..$stats->{YSTEPS}) + { + my $dy=sprintf($pattern,$factor,$y); + $buf.=".nr wi \\w'$dy'\n"; + $buf.="\\h'-\\n[wi]u/2u'$dy\\h'${ydiv}p-(\\n[wi]u/2u)'\\c\n"; + $y+=$stats->{YSTEP}; + } + + + if ($grph{KEYBOX}->[0]) + { + my $marg=$symsize*4; + my $ps=$grph{PS}->[0]; + + my $boxlabels=join("\t",@{$grph{BOXLABELS}}); + my $boxheads=join("\t",@{$grph{BOXHEADS}}); + my $boxtabs=join(' ',@{$grph{BOXTABS}}); + $buf.=".sp |\\n[GRP:mk]u+$grph{BOXFRAME}->[1]p\n.in +$grph{BOXFRAME}->[0]p\n.ta $boxtabs\n.vs\n.in +(4p)\n\\fB$boxheads\\fP\n.sp .2\n.in -(4p)\n"; + my $y2=0; + # $buf.=".sp ${pointsz}p\n" if $grph{SYNC}; + + foreach my $i (0..scalar(@{$stats->{NAME}})-1) + { + next if !defined($stats->{NAME}->[$i]); + my ($lbl,$txt)=split('~',$stats->{NAME}->[$i]); + + $txt=~tr[^][\t]; + + if ($grph{SYNC}->[0]) + { + $buf.=".sp |\\n[GRP:mk]u+$sync[$i]p-2p\n"; + } +# else +# { + $buf.="\\v'-".($pointsz*.4)."p'\\h'-${thick}p'\\Z!\\M[$grph{SCOLOURS}->[$i]]\\v'-${thick}p'\\D'P ${thick2}p 0 0 ${thick2}p -${thick2}p 0'!\\h'${thick2}p'\\v'".($pointsz*.4)."p'\\~\\c\n" if !$grph{POSCOLOUR}->[0]; + $buf.="$txt\n"; + $buf.="\\M[]\\c\n" if !$grph{POSCOLOUR}->[0]; +# } + # print STDERR "$sync[$i] " + # $buf.="\\v'-".($pointsz*.4)."p'\\D'l ".(${symsize}*4)."p 0p'\\Z'\\h'-".(${symsize}*2)."p'\\*[series$s]'\\v'".($pointsz*.4)."p'\\~\\c\n"; + # $buf.=".in +${marg}p\n.sp -1\n$txt\\h'".(${symsize}*2)."p'\n.sp $fldk->{SKIPAFTER}p\n.in -${marg}p\n"; + } + } + + # print STDERR "\n"; + } + else + { + # Move to origin (lower left corner) + + $buf.=".mk grph\n\\Z'\\D't ${thickness}p''\\v'${ygrph}p+${topmarg}p+${tm}p'\\h'${xmarg}p+${lm}p'\\c\n"; + + # Background + + $buf.="\\Z'\\M[$grph{WALLCOLOUR}->[0]]\\D'P 0p -${ygrph}p ${xgrph}p 0 0 ${ygrph}p'\\M[]'\\c\n" if $grph{WALLCOLOUR}->[0]; + + # Left line + + $buf.="\\Z'\\L'-${ygrph}p''\\c\n"; + + # Bottom line + + $buf.="\\Z'"; + + if ($stats->{YMIN} < $floor and $stats->{YMAX} >= $floor) + { + # zero is between min/max so draw axis on zero + $buf.="\\v'-".abs($stats->{YMIN}-$floor)/$span*$ygrph."p'" + } + + $buf.="\\l'${xgrph}p''\\c\n"; + + # Label Y axis + + # ticks + + $buf.="\\Z'"; + + for my $j (0..$stats->{YSTEPS}) + { + $buf.="\\v'-${ydiv}p'" if $j; + $buf.="\\h'-".($pointsz*.1+$thickness/2)."p'\\l'".($pointsz*.1)."p'\\h'".($thickness/2)."p'"; + $buf.="\\Z!\\D'l ".(${xgrph}-$thickness)."p 0'!" if $grph{HGRID}->[0]; + } + + $buf.="'\\c\n"; + + # Label X axis + + # ticks + + foreach my $j (0..$lbrows) + { + my $sofar=0; + my $fi=0; + my $targ=0; + my $nd; + my $i; + + for ($i=0; $i{LABELS}}); $i=$nd+1) + { + $nd=$stats->{LABND}->[$i]->[$j]; + $nd=$i if $nd < 0; + $sofar+=($nd-$i)*$xdiv; + + my $mi=($i!=$nd)?$nd:int(($i-$fi)/2)+$fi; + my $lblsz=length($stats->{LABELS}->[$mi]->[$j] || '')*$pointsz*.6; + + if ($lblsz==0 or ($lblsz) > $xdiv+$sofar) + { + $fi=$nd+1 if $lblsz==0; + $sofar+=$xdiv; + $stats->{LABELS}->[$nd]->[$j]='.' if $nd > $i; + next; + } + else + { +# print STDERR "$stats->{LABELS}->[$mi]->[$j]: sofar $sofar: lblsz $lblsz: xdiv $xdiv\n"; + $sofar=0; + foreach my $t ($fi..$nd) + { + $stats->{LABELS}->[$t]->[$j]='' if $stats->{LABELS}->[$t]->[$j] ne '.' and $t != $mi; + } + $fi=$nd+1; + } + + } + + foreach my $i ($fi..$#{$stats->{LABELS}}) + { + $stats->{LABELS}->[$i]->[$j]=''; + } + + } + + $buf.="\\Z'"; + + for my $j (0..$stats->{XSTEPS}-1) + { + $buf.="\\h'${xdiv}p'" if $j; + $buf.="\\h'".(${xdiv}/2)."p'" if $j==0; + next if $stats->{LABELS}->[$j]->[0] eq ''; + $buf.="\\D'l 0 ".($pointsz*.3)."p'\\v'-".($pointsz*.3)."p'"; + $buf.="\\Z!\\D'l 0 -".(${ygrph}-$thickness)."p'!" if $grph{VGRID}->[0]; + } + + $buf.="'\\c\n"; + + # $buf.=series + + # First any bars? + my $barno=0; + + foreach my $i (0..scalar(@{$stats->{DATA}})-1) + { + my $set=$stats->{DATA}->[$i]; + next if !defined($set); + next if !$stats->{BAR}->[$i]; + my @tset=@{$set}; + my ($oy,$ay,$cx,$ox); + + $cx=$xdiv/2+$barwidth/2; + + for ($ox=0; $ox<=$#tset; $ox++) + { + last if $tset[$ox] ne '.'; + $cx+=$xdiv; + } + + if (!defined($tset[$ox]) or $tset[$ox] eq '.') + { + $stats->{NAME}->[$i]=undef; + next; + } + + $buf.="\\Z'"; + my $baseline=($stats->{YMIN}<$floor)?((($stats->{YMIN}-$floor)/$span)*$ygrph):0; + # $oy=((($tset[$ox]-$stats->{YMIN})/$span)+$stats->{YMIN} )*$ygrph; + $oy=(($tset[$ox]-$stats->{YMIN})/$span)*$ygrph; + # $oy=((($tset[$ox]-$stats->{YMIN})/$span)-$stats->{YMIN})*$ygrph; + my $s=($i % 6) + 1; + + $buf.="\\v'-${oy}p'\\h'${cx}p'"; + $cx=0; + my $cx2=sprintf("%.3f",($barno*$barwidth)-($bars*$barwidth/2)); + my $dep; + my $colo; + + foreach my $j ($ox+1..$stats->{XSTEPS}) + { + $cx+=$xdiv; + next if !defined($tset[$j]); + next if $tset[$j] eq '.'; + my $y=(($tset[$j]-$stats->{YMIN})/$span)*$ygrph; + $dep=$oy+$baseline; + $dep=sgn($dep)*.5 if abs($dep) < 1; + if ($grph{POSCOLOUR}->[0]) + { + $colo=($dep < 0)?$grph{NEGCOLOUR}->[0]:$grph{POSCOLOUR}->[0]; + } + else + { + $colo=$grph{SCOLOURS}->[$i]; + } + # my $y=((($tset[$j]-$stats->{YMIN})/$span)+$stats->{YMIN} )*$ygrph; + # my $y=((($tset[$j]-$stats->{YMIN})/$span)-$stats->{YMIN})*$ygrph; + $buf.="\\m[$colo]" if $grph{COLOURED}->[0]; + + $buf.="\\Z~\\D't 0p'\\M[$colo]\\h'${cx2}p'\\D'P ${barwidth}p 0p 0p ${dep}p -${barwidth}p 0p 0p -${dep}p'\\M[]\\D't ${thickness}p'~"; + $buf.="\\h'${cx}p'\\v'".sprintf("%.3f",$oy-$y)."p'"; + # $buf.="\\D'l ${cx}p ".sprintf("%.3f",$oy-$y)."p'"; + + $buf.="\\m[]" if $grph{COLOURED}->[0]; + $oy=$y; + $cx=0; + } + + $dep=$oy+$baseline; + if ($grph{POSCOLOUR}->[0]) + { + $colo=($dep < 0)?$grph{NEGCOLOUR}->[0]:$grph{POSCOLOUR}->[0]; + } + else + { + $colo=$grph{SCOLOURS}->[$i]; + } + $buf.="\\Z~\\D't 0p'\\M[$colo]\\h'${cx2}p'\\D'P ${barwidth}p 0p 0p ${dep}p -${barwidth}p 0p 0p -${dep}p'\\M[]\\D't ${thickness}p'~"; + + $buf.="'\\c\n"; + $barno++; + } + + # Now the graph lines + + foreach my $i (0..scalar(@{$stats->{DATA}})-1) + { + my $set=$stats->{DATA}->[$i]; + next if !defined($set); + next if $stats->{BAR}->[$i]; + my @tset=@{$set}; + my ($oy,$ay,$cx,$ox); + + $cx=$xdiv/2; + + for ($ox=0; $ox<=$#tset; $ox++) + { + last if $tset[$ox] ne '.'; + $cx+=$xdiv; + } + + if (!defined($tset[$ox]) or $tset[$ox] eq '.') + { + $stats->{NAME}->[$i]=undef; + next; + } + + $buf.="\\Z'"; + $buf.="\\m[$grph{SCOLOURS}->[$i]DK]" if $grph{COLOURED}->[0]; + $buf.="\\Z!\\D't ${gthickness}p'!"; + $oy=(($tset[$ox]-$stats->{YMIN})/$span)*$ygrph; + my $s=($i % 6) + 1; + + if (exists($stats->{ANCHOR}) and $stats->{ANCHOR}->[$i] ne '.') + { + $ay=(($stats->{ANCHOR}->[$i]-$stats->{YMIN})/$span)*$ygrph; + $buf.="\\v'-${ay}p'"; + if ($background and $i == 0) + { + $buf.="\\Z'\\D't 0p'\\M[$grph{SCOLOURS}->[$i]DK]\\D'P ${cx}p ".sprintf("%.3f",$ay-$oy)."p 0p ${oy}p -${cx}p 0p 0p -${ay}p'\\M[]\\D't ${gthickness}p''"; + } + $buf.="\\D'l ${cx}p ".sprintf("%.3f",$ay-$oy)."p'"; + $cx=0; + } + else + { + $buf.="\\v'-${oy}p'\\h'${cx}p'"; + $cx=0; + } + + foreach my $j ($ox+1..$stats->{XSTEPS}-1) + { + $cx+=$xdiv; + next if !defined($tset[$j]); + next if $tset[$j] eq '.'; + my $y=(($tset[$j]-$stats->{YMIN})/$span)*$ygrph; + if ($background and $i == 0) + { + $buf.="\\Z'\\D't 0p'\\M[$grph{SCOLOURS}->[$i]DK]\\D'P ${cx}p ".sprintf("%.3f",$oy-$y)."p 0p ${y}p -${cx}p 0p 0p -${oy}p'\\M[]\\D't ${gthickness}p''"; + } + + $buf.="\\D'l ${cx}p ".sprintf("%.3f",$oy-$y)."p'"; + + $oy=$y; + $cx=0; + } + + $buf.="\\m[]" if $grph{COLOURED}->[0]; + $buf.="'\\c\n"; + + # Draw points + + if ($symsize) + { + $cx=$xdiv/2; + + for ($ox=0; $ox<=$#tset; $ox++) + { + last if $tset[$ox] ne '.'; + $cx+=$xdiv; + } + + if (!defined($tset[$ox]) or $tset[$ox] eq '.') + { + $stats->{NAME}->[$i]=undef; + next; + } + + $buf.="\\Z'"; + $buf.="\\m[$grph{SCOLOURS}->[$i]]" if $grph{COLOURED}->[0]; + $oy=(($tset[$ox]-$stats->{YMIN})/$span)*$ygrph; + + if (exists($stats->{ANCHOR}) and $stats->{ANCHOR}->[$i] ne '.') + { + $ay=(($stats->{ANCHOR}->[$i]-$stats->{YMIN})/$span)*$ygrph; + $buf.="\\v'-${ay}p'"; + $buf.="\\h'${cx}p'\\v'".sprintf("%.3f",$ay-$oy)."p'"; + $cx=0; + } + else + { + $buf.="\\v'-${oy}p'\\h'${cx}p'"; + $cx=0; + } + + my $sym=''; + $sym="\\*[series$s]" if !$background or $i != 0; + $buf.=$sym; + + foreach my $j ($ox+1..$stats->{XSTEPS}-1) + { + $cx+=$xdiv; + next if !defined($tset[$j]); + next if $tset[$j] eq '.'; + my $y=(($tset[$j]-$stats->{YMIN})/$span)*$ygrph; + $buf.="\\h'${cx}p'\\v'".sprintf("%.3f",$oy-$y)."p'$sym"; + $oy=$y; + $cx=0; + } + + $buf.="\\m[]" if $grph{COLOURED}; + $buf.="'\\c\n"; + } + } + + # $buf.=X Labels + + $buf.=".nf\n.sp |\\n[grph]u+${ygrph}p+${topmarg}p+${tm}p\n.vs $grph{VS}->[0]p\n"; + + foreach my $j (0..$lbrows) + { + $buf.="\\m[$grph{TEXTCOLOUR}->[0]]\\c\n"; + $buf.=".ta "; + my $tab=$xmarg; + my $tabln=''; + my $divs=1; + my $nd=0; + + for (my $i=0; $i{LABELS}}); $tab+=$divs*$xdiv, $i=$nd+1) + { + # next if $xskip != 1 and ($i+1) % $xskip != 1; + $nd=$stats->{LABND}->[$i]->[$j]; + $nd=$i if $nd < 0; + $divs=$nd-$i+1; + $i=$nd; + my $vals=$stats->{LABELS}->[$i]; + next if !defined($vals->[$j]) or $vals->[$j] eq '' or $vals->[$j] eq '.'; + $buf.="".($tab+($divs*$xdiv)/2)."pC "; + $tabln.="\t$vals->[$j]"; + } + + + $buf.="\n\\s'+${j}'$tabln\\s'-${j}'\n"; + } + + $buf.=".vs\n.fi\n.ta ".($xmarg+$lm-$pointsz*.2-$thickness/2)."pR\n"; + my $y=$stats->{YMIN}; + my $factor=0; + my $pattern="%.*f"; + if ($grph{PDECIMALS}->[0] ne '') + { + # $pattern.='%%'; + $factor=$grph{PDECIMALS}->[0]; + } + else + { + $factor=length($1) if ($stats->{YSTEP}=~m/\.(\d+)$/); + } + + foreach my $j (0..$stats->{YSTEPS}) + { + $buf.=".sp |\\n[grph]u+".(${ygrph}-$ydiv*$j+$pointsz/4+$topmarg+${tm})."p\n\t".sprintf($pattern,$factor,$y)."\n"; + $y+=$stats->{YSTEP}; + } + + $buf.="\\m[]\\D't ${thickness}p'\n"; + + if (!$grph{KEYBOX}->[0]) + { + $buf.=".sp |\\n[grph]u+${pointsz}p+${tm}p\n.in +${xmarg}p+${lm}p+6p\n"; + foreach my $i (0..scalar(@{$stats->{NAME}})-1) + { + next if !defined($stats->{NAME}->[$i]); + my $s=($i % 6)+1; + if ($stats->{BAR}->[$i]) + { + $buf.="\\v'-".($pointsz*.4)."p'\\h'-${thick}p'\\Z!\\M[$grph{SCOLOURS}->[$i]]\\v'-${thick}p'\\D'P ${thick2}p 0 0 ${thick2}p -${thick2}p 0'!\\h'${thick2}p'\\v'".($pointsz*.4)."p'\\~$stats->{NAME}->[$i]\\0\\M[]\n"; + } + else + { + my $symsize=2; + $buf.="\\Z'\\D't 2p'\\m[$grph{SCOLOURS}->[$i]DK]'"; + $buf.="\\v'-".($pointsz*.4)."p'\\D'l ".(${symsize}*4)."p 0p'\\Z'\\h'-".(${symsize}*2)."p'\\m[]\\*[series$s]'\\v'".($pointsz*.4)."p'\\~$stats->{NAME}->[$i]\\h'".(${symsize}*2)."p'\n"; + } + } + } + else + { + my $marg=$symsize*4; + + my $boxlabels=join("\t",@{$grph{BOXLABELS}}); + my $boxheads=join("\t",@{$grph{BOXHEADS}}); + my $boxtabs=join(' ',@{$grph{BOXTABS}}); + + $buf.=".fl\n.vs 0\n.sp |\\n[GRP:mk]u+$grph{BOXFRAME}->[1]p\n.in +$grph{BOXFRAME}->[0]p\n.ta $boxtabs\n.vs $grph{VS}->[0]p\n.in +(1m+4p)\n\\fB$boxheads\\fP\n.sp -.2\n.in -(1m+4p)\n"; + + # $buf.=".in +".($fldk->{THICKNESS}->{LEFT}*.5)."p\n.sp -1v\n.sp $fldk->{INDENT}->{TOP}p\n.ll +$fldk->{POSITION}->{WIDTH}p\n"; + foreach my $i (0..scalar(@{$stats->{NAME}})-1) + { + next if !defined($stats->{NAME}->[$i]); + my $s=($i % 6)+1; + $buf.="\\v'-".($pointsz*.4)."p'\\D'l ".(${symsize}*4)."p 0p'\\Z'\\h'-".(${symsize}*2)."p'\\*[series$s]'\\v'".($pointsz*.4)."p'\\~\\c\n"; + $buf.=".in +${marg}p\n.sp -1\n$stats->{NAME}->[$i]\\h'".(${symsize}*2)."p'\n.in -${marg}p\n"; + } + } + } + + $buf.=".fl\n.ev\n"; + ### $srcur=undef; + # outbuf($buf); +} + +sub d2 +{ + return sprintf("%.2f",$_[0]); +} + +sub Swap +{ + my $v1=shift; + my $v2=shift; + + my $t=$$v1; + $$v1=$$v2; + $$v2=$t; +} diff --git a/bin/custom b/bin/custom new file mode 100755 index 0000000..032cb03 --- /dev/null +++ b/bin/custom @@ -0,0 +1,57 @@ +#!/bin/sh + +# From a single byte in hexadecimal per line to lines ending with 0a +# (hex for '\n'). Ex: 61 62 63 0a +# Required to easily match (and remove) multi-byte characters. +regroup_lines() awk ' + BEGIN { + line_start=1 + } + + { + if (line_start == 1) + line = $1; + else + line = line " " $1; + + line_start = 0; + if ($1 == "0a") { + print line; + line_start = 1 + } + } + + END { + if (line_start == 0) + print line + } + ' + +uppercase() tr "[a-z]" "[A-Z]" + +# One column decimal to plain text. +from_dec() awk '{ printf ("%c", $1 + 0) }' + +# Replace spaces by line returns, outputs a single column. +spaces_to_line_returns() tr " " "\n" + +# Convert input into hexadecimal and a single byte per line. +to_hex_one_column() { od -An -tx1 | awk '{for(i=1;i<=NF;i++){ print $i }}'; } + +# One column hexa to one column decimal. +hex_to_dec() { { echo "obase=10;ibase=16;" ; cat ; } | bc ; } + +# Reverse hexadecimal (with space separators) to original value. +from_hex() { spaces_to_line_returns | uppercase | hex_to_dec | from_dec; } + +# Replace unbreakable spaces by '\ '. +replace_unbreakable_spaces() sed "s/c2 a0/5c 20/g" + +custom_mods(){ + to_hex_one_column | # Input to hexadecimal, 1-byte representation per line. + regroup_lines | # From 1-byte to x-byte lines with space separators. + replace_unbreakable_spaces | # Replace unbreakable spaces by '\ '. + from_hex # Convert back from hex (x-byte per line, space separator). +} + +custom_mods diff --git a/histoire-de-ta-bêtise.ms b/histoire-de-ta-bêtise.ms index e726983..b58872d 100644 --- a/histoire-de-ta-bêtise.ms +++ b/histoire-de-ta-bêtise.ms @@ -1,5 +1,6 @@ .so macros.ms .so book-summary-macros.ms +.mso fr.tmac .TITLE Histoire de ta bêtise .AUTHOR François Bégaudeau .SUMMARIZED_BY_FR Philippe Pittoli @@ -87,6 +88,61 @@ J'ajoute volontiers que ce délire s'est désormais répandu à bien des milieux Ce besoin de tout voir sur un prisme moral, devoir se positionner pour ou contre des idées, une vraie immaturité émotionnelle. .FOOTNOTE2 +La bourgoisie matraque les prolo, mais absorbe le situationnisme, un million de migrants pour l'Allemagne pour sauver sa démographie, le management collaboratif pour absorber la délibération égalitaire, etc. +La liste des récupérations est longue. +Les discours subversifs sont infantilisés, en les mettant en scène pour les humilier. +Parce que le prolo fait peur, le bourgeois devient « patriarche cool » et donne congés payés, allocations chômage, bourses scolaires, soins. +Tout ça pour cacher que le système a des cadences laborieuses, énormément de chômage, une ségrégation scolaire, des métiers qui meurtrissent. +Mais comme le travail ne crée plus autant de marges, on taxe davantage le travail, le coût de la vie augmente pour nourrir la marge du bourgeois. +En page 65, Bégaudeau annonce la couleur : dès que l'on rentre dans une phase difficile économiquement, le bourgeois devient complètement libéral, passe à +.I "En Marche" +et met de côté le Parti Socialiste qui n'était qu'une +.B névrose . + +Page 66, référence à Coluche : le travailleur pauvre c'est pas plus mal que si c'était pire. + +Page 68, critique de l'hypocrisie. +Plan social, sauvegarde de l'emploi => licenciement. +Restructuration => compression de personnel. +Modernisation => privatisation. +Le bourgeois pense parfois sincèrement ses conneries, par conséquent même quand il ne ment pas, il paraît creux. +Aussi, on parle davantage de l'esthétique bourgeois que du fond, peut-être que l'hypocrisie serait trop flagrante. + +Page 80, Bégaudeau parle de Vanessa Paradis, qui n'est pas connue pour ses œuvres pas-si-mémorables, mais parce qu'elle apparaît dans plus de 150 couvertures de magazines. +Elle est « connue pour être célèbre ». +Les magazines ne reflètent pas sa notoriété, ils la crée de toute pièce\*[*]. +.FOOTNOTE1 +Et ceci me fait fortement penser à Macron. +.FOOTNOTE2 + +Tout au long du livre, Bégaudeau rappelle que l'art est tout autant apprécié qu'il raconte quelque chose sur nous-même. +On apprécie une œuvre autant qu'on s'apprécie nous-même aimant cette œuvre. + +Page 82, Bégaudeau est visionnaire : il a déjà capté qu'on allait conditionner les salaires des profs à leur mérite, à leurs performances, tout simplement parce qu'il est insupportable pour les bourgeois qu'une personne touche un salaire simplement pour faire leur travail (plutôt que pour se soumettre à la volonté de quelqu'un, je suppose). +La valeur d'un geste doit être liée à une valeur marchande, sinon il ne la voit pas, il ne comprend pas. +Le bourgeois ne voit d'ailleurs plus que le commerce, et son monde devient flou : le sourire de la boulangère est-il sincère ou est-ce un argument de vente\*[*] ? +.FOOTNOTE1 +Cela rappelle fortement le livre +.I "Religion poisons everything" " »." "« " +.FOOTNOTE2 + +Page 95 : Macron n'est pas moderne, il est neuf. +Très juste. + +Page 100 : le bourgeois a peur des extrêmes, lui est dans la nuance. +Sauf bien évidemment pour parler des extrêmes, qui sont extrêmes de manière absolue. +Ou bien du fait qu'un patron soit nécessaire et doive gagner plus que ses employés. +Ou encore que la sortie de l'euro provoquera une troisième guerre mondiale. +Bien entendu, il faut réduire les dépenses publiques. +Bien entendu également, la France est une démocratie, etc\*[*]. +.FOOTNOTE1 +Fait intéressant, Bégaudeau parlait déjà en janvier 2019 des vaccins, en disant que toute remise en cause tenait forcément du complotisme pour un petit bourgeois. +Je trouve cela assez juste, dans la mesure où se poser simplement la question est mal vu quand bien même la conclusion après une étude rationnelle de la situation amènerait à vouloir un statu quo, c'est-à-dire à être d'accord avec leur usage tel qu'il est fait actuellement. +Le simple fait de poser une question est déjà presque réprimandé, et c'est un problème. +.FOOTNOTE2 +Bref, pour quelqu'un de modéré, il y a comme des absolus indépassables, qui ne peuvent être remis en question, qui ne peuvent même pas être discutés. +Pour quelqu'un qui se dit modéré, cela fait un peu tâche. + .SECTION Expressions vides de sens .PARAGRAPH_INDENTED Bégaudeau critique les expressions toutes faites, sans substance, qui tentent d'attaquer ou diminuer un point de vue. @@ -135,6 +191,14 @@ Ce passage montre son point de vue, et c'est un peu tout. Autre exemple, à un moment il parle du racisme engendré par le capitalisme. Autant la prédation du libéralisme me semble évidente, autant le racisme du capitalisme beaucoup moins. +Page 66 à 67, Bégaudeau parle des attentats de 2015, le fait que si on parle de « banlieue islamiste » c'est forcément pour parler des « arabes ». +Pour lui, se désolidariser des islamistes et dire fermement qu'on ne veut pas de ça parce qu'on s'attaque à nos valeurs, c'est en réalité être raciste. +Je ne suis pas d'accord, je pense que c'est un faux dilemme un peu ridicule. +Il va même jusqu'à dire qu'on ne considérerait pas le français qui ne boit pas comme un français, ce qui est complètement abusé selon moi. +La culture islamiste, on voit quand même à quoi ça ressemble (voile intégral pour les femmes, interdiction de la musique, etc.), et tu n'es pas islamiste-compatible juste parce que tu ne bois pas. +C'est quand même dommage d'avoir un livre par ailleurs plutôt lucide et modéré pour se vautrer dans des avis tranchés d'une façon aussi absurde. +Tout comme, page 75, il parle de communautarisme (sous-entendu presque racial) du bourgeois, qui préférerait presque être métisse pour moins qu'on reconnaisse son milieu très fermé : la formulation est au moins maladroite. + .SECTION Conclusion .PARAGRAPH_INDENTED À plusieurs reprise Bégaudeau rappelle l'hypocrisie ambiante. diff --git a/macros.ms b/macros.ms index 71021ad..e2bf766 100644 --- a/macros.ms +++ b/macros.ms @@ -18,6 +18,7 @@ accumulate .defcolor darkblue rgb 0.3 0.3 0.7 .defcolor darkred rgb 0.7 0.3 0.3 .defcolor black rgb 0 0 0 +.defcolor color_box rgb 1 1 .6 . . \" with semantic .defcolor citation rgb 0.4 0.4 0.4 @@ -25,6 +26,7 @@ accumulate .defcolor explanation rgb 0.7 0.4 0.4 .defcolor explanationbar rgb 0.8 0.3 0.3 . +.defcolor specialcolor_command rgb 0.7 0.3 0.3 .defcolor specialcolor_type rgb 0.6 0.3 0.5 .defcolor specialcolor_constructor rgb 0.1 0.5 0.2 .defcolor specialcolor_module rgb 0.1 0.5 0.2 @@ -34,6 +36,7 @@ accumulate .defcolor specialcolor_shine rgb 0.3 0.3 0.7 . . \" SIZES +.nr specialsize_command 10 .nr specialsize_type 8 .nr specialsize_constructor 8 .nr specialsize_module 8 @@ -43,6 +46,7 @@ accumulate .nr specialsize_shine 11 . . \" FONTS +.ds specialfont_command CW .ds specialfont_type CW .ds specialfont_constructor CW .ds specialfont_module CW @@ -165,8 +169,14 @@ accumulate . . .de FRAC +.ie '\\$3'' \{\ \v'-.7m\s[\\n(.s*6u/10u]+.7m'\\$1\v'-.7m\s0+.7m'\ \(f/\s[\\n(.s*6u/10u]\\$2\s0 +\} +.el \{\ +\v'-.7m\s[\\n(.s*6u/10u]+.7m'\\$1\v'-.7m\s0+.7m'\ +\(f/\s[\\n(.s*6u/10u]\\$2\s0\\$3 +\} .. .de FOOTNOTE_TO_COLUMN_WIDTH .nr pg@fn-colw \\n[pg@colw] \" footnotes' column width @@ -187,6 +197,7 @@ accumulate . \" Fonts and colors. . .de SPECIAL_WORDS +.ie !'\\$3'' \\$3\c .nr current_size \\n[.s] \" Current point size. .gcolor specialcolor_\\*[semantictoken] . @@ -220,39 +231,40 @@ accumulate .b2 .. .de COMMANDNAME -.I "\\$1" "\\$2" +.ds semantictoken command +.SPECIAL_WORDS \\$@ .. .de FUNCTION .ds semantictoken function -.SPECIAL_WORDS "\\$1" "\\$2" +.SPECIAL_WORDS \\$@ .. .de TYPE .ds semantictoken type -.SPECIAL_WORDS "\\$1" "\\$2" +.SPECIAL_WORDS \\$@ .. .de TYPECLASS .I "\\$1" "\\$2" .. .de OPERATOR .ds semantictoken operator -.SPECIAL_WORDS "\\$1" "\\$2" +.SPECIAL_WORDS \\$@ .. .de QUESTION .ds semantictoken question -.SPECIAL_WORDS "\\$1" "\\$2" +.SPECIAL_WORDS \\$@ \h'5p' .. .de CONSTRUCTOR .ds semantictoken constructor -.SPECIAL_WORDS "\\$1" "\\$2" +.SPECIAL_WORDS \\$@ .. .de MODULE .ds semantictoken module -.SPECIAL_WORDS "\\$1" "\\$2" +.SPECIAL_WORDS \\$@ .. .de SHINE .ds semantictoken shine -.SPECIAL_WORDS "\\$1" "\\$2" +.SPECIAL_WORDS \\$@ .. .de MODULEX .MODULE \\$1 , @@ -397,3 +409,26 @@ Compilé pour la dernière fois le .de VOCABULARY2 .KE .. +. +. +.de HIGHLIGHT +. +. nr @wd \w'\\$1' +. nr x1 0 +. nr y1 (\\n[rst]u - \\n[rsb]u + .4m) +. nr x2 (\\n[@wd]u + .4m) +. nr y2 0 +. nr x3 0 +. nr y3 (\\n[rst]u - \\n[rsb]u + .4m) +. nr x4 (\\n[@wd]u + .4m) +. nr y4 0 +. +\h'.2m'\ +\h'-.2m'\v'(.2m - \\n[rsb]u)'\ +\M[color_box]\ +\D'P \\n[x1] -\\n[y1]u \\n[x2]u \\n[y2]u \\n[x3]u \\n[y3]u -\\n[x4]u \\n[y4]u '\ +\h'.2m'\v'-(.2m - \\n[rsb]u)'\ +\M[]\ +\\$1\ +\h'.2m' +..