diff options
author | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2013-12-05 18:39:11 +0100 |
---|---|---|
committer | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2013-12-05 18:39:11 +0100 |
commit | b96a4189d89146cdc6bba5e2c477a42b46f787cd (patch) | |
tree | 8965e9904b8fc1de286fbaa70cb28a46fbedc2e6 | |
download | groff-tools-b96a4189d89146cdc6bba5e2c477a42b46f787cd.tar.gz |
initial commit of files from my bachelor-thesis repo
-rwxr-xr-x | ebnf.sno | 138 | ||||
-rw-r--r-- | groff.outlang | 72 | ||||
-rwxr-xr-x | highlight.sno | 28 | ||||
-rw-r--r-- | plantuml.cfg | 10 | ||||
-rw-r--r-- | sql.lang | 46 | ||||
-rw-r--r-- | syntax.pic | 110 | ||||
-rw-r--r-- | uml-graph/sequence.pic | 407 | ||||
-rwxr-xr-x | uml.sno | 40 |
8 files changed, 851 insertions, 0 deletions
diff --git a/ebnf.sno b/ebnf.sno new file mode 100755 index 0000000..682be78 --- /dev/null +++ b/ebnf.sno @@ -0,0 +1,138 @@ +#!/usr/local/bin/snobol4 -b + +*** +*** Definitions +*** + define('optspace(pattern)') + define('string()') + define('serialize()') + strings = array(2) + str_no = 0 + + define('emit_groff(str)') + + define('begin_rule()') + define('end_rule()') + + define('emit_nonterm()') + define('emit_term()') + define('emit_empty()') + + define('begin_exp()') + define('end_exp()') + + define('begin_alt()') + define('end_alt()') + define('repeat()') + define('repeat_with()') + + &anchor = 1 + &fullscan = 1 + +*** +*** EBNF grammar +*** + letter = &lcase &ucase + digit = "0123456789" + + space = span(" " char(9) char(10) char(13)) | "" + eol = break(char(10) char(13)) + nonterm = ( "`" break("`") $ *string() "`" ++ | (any(letter) (span(letter digit "_") | "")) $ *string() ) ++ (optspace("~") *nonterm | "") + term = ( "'" break("'") $ *string() "'" ++ | '"' break('"') $ *string() '"' ) ++ (optspace("~") *term | "") + + lhs = nonterm + exp = nonterm *emit_nonterm() ++ | term *emit_term() ++ | optspace("[") *emit_empty() *begin_alt() *rhs optspace("]") *end_alt() ++ | optspace("{") *begin_exp() *rhs optspace("}") *end_exp() ++ (optspace("~") term *repeat_with() | *repeat()) ++ | optspace("(") *begin_exp() *rhs optspace(")") *end_exp() ++ | *emit_empty() + rhs = exp ++ ( optspace("|") *begin_alt() *rhs *end_alt() ++ | optspace(",") *rhs ++ | "") + +* NOTE: have to reset str_no if there is no lhs, since +* strings may already contain a nonterminal + rule = ( lhs optspace("=" | ":=" | "::=") ++ | *?(str_no = 0) "" $ *string() ) ++ *begin_rule() rhs optspace(";") *end_rule() + comment = optspace("(*" breakx("*") "*)" | "#" eol) + groff = optspace("." eol $ str) *emit_groff(str) + pic = optspace("%" eol $ output) + grammar = arbno(comment | groff | pic | rule) rpos(0) + +*** +*** MAIN +*** + lineno = 1 + +loop line = input :f(end) + line ".lf " int . lineno :s(next) + line ".EBNF" :s(src.l) + lineno = lineno + 1 +next output = line :(loop) + +src.l line = input + lineno = lineno + 1 + line ".EBNF" :s(compile) + src = src line char(10) :(src.l) + +compile + output = ".PS" + output = 'copy "syntax.pic";' + (src ? grammar, terminal = "FAILURE") + output = 'reset;' + output = ".PE" + output = ".lf " (lineno + 1) + src = "" :(loop) + +*** +*** Procedures +*** +optspace + optspace = space pattern space :(return) + +string + string = .strings[str_no = str_no + 1] :(nreturn) +serialize +* NOTE: will leave str_no == 0 + serialize = '"' strings[str_no] '" ' serialize + eq(str_no = str_no - 1, 0) :s(return)f(serialize) + +emit_groff + output = 'command ".' str '";' :(return) + +begin_rule + output = 'begin_rule(' serialize() ');' :(return) +end_rule + output = 'end_rule();' :(return) + +emit_nonterm + output = 'nonterminal(' serialize() ');' :(return) +emit_term + output = 'terminal(' serialize() ');' :(return) +emit_empty + output = 'empty();' :(return) + +begin_exp + output = 'begin_group();' :(return) +end_exp + output = 'end_group();' :(return) + +begin_alt + output = 'begin_alt(last []);' :(return) +end_alt + output = 'end_alt(2nd last []);' :(return) + +repeat output = 'repeat(last []);' :(return) +repeat_with + output = 'repeat_with(last [],' serialize() ');' :(return) + +end + diff --git a/groff.outlang b/groff.outlang new file mode 100644 index 0000000..60e217e --- /dev/null +++ b/groff.outlang @@ -0,0 +1,72 @@ +extension "mom" + +doctemplate +" +.NEWCOLOR green RGB #33CC00 +.NEWCOLOR red RGB #FF0000 +.NEWCOLOR darkred RGB #990000 +.NEWCOLOR blue RGB #0000FF +.NEWCOLOR brown RGB #9A1900 +.NEWCOLOR pink RGB #CC33CC +.NEWCOLOR yellow RGB #FFCC00 +.NEWCOLOR cyan RGB #66FFFF +.NEWCOLOR purple RGB #993399 +.NEWCOLOR orange RGB #FF6600 +.NEWCOLOR brightorange RGB #FF9900 +.NEWCOLOR brightgreen RGB #33FF33 +.NEWCOLOR darkgreen RGB #009900 +.NEWCOLOR black RGB #000000 +.NEWCOLOR teal RGB #008080 +.NEWCOLOR gray RGB #808080 +.NEWCOLOR darkblue RGB #000080 +.NEWCOLOR white RGB #FFFFFF +" + +" +" +end + +# NOTE: There must be a Typewrite Bold style +# I'm using the Latin Modern fonts that have this style. +# Otherwise you could use Mom's \*[BOLDER] escape. + +bold "\f[TTB]$text\fP" +italics "\f[TTI]$text\fP" +# FIXME: no way to implement underline generically +#underline + +#notfixed "\fR$text\fP" +#fixed "\fR$text\fP" + +color "\*[$style]$text\*[black]" + +colormap +"green" "green" +"red" "red" +"darkred" "darkred" +"blue" "blue" +"brown" "brown" +"pink" "pink" +"yellow" "yellow" +"cyan" "cyan" +"purple" "purple" +"orange" "orange" +"brightorange" "brightorange" +"brightgreen" "brightgreen" +"darkgreen" "darkgreen" +"black" "black" +"teal" "teal" +"gray" "gray" +"darkblue" "darkblue" +"white" "white" +default "black" +end + +# lines may be empty, so begin them with the non-spacing \& +# also, this allows "." and "'" at the beginning of the line +lineprefix "\&" + +translations +"\\" "\\e" +#"\t" " " +end diff --git a/highlight.sno b/highlight.sno new file mode 100755 index 0000000..ce43a1b --- /dev/null +++ b/highlight.sno @@ -0,0 +1,28 @@ +#!/usr/local/bin/snobol4 -b + + &anchor = 1 +* flush OUTPUT immediately + output(.output, 6, "W") + +loop line = input :f(end) + line ".HIGHLIGHT " rem . language :s(pipe) + output = line :(loop) + +* empty line to fixup line numbering +pipe output = "." +* FIXME: hack to strip the last byte (linefeed) since source-highlight +* is picky about newlines at the end of the file (will print another lineprefix) + output(.pipe, 100,, ++ "| head -c -1 | source-highlight --outlang-def groff.outlang -s " language) + +pipe_l line = input + line ".HIGHLIGHT" :s(close) + pipe = line :(pipe_l) + +close endfile(100) +* empty line to fixup line numbering +* FIXME: the linefeed is necessary because source-highlight did not terminate +* the last line + output = char(10) "." :(loop) + +end diff --git a/plantuml.cfg b/plantuml.cfg new file mode 100644 index 0000000..9be6fcf --- /dev/null +++ b/plantuml.cfg @@ -0,0 +1,10 @@ +' CMU Serif is a TrueType Computer Modern Unicode font +' This results in additional fonts in the final PDF, but is much easier +' than trying to use the same fonts Groff uses +skinparam defaultFontName CMU Serif +skinparam defaultFontSize 9 + +skinparam monochrome true + +skinparam shadowing false + diff --git a/sql.lang b/sql.lang new file mode 100644 index 0000000..53195f8 --- /dev/null +++ b/sql.lang @@ -0,0 +1,46 @@ +type = "VARCHAR|TINYINT|TEXT|DATE|SMALLINT|MEDIUMINT|INT|INTEGER|BIGINT", +"FLOAT|DOUBLE|DECIMAL|DATETIME|TIMESTAMP|TIME|YEAR|UNSIGNED", +"CHAR|CHARACTER|VARYING|TINYBLOB|TINYTEXT|BLOB|MEDIUMBLOB|MEDIUMTEXT", +"LONGBLOB|LONGTEXT|ENUM|BOOL|BINARY|VARBINARY" nonsensitive + +keyword = "ALL|ASC|AS|ALTER|AND|ADD|AUTO_INCREMENT", + "BETWEEN|BINARY|BOTH|BY|BOOLEAN", + "CHANGE|CHECK|COLUMNS|COLUMN|CROSS|CREATE", + "DATABASES|DATABASE|DATA|DELAYED|DESCRIBE|DESC|DISTINCT|DELETE|DROP|DEFAULT", + "ENCLOSED|ESCAPED|EXISTS|EXPLAIN", + "FIELDS|FIELD|FLUSH|FOR|FOREIGN|FUNCTION|FROM", + "GROUP|GRANT", + "HAVING", + "IGNORE|INDEX|INFILE|INSERT|INNER|INTO|IDENTIFIED|IN|IS|IF", + "JOIN", + "KEYS|KILL|KEY", + "LEADING|LIKE|LIMIT|LINES|LOAD|LOCAL|LOCK|LOW_PRIORITY|LEFT|LANGUAGE", + "MODIFY", + "NATURAL|NOT|NULL|NEXTVAL", + "OPTIMIZE|OPTION|OPTIONALLY|ORDER|OUTFILE|OR|OUTER|ON", + "PROCEDURE","PROCEDURAL|PRIMARY", + "READ|REFERENCES|REGEXP|RENAME|REPLACE|RETURN|REVOKE|RLIKE|RIGHT", + "SHOW|SONAME|STATUS|STRAIGHT_JOIN|SELECT|SETVAL|SET", + "TABLES|TERMINATED|TO|TRAILING","TRUNCATE|TABLE|TEMPORARY|TRIGGER|TRUSTED", + "UNION|UNIQUE|UNLOCK|USE|USING|UPDATE", + "VALUES|VARIABLES|VIEW", + "WITH|WRITE|WHERE", + "ZEROFILL|TYPE", + "XOR" + nonsensitive + +include "c_string.lang" + +environment string delim "`" "`" begin + specialchar = $SPECIALCHAR +end + +include "script_comment.lang" + +include "c_comment.lang" + +comment start "--" + +include "symbols.lang" + +include "number.lang"
\ No newline at end of file diff --git a/syntax.pic b/syntax.pic new file mode 100644 index 0000000..6c2a6f3 --- /dev/null +++ b/syntax.pic @@ -0,0 +1,110 @@ +linewid = linewid/2; + +define begin_group { + [Start: Here; +} +define end_group { + End: Here;] with .Start at Here; + move to last [].End; +} + +define terminal { + begin_group(); + arrow; + command ".FT TT"; + command ".DOC_PT_SIZE +4"; + circle $1; + command ".DOC_PT_SIZE -4"; + command ".FT R"; + line; + end_group(); +} + +define nonterminal { + begin_group(); + arrow; + command ".FT I"; + box $1; + command ".FT R"; + line; + end_group(); +} + +define keyword { + begin_group(); + arrow; + command ".FT TT"; + box $1; + command ".FT R"; + line; + end_group(); +} + +define empty { + begin_group(); + # straight line, as long as a box would be + line linewid+boxwid+linewid; + end_group(); +} + +### +### repeat(block); +### Block must have labels `Start` and `End`. +### +define repeat { + line from $1.End to $1.se - (0,circlerad*2); + arrow to ($1.Start,Here) then to $1.Start; + line from $1.End right linewid/2; +} + +### +### repeat(block,terminal_symbol); +### +define repeat_with { + command ".FT TT"; + command ".DOC_PT_SIZE +4"; + circle at bottom of $1 - (0,circlerad*2) $2; + command ".DOC_PT_SIZE -4"; + command ".FT R"; + + arrow from $1.End to ($1.End,last circle) then \ + to east of last circle; + arrow from west of last circle to ($1.Start,last circle .e) then \ + to $1.Start; + line from $1.End right linewid/2; +} + +### begin_alt(base); +define begin_alt { + line from $1.Start to $1.sw - (0,boxht); + begin_group(); +} + +### end_alt(base); +define end_alt { + end_group(); + # base might be smaller than alternative + if (Here.x < $1.End.x) then { + line to ($1.End,Here); + } + arrow to (Here,$1.End); + # Extend end of base if it is smaller than alternative + # and leave linewid/2 space for next alternative + line from $1.End to Here + (linewid/2,0); +} + +define begin_rule { + move down; + right; + command ".FT I"; + {$1 at Here - (boxwid/2,0)} + command ".FT R"; + begin_group(); + line; +} + +define end_rule { + arrow; + end_group(); + move to last [].sw; +} diff --git a/uml-graph/sequence.pic b/uml-graph/sequence.pic new file mode 100644 index 0000000..6aaa6a2 --- /dev/null +++ b/uml-graph/sequence.pic @@ -0,0 +1,407 @@ +#/usr/bin/pic2plot -Tps +# +# Pic macros for drawing UML sequence diagrams +# +# (C) Copyright 2004-2005 Diomidis Spinellis. +# +# Permission to use, copy, and distribute this software and its +# documentation for any purpose and without fee is hereby granted, +# provided that the above copyright notice appear in all copies and that +# both that copyright notice and this permission notice appear in +# supporting documentation. +# +# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +# MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. +# +# $Id$ +# + + +# Default parameters (can be redefined) + +# Spacing between messages +spacing = 0.25; +# Active box width +awid = .1; +# Box height +boxht = 0.3; +# Commend folding +corner_fold=awid +# Comment distance +define comment_default_move {up 0.25 right 0.25}; +# Comment height +comment_default_ht=0.5; +# Comment width +comment_default_wid=1; +# Underline object name +underline=1; + +# Create a new object(name,label) +define object { + $1: box $2; move; + # Could also underline text with \mk\ul\ul\ul...\rt + if (underline) then { + line from $1.w + (.1, -.07) to $1.e + (-.1, -.07); + } + move to $1.e; + move right; + # Active is the level of activations of the object + # 0 : inactive : draw thin line swimlane + # 1 : active : draw thick swimlane + # > 1: nested : draw nested swimlane + active_$1 = 0; + lifestart_$1 = $1.s.y; +} + +# Create a new external actor(name,label) +define actor { + $1: [ + XSEQC: circle rad 0.06; + XSEQL: line from XSEQC.s down .12; + line from XSEQL.start - (.15,.02) to XSEQL.start + (.15,-.02); + XSEQL1: line from XSEQL.end left .08 down .15; + XSEQL2: line from XSEQL.end right .08 down .15; + line at XSEQC.n invis "" "" "" $2; + ] + move to $1.e; + move right; + active_$1 = 0; + lifestart_$1 = $1.s.y - .05; +} + +# Create a new placeholder object(name) +define placeholder_object { + $1: box invisible; + move; + move to $1.e; + move right; + active_$1 = 0; + lifestart_$1 = $1.s.y; +} + +define pobject { + placeholder_object($1); +} + +define extend_lifeline { + if (active_$1 > 0) then { + # draw the left edges of the boxes + move to ($1.x - awid/2, Here.y); + for level = 1 to active_$1 do { + line from (Here.x, lifestart_$1) to Here; + move right awid/2 + } + + # draw the right edge of the innermost box + move right awid/2; + line from (Here.x, lifestart_$1) to Here; + } else { + line from ($1.x, lifestart_$1) to ($1.x, Here.y) dashed; + } + lifestart_$1 = Here.y; +} + +# complete(name) +# Complete the lifeline of the object with the given name +define complete { + extend_lifeline($1) + if (active_$1) then { + # draw bottom of all active boxes + line right ((active_$1 + 1) * awid/2) from ($1.x - awid/2, Here.y); + } +} + +# Draw a message(from_object,to_object,label) +define message { + down; + move spacing; + # Adjust so that lines and arrows do not fall into the + # active box. Should be .5, but the arrow heads tend to + # overshoot. + if ($1.x <= $2.x) then { + off_from = awid * .6; + off_to = -awid * .6; + } else { + off_from = -awid * .6; + off_to = awid * .6; + } + + # add half a box width for each level of nesting + if (active_$1 > 1) then { + off_from = off_from + (active_$1 - 1) * awid/2; + } + + # add half a box width for each level of nesting + if (active_$2 > 1) then { + off_to = off_to + (active_$2 - 1) * awid/2; + } + + if ($1.x == $2.x) then { + arrow from ($1.x + off_from, Here.y) right then down .25 then left $3 ljust " " " "; + } else { + arrow from ($1.x + off_from, Here.y) to ($2.x + off_to, Here.y) $3 " "; + } +} + +# Display a lifeline constraint(object,label) +define lifeline_constraint { + off_from = awid; + # add half a box width for each level of nesting + if (active_$1 > 1) then { + off_from = off_from + (active_$1 - 1) * awid/2; + } + + box at ($1.x + off_from, Here.y) invis $2 ljust " " ; +} + +define lconstraint { + lifeline_constraint($1,$2); +} + +# Display an object constraint(label) +# for the last object drawn +define object_constraint { + { box invis with .s at last box .nw $1 ljust; } +} + +define oconstraint { + object_constraint($1); +} + +# Draw a creation message(from_object,to_object,object_label) +define create_message { + down; + move spacing; + if ($1.x <= $2.x) then { + off_from = awid * .6; + off_to = -boxwid * .51; + } else { + off_from = -awid * .6; + off_to = boxwid * .51; + } + + # add half a box width for each level of nesting + if (active_$1 > 1) then { + off_from = off_from + (active_$1 - 1) * awid/2; + } + + # See comment in destroy_message + XSEQA: arrow from ($1.x + off_from, Here.y) to ($2.x + off_to, Here.y) "«create»" " "; + if ($1.x <= $2.x) then { + { XSEQB: box $3 with .w at XSEQA.end; } + } else { + { XSEQB: box $3 with .e at XSEQA.end; } + } + { + line from XSEQB.w + (.1, -.07) to XSEQB.e + (-.1, -.07); + } + lifestart_$2 = XSEQB.s.y; + move (spacing + boxht) / 2; +} + +define cmessage { + create_message($1,$2,$3); +} + +# Draw an X for a given object +define drawx { + { + line from($1.x - awid, lifestart_$1 - awid) to ($1.x + awid, lifestart_$1 + awid); + line from($1.x - awid, lifestart_$1 + awid) to ($1.x + awid, lifestart_$1 - awid); + } +} + +# Draw a destroy message(from_object,to_object) +define destroy_message { + down; + move spacing; + # The troff code is \(Fo \(Fc + # The groff code is also \[Fo] \[Fc] + # The pic2plot code is \Fo \Fc + # See http://www.delorie.com/gnu/docs/plotutils/plotutils_71.html + # To stay compatible with all we have to hardcode the characters + message($1,$2,"«destroy»"); + complete($2); + drawx($2); +} + +define dmessage { + destroy_message($1,$2); +} + +# An object deletes itself: delete(object) +define delete { + complete($1); + lifestart_$1 = lifestart_$1 - awid; + drawx($1); +} + +# Draw a message return(from_object,to_object,label) +define return_message { + down; + move spacing; + # See comment in message + if ($1.x <= $2.x) then { + off_from = awid * .6; + off_to = -awid * .6; + } else { + off_from = -awid * .6; + off_to = awid * .6; + } + + # add half a box width for each level of nesting + if (active_$1 > 1) then { + off_from = off_from + (active_$1 - 1) * awid/2; + } + + # add half a box width for each level of nesting + if (active_$2 > 1) then { + off_to = off_to + (active_$2 - 1) * awid/2; + } + + arrow from ($1.x + off_from, Here.y) to ($2.x + off_to, Here.y) dashed $3 " "; +} + +define rmessage { + return_message($1,$2,$3); +} + +# Object becomes active +# Can be nested to show recursion +define active { + extend_lifeline($1); + # draw top of new active box + line right awid from ($1.x + (active_$1 - 1) * awid/2, Here.y); + active_$1 = active_$1 + 1; +} + +# Object becomes inactive +# Can be nested to show recursion +define inactive { + extend_lifeline($1); + active_$1 = active_$1 - 1; + # draw bottom of innermost active box + line right awid from ($1.x + (active_$1 - 1) * awid/2, Here.y); +} + +# Time step +# Useful at the beginning and the end +# to show object states +define step { + down; + move spacing; +} + +# Switch to asynchronous messages +define async { + arrowhead = 0; + arrowwid = arrowwid * 2; +} + +# Switch to synchronous messages +define sync { + arrowhead = 1; + arrowwid = arrowwid / 2; +} + +# same as lifeline_constraint, but Text and empty string are exchanged. +define lconstraint_below{ + off_from = awid; + # add half a box width for each level of nesting + if (active_$1 > 1) then { + off_from = off_from + (active_$1 - 1) * awid/2; + } + + box at ($1.x + off_from, Here.y) invis "" $2 ljust; +} + +# begin_frame(left_object,name,label_text); +define begin_frame { + # The lifeline will be cut here + extend_lifeline($1); + # draw the frame-label + $2: box $3 invis with .n at ($1.x, Here.y); + d = $2.e.y - $2.se.y; + line from $2.ne to $2.e then down d left d then to $2.sw; + # continue the lifeline below the frame-label + move to $2.s; + lifestart_$1 = Here.y; +} + +# end_frame(right_object,name); +define end_frame { + # dummy-box for the lower right corner: + box invis "" with .s at ($1.x, Here.y); + # draw the frame + frame_wid = last box.se.x - $2.nw.x + frame_ht = - last box.se.y + $2.nw.y + box with .nw at $2.nw wid frame_wid ht frame_ht; + # restore Here.y + move to last box.s; +} + +# comment(object,[name],[line_movement], [box_size] text); +define comment { + old_y = Here.y + # draw the first connecting line, at which's end the box wil be positioned + move to ($1.x, Here.y) + if "$3" == "" then { + line comment_default_move() dashed; + } else { + line $3 dashed; + } + + # draw the box, use comment_default_xx if no explicit + # size is given together with the text in parameter 4 + old_boxht=boxht; + old_boxwid=boxwid; + boxht=comment_default_ht; + boxwid=comment_default_wid; + if "$2" == "" then { + box invis $4; + } else { + $2: box invis $4; + } + boxht=old_boxht; + boxwid=old_boxwid; + + # draw the frame of the comment + line from last box.nw \ + to last box.ne - (corner_fold, 0) \ + then to last box.ne - (0, corner_fold) \ + then to last box.se \ + then to last box.sw \ + then to last box.nw ; + line from last box.ne - (corner_fold, 0) \ + to last box.ne - (corner_fold, corner_fold) \ + then to last box.ne - (0, corner_fold) ; + + # restore Here.y + move to ($1.x, old_y) +} + +# connect_to_comment(object,name); +define connect_to_comment { + old_y = Here.y + # start at the object + move to ($1.x, Here.y) + # find the best connection-point of the comment to use as line-end + if $1.x < $2.w.x then { + line to $2.w dashed; + } else { + if $1.x > $2.e.x then { + line to $2.e dashed; + } else { + if Here.y < $2.s.y then { + line to $2.s dashed; + } else { + if Here.y > $2.n.y then { + line to $2.n dashed; + } + } + } + } + # restore Here.y + move to ($1.x, old_y) +} @@ -0,0 +1,40 @@ +#!/usr/local/bin/snobol4 -b + + &anchor = 1 + + float = span("0123456789.") + + count = 0 + lineno = 1 + +loop line = input :f(end) + line ".lf " float . lineno :s(next) + line ".UML" rem . options :s(pipe) + lineno = lineno + 1 +next output = line :(loop) + +pipe filename = "uml_temp" (count = count + 1) ".pdf" + output(.pipe, 100,, ++ "| plantuml -pipe -tsvg -failonerror -config plantuml.cfg | " ++ "rsvg-convert -f pdf -o " filename) + pipe = "@startuml" + +pipe_l line = input + lineno = lineno + 1 + line ".UML" :s(close) + pipe = line :(pipe_l) + +close pipe = "@enduml" + endfile(100) + +* get PDF dimensions + input(.pipe, 100,, "|pdfinfo " filename) +get_info + pipe "Page size:" span(" ") float . width " x " float . height :f(get_info) + endfile(100) + + output = ".PDF_IMAGE " filename " " width "p " height "p" options + output = ".lf " (lineno + 1) :(loop) + +end + |