/bin/prag.awk
http://shell-simulator.googlecode.com/ · AWK · 702 lines · 582 code · 2 blank · 118 comment · 193 complexity · ae297bab4f507146dbcbc0924a1aa19c MD5 · raw file
- #!gawk -f
- # Copyright (C) 1992, 1993 Holger J. Meyer, Rostock, Germany
- # hm@GUUG.de
- #
- # See file ``Copyright'' for terms of copyright.
- #
- # Module:
- # Process a grap(1) like language, to produce graphs. The input language
- # syntax is documented in lines marked with double hash marks ('##').
- # The first implementation was much inspired by the graph program from
- # ``Aho, A.V., Kernighan, B. W., Weinberger, P. J. "The AWK Programming
- # Language", Addison-Wesley, Reading, 1988''.
- #
- # Source:
- # NAWK
- #
- # History:
- # 92/4/20 hme, initial version written
- # 93/8/24 hme, multiple graphs, grids, etc. added
- # 93/10/20 hme, labeled margin boxes, generate `reset' before .PE
- # 95/9/24 hme, more grap conformance, improved ticks (by eduardo@nostromo.medusa.es)
- # 95/11/15 hme, put out only labeled margin boxes
- #
- # Layout:
- #
- # GRAPH
- # +----------+------------------------+----------+
- # | | ^ | |
- # | | TMARG ht/6| |
- # | | v | |
- # +----------+------------------------+----------+
- # | LMARG | FRAME ^ | RMARG |
- # | | | | |
- # | | | | |
- # | | ht | |
- # | | | | |
- # | | | | |
- # |<-wid/6-->|<---------wid--------v->|<--wid/6->|
- # +----------+------------------------+----------+
- # | | ^ | |
- # | | BMARG ht/6| |
- # | | v | |
- # +----------+------------------------+----------+
- #
- #
- BEGIN {
- MYADDR = "hm@GUUG.de";
- # number (RE)
- NUMBER = "^[-+]?([0-9]+[.]?[0-9]*|[.][0-9]+)" "([eE][-+]?[0-9]+)?$";
- GNAME = "GRAPH"; # label for whole picture
- FNAME = "FRAME"; # label for frame
- MNAME = "MARG"; # label for [top|....] margin boxes
- DEFLSTYLE = "solid";
- DEFCH = "\\s+2\\(bu\\s-2";
- MARKED = 1;
- MINXTICKS = 5;
- MINYTICKS = 5;
- nG1 = 0;
- grapinput = 0;
- err = 0;
- dot_lf = 1;
- warn = 1;
- debug = 0;
- }
- ## .G1 [width [height]]
- # start of graph input
- /^.G1/ {
- ++nG1;
- grapinput = 1;
- data = 0;
- initgraph();
- if (NF >= 2) {
- wid = $2;
- }
- if (NF >= 3) {
- ht = $3;
- }
- resizegraph();
- if (dot_lf) {
- printf(".lf %d %s\n", FNR, FILENAME);
- }
- next;
- }
- ## .G2
- # end of graph input -- draw graph
- /^.G2/ {
- if (!grapinput) {
- printf("\"%s\":%d: missing previous .G1\n", FILENAME, FNR) |"cat >&2";
- errexit(-1);
- }
- else {
- endgraph();
- grapinput = 0;
- }
- if (dot_lf) {
- printf(".lf %d %s\n", FNR, FILENAME);
- }
- next;
- }
- # copy all outside from .G1 and .G2
- !grapinput {
- print $0;
- next;
- }
- ## # comment
- # delete comments
- /^#/ {
- next;
- }
- ## draw line-style
- $1 == "draw" {
- if (NF != 2) {
- printf("\"%s\":%d: draw line-style\n", FILENAME, FNR) | "cat >&2";
- errexit(-1);
- }
- if ($2 == "marked") {
- g_flags[ngs] = MARKED;
- }
- else {
- g_lstyle[ngs] = $2;
- }
- next;
- }
- ## new [line-style [name [label]]]
- # begin new graph, put old data points out
- $1 == "new" {
- cg = ++ngs;
- newgraph(ngs);
- if (NF >= 2) {
- if ($2 == "marked") {
- g_flags[ngs] = MARKED;
- }
- else {
- g_lstyle[ngs] = $2;
- }
- }
- if (NF >= 3) {
- g_name[ngs] = $3;
- }
- if (NF >= 4) {
- $1 = $2 = $3 = "";
- sub(/^[ \t]*/, "");
- g_label[ngs] = $0;
- }
- g_ndata[ngs] = 0;
- next;
- }
- ## label [left | right | top | bot] label-string
- # left, right, top, bottom label
- $1 == "label" {
- pos = $2;
- if (pos == "left") {
- sub(/^[ \t]*label[ \t]+left[ \t]*/, "");
- }
- else if (pos == "right") {
- sub(/^[ \t]*label[ \t]+right[ \t]*/, "");
- }
- else if (pos == "top") {
- sub(/^[ \t]*label[ \t]+top[ \t]*/, "");
- }
- else if (pos == "bot") {
- sub(/^[ \t]*label[ \t]+bot[ \t]*/, "");
- }
- else {
- printf("\"%s\":%d: label [left|right|top|bot] string ...\n",
- FILENAME, FNR) | "cat >&2";
- errexit(-1);
- }
- t_label[pos] = $0;
- next;
- }
- ## ticks [left | right | top | bot] [where] position ...
- ## ticks [left | right | top | bot] [where] from begin to end [by step]
- # ticks for x- & y-axis, left, top, right or bottom position
- $1 == "ticks" {
- if (NF <= 3) {
- printf("\"%s\":%d: ticks [left|right|top|bot] [where] position ...\n",
- FILENAME, FNR) | "cat >&2";
- errexit(-1);
- }
- if ($2 != "left" && $2 != "right" && $2 != "top" && $2 != "bot") {
- printf("\"%s\":%d: ticks [left|right|top|bot] [where] position ...\n",
- FILENAME, FNR) | "cat >&2";
- errexit(-1);
- }
- i = 3;
- t_num[$2] = 0;
- if ($3 == "in" || $3 == "out") {
- t_where[$2] = $3;
- ++i;
- }
- if ($i != "from") {
- while (i <= NF) {
- t_pos[$2, t_num[$2]] = $i;
- ++t_num[$2];
- ++i;
- }
- }
- else {
- if ($(i+2) != "to" || NF < i+3) {
- printf( "\"%s\":%d: ticks [left|right|top|bot] [where] from begin to end [by step]\n",
- FILENAME, FNR) | "cat >&2";
- errexit(-1);
- }
- if ($(i+4) == "by") {
- if (NF == i+5) {
- tickstep = $(i+5);
- }
- else {
- printf( "\"%s\":%d: ticks [left|right|top|bot] [where] from begin to end [by step]\n",
- FILENAME, FNR) | "cat >&2";
- errexit(-1);
- }
- }
- else {
- tickstep = 1;
- }
- for (tick = $(i+1); tick <= $(i+3); tick += tickstep) {
- t_pos[$2, t_num[$2]] = tick;
- ++t_num[$2];
- }
- }
- next;
- }
- ## frame frame-attributes ...
- # frame-attributes
- $1 == "frame" {
- if (NF == 1) {
- printf("\"%s\":%d: frame frame-attributes ...\n",
- FILENAME, FNR) | "cat >&2";
- errexit(-1);
- }
- sub(/^[ \t]*frame[ \t]+/, "");
- fattr = $0;
- next;
- }
- ## spline
- ## nospline
- $1 == "spline" {
- g_spline[ngs] = "sp";
- next;
- }
- $1 == "nospline" {
- g_spline[ngs] = "";
- next;
- }
- ## range xmin ymin xmax ymax
- $1 == "range" && $2 ~ NUMBER && $3 ~ NUMBER && $4 ~ NUMBER && $5 ~ NUMBER {
- if (NF != 5) {
- printf("\"%s\":%d: range xmin ymin xmax ymax\n",
- FILENAME, FNR) | "cat >&2";
- errexit(-1);
- }
- xmin = $2;
- ymin = $3;
- xmax = $4;
- ymax = $5;
- next;
- }
- ## ht number
- # graph height
- $1 == "ht" && $2 ~ NUMBER {
- if (NF != 2) {
- printf("\"%s\":%d: ht height\n", FILENAME, FNR) | "cat >&2";
- errexit(-1);
- }
- ht = $2;
- resizegraph();
- next;
- }
- ## wid number
- # graph width
- $1 == "wid" && $2 ~ NUMBER {
- if (NF != 2) {
- printf("\"%s\":%d: wid width\n", FILENAME, FNR) | "cat >&2";
- errexit(-1);
- }
- wid = $2;
- resizegraph();
- next;
- }
- ## grid [line-style]
- # graph with grid
- $1 == "grid" {
- if (NF == 1) {
- grid = "dotted";
- }
- else if (NF == 2) {
- grid = $2;
- }
- else {
- printf("\"%s\":%d: grid [line-style]\n", FILENAME, FNR) | "cat >&2";
- errexit(-1);
- }
- next;
- }
- ## mark drawing-character
- # set default drawing character for this graph
- $1 == "mark" {
- if (NF != 2) {
- printf("\"%s\":%d: mark drawing-character\n", FILENAME, FNR) | "cat >&2";
- errexit(-1);
- }
- g_defch[ngs] = $2;
- g_flags[ngs] = MARKED;
- next;
- }
- ## .lf line-number file-name
- # groff's ``.lf line file''
- $1 == ".lf" {
- print $0;
- next;
- }
- # collecting DATA
- ## next [graph-name] [at] position
- # next point extraction: awk falls through these actions!!!
- $1 == "next" && $3 == "at" {
- found = 0;
- for (i = 0; i <= ngs; ++i) {
- if (g_name[i] == $2) {
- # alter cg to point temporarily to an other graph
- # after collecting data, it shall be restored
- cg = i;
- ++found;
- break;
- }
- }
- if (!found) {
- printf("\"%s\":%d: illegal graph-name \"%s\": ignored\n",
- FILENAME, FNR, $2) | "cat >&2";
- }
- sub(/^[ \t]*next[ \t]+[a-zA-Z]+[ \t]+at[ \t]*/, "next at ");
- }
- $1 == "next" && $2 == "at" {
- sub(/^[ \t]*next[ \t]+at[ \t]*/, "next ");
- }
- $1 == "next" {
- sub(/^[ \t]*next[ \t]*/, "");
- }
- # pairs of numbers with opt drawing char
- $1 ~ NUMBER && $2 ~ NUMBER {
- g_x[cg, g_ndata[cg]] = $1;
- g_y[cg, g_ndata[cg]] = $2;
- if (NF >= 3) {
- $1 = $2 = "";
- sub(/^[ \t]*/, "");
- g_ch[cg, g_ndata[cg]] = $0; # extra plotting character
- }
- else {
- g_ch[cg, g_ndata[cg]] = "";
- }
- ++g_ndata[cg]; # count number of data points
- cg = ngs; # reset current graph
- data = 1;
- next;
- }
- # a single number with opt drawing char
- $1 ~ NUMBER && $2 !~ NUMBER {
- g_y[cg, g_ndata[cg]] = $1;
- g_x[cg, g_ndata[cg]] = g_ndata[cg];
- if (NF >= 2) {
- $1 = "";
- sub(/^[ \t]*/, "");
- g_ch[cg, g_ndata[cg]] = $0; # extra plotting character
- }
- else {
- g_ch[cg, g_ndata[cg]] = "";
- }
- ++g_ndata[cg];
- cg = ngs; # reset current graph
- data = 1;
- next;
- }
- ## pic '{' anything '}'
- # rest of input goes direct to pic
- $1 != "pic" {
- if (warn) {
- printf("\"%s\":%d: inputline passed through pic\n",
- FILENAME, FNR) | "cat >&2";
- }
- }
- {
- sub(/^[ \t]*pic[ \t]*{[ \t]*/, "");
- sub(/[ \t]*}[ \t]*$/, "");
- piccode = sprintf("%s%s\n", piccode, $0);
- next;
- }
- END {
- if (err) {
- exit(err);
- }
- if (grapinput) {
- printf("\"%s\":%d: missing .G2 \n", FILENAME, FNR) | "cat >&2";
- endgraph();
- }
- exit(0);
- }
- #
- # subroutine stuff
- #
- function errexit(e) {
- err = e;
- exit(-1);
- }
- function initgraph() {
- ht = 2; # default frame size
- wid = 3;
- fattr = ""; # frame-attributes
- grid = "";
- ngs = 0; # number of graphs
- cg = 0; # current graph, may differ from ngs due to next stmnt.
- # struct graph {
- # integer g_flags, # various flags indicating mark style etc.
- # string g_lstyle; # line style
- # string g_spline; # draw graph with [sp]line
- # string g_name; # graph name
- # string g_label; # graph label
- # integer g_ndata; # # of data items
- # real g_x[]; # x coords
- # real g_y[]; # y coords
- # string g_ch[]; # optional point drawing character
- # string g_defch; # default drawing character
- # };
- g_defch[0] = DEFCH;
- g_defch[1] = "\\(*D";
- g_defch[2] = "\\(pl";
- g_defch[3] = "\\(sq";
- g_defch[4] = "\\(mu";
- newticks("left");
- newticks("right");
- newticks("top");
- newticks("bot");
- newgraph(ngs);
-
- piccode = "";
- xmin = xmax = ymin = ymax = 0;
- }
- function resizegraph()
- {
- # left, right, top, bot margin of frame
- m_size["left"] = m_size["right"] = wid/6;
- m_size["top"] = m_size["bot"] = ht/6;
- ticklen = ht/32; # default len for tick marker
- }
- function newgraph(g) {
- g_flags[g] = 0;
- g_lstyle[g] = DEFLSTYLE;
- g_spline[g] = "sp"; # [sp]line used for graph drawing
- g_name[g] = "OOPS";
- g_label[g] = "";
- g_ndata[g] = 0;
- }
- function newticks(where) {
- t_label[where] = "";
- t_where[where] = "out";
- t_num[where] = 0;
- t_pos[where, 0] = 0;
- }
- function endgraph() {
- grapinput = 0;
- if (!xmin && !xmax && !ymin && !ymax) { # no range was given
- xmin = xmax = g_x[0, 0];
- ymin = ymax = g_y[0, 0];
- for (g = 0; g <= ngs; ++g) {
- for (i = 0; i < g_ndata[g]; ++i) {
- if (g_x[g, i] < xmin) {
- xmin = g_x[g, i];
- }
- if (g_x[g, i] > xmax) {
- xmax = g_x[g, i];
- }
- if (g_y[g, i] < ymin) {
- ymin = g_y[g, i];
- }
- if (g_y[g, i] > ymax) {
- ymax = g_y[g, i];
- }
- }
- }
- }
- printf(".PS %g %g\n", wid+m_size["left"]+m_size["right"], ht+m_size["top"]+m_size["bot"]);
- printf("# DO NOT EDIT!\n");
- printf("# generated from \"%s\" by prag (C) %s\n", FILENAME, MYADDR);
- if (data) { # any data?
- cutmarg();
- frame();
- label();
- ticks();
- for (g = 0; g <= ngs; ++g) {
- drawgraph(g);
- }
- }
- if (piccode != "") {
- printf("%s", piccode);
- }
- printf("reset\n.PE\n");
- }
- # cut off margins without a label
- function cutmarg( w) {
- for (w in m_size) {
- if (t_label[w] == "") {
- m_size[w] = 0;
- }
- }
- }
- # create frame from graph
- function frame() {
- printf("%s:\tbox invis ht %g wid %g\n",
- GNAME, ht+m_size["top"]+m_size["bot"], wid+m_size["left"]+m_size["right"]);
- printf("%s:\tbox %s ht %g wid %g with .sw at %s.sw + (%g, %g)\n",
- FNAME, fattr, ht, wid, GNAME, m_size["left"], m_size["bot"]);
- }
- # center label under x-axis and left from y-axis
- function label() {
- if (t_label["left"]) {
- printf("%s%s:\tbox wid %g ht %g invis %s with .e at %s.w\n",
- MNAME, "left", m_size["left"], ht, t_label["left"], GNAME);
- }
- if (t_label["right"]) {
- printf("%s%s:\tbox wid %g ht %g invis %s with .w at %s.e\n",
- MNAME, "right", m_size["right"], ht, t_label["right"], GNAME);
- }
- if (t_label["top"]) {
- printf("%s%s:\tbox wid %g ht %g invis %s with .s at %s.n\n",
- MNAME, "top", wid, m_size["top"], t_label["top"], GNAME);
- }
- if (t_label["bot"]) {
- printf("%s%s:\tbox wid %g ht %g invis %s with .n at %s.s\n",
- MNAME, "bot", wid, m_size["bot"], t_label["bot"], GNAME);
- }
- }
- # create tick marks for all axes
- function ticks( i, user_ticks, w) {
- user_ticks = 0;
- for (i = 0; i < t_num["left"]; ++i) {
- printf("line %s %g at %g <%s.sw, %s.nw>\n",
- t_where["left"] == "out" ? "left" : "right",
- ticklen, w = yscale(t_pos["left", i]), FNAME, FNAME);
- printf("\"%s \" at last line.w rjust\n", t_pos["left", i]);
- if (w != 0 && w != 1 && grid != "") {
- printf("line %s from %g <%s.sw, %s.nw> to %g <%s.se, %s.ne>\n",
- grid, w, FNAME, FNAME, w, FNAME, FNAME);
- }
- ++user_ticks;
- }
- for (i = 0; i < t_num["right"]; ++i) {
- printf("line %s %g at %g <%s.se, %s.ne>\n",
- t_where["right"] == "out" ? "right" : "left",
- ticklen, yscale(t_pos["right", i]), FNAME, FNAME);
- printf("\" %s\" at last line.e ljust\n", t_pos["right", i]);
- ++user_ticks;
- }
- for (i = 0; i < t_num["top"]; ++i) {
- printf("line %s %g at %g <%s.nw, %s.ne>\n",
- t_where["bot"] == "out" ? "up" : "down",
- ticklen, xscale(t_pos["top", i]), FNAME, FNAME);
- printf("\"%s\" at last line.n above\n", t_pos["top", i]);
- ++user_ticks;
- }
- for (i = 0; i < t_num["bot"]; ++i) {
- printf("line %s %g at %g <%s.sw, %s.se>\n",
- t_where["bot"] == "out" ? "down" : "up",
- ticklen, w = xscale(t_pos["bot", i]), FNAME, FNAME);
- printf("\"%s\" at last line.s below\n", t_pos["bot", i]);
- if (w != 0 && w != 1 && grid != "") {
- printf("line %s from %g <%s.sw, %s.se> to %g <%s.nw, %s.ne>\n",
- grid, w, FNAME, FNAME, w, FNAME, FNAME);
- }
- ++user_ticks;
- }
- if (!user_ticks) {
- xmax = roundceil(MINXTICKS, xmax);
- ymax = roundceil(MINYTICKS, ymax);
- xmin = roundfloor(MINXTICKS, xmin);
- ymin = roundfloor(MINYTICKS, ymin);
- ysteps = steps(MINYTICKS, ymin, ymax);
- #for (i = 0; i <= ysteps; ++i) {
- for (i = 1; i < ysteps; ++i) {
- printf("line left %g at %g <%s.sw, %s.nw>\n",
- ticklen, w = i/ysteps, FNAME, FNAME);
- printf("\"%s\" at last line.w rjust\n", ymin + (ymax - ymin)*i/ysteps);
- if (w != 0 && w != 1 && grid != "") {
- printf("line %s from %g <%s.sw, %s.nw> to %g <%s.se, %s.ne>\n",
- grid, w, FNAME, FNAME, w, FNAME, FNAME);
- }
- }
- xsteps = steps(MINXTICKS, xmin, xmax);
- #for (i = 0; i <= xsteps; ++i) {
- for (i = 1; i < xsteps; ++i) {
- printf("line down %g at %g <%s.sw, %s.se>\n",
- ticklen, w = i/xsteps, FNAME, FNAME);
- printf("\"%s\" at last line.s below\n", xmin + (xmax - xmin)*i/xsteps);
- if (w != 0 && w != 1 && grid != "") {
- printf("line %s from %g <%s.sw, %s.se> to %g <%s.nw, %s.ne>\n",
- grid, w, FNAME, FNAME, w, FNAME, FNAME);
- }
- }
- }
- }
- # scale x-value
- function xscale(x) {
- return((x-xmin)/(xmax-xmin));
- }
- # scale y-value
- function yscale(y) {
- return((y-ymin)/(ymax-ymin));
- }
- # round ranges, VERY POOR!
- # round to smallest e*10^log10(val) + n*e .gt. val
- function roundceil(ex, val, e, v) {
- e = ex;
- while (e < val) {
- e *= 10;
- }
- v = val;
- if (int(v) % e) {
- v = e*(int(v/e) + 1);
- }
- while (v >= val) {
- v -= ex;
- }
- if (debug) {
- printf("roundceil(%g, %g) returns %g\n",
- ex, val, v + ex) | "cat >&2";
- }
- return(v + ex);
- }
- # round to greatest e*10^log10(val) - n*e .lt. val
- function roundfloor(ex, val, e, v) {
- e = ex;
- while (e < val) {
- e *= 10;
- }
- if (e > ex) {
- e /= 10;
- }
- v = val;
- if (int(v) % e) {
- v = e*(int(v/e));
- }
- while (v <= val) {
- v += ex;
- }
- if (debug) {
- printf("roundfloor(%g, %g) returns %g\n",
- ex, val, v - ex) | "cat >&2";
- }
- return(v - ex);
- }
- # count of ticks
- function steps(defsteps, min, max)
- {
- # very simple solution
- return(defsteps);
- }
- # sorting routine
- function swap(g, i, j, t) {
- t = g_x[g, i];
- g_x[g, i] = g_x[g, j];
- g_x[g, j] = t;
- t = g_y[g, i];
- g_y[g, i] = g_y[g, j];
- g_y[g, j] = t;
- t = g_ch[g, i];
- g_ch[g, i] = g_ch[g, j];
- g_ch[g, j] = t;
- }
- # insertion sort
- function sort(g, i, j) {
- for (i = 1; i < g_ndata[g]; ++i) {
- for (j = i; j > 0 && g_x[g, j - 1] > g_x[g, j]; --j) {
- swap(g, j - 1, j);
- }
- }
- }
-
- # create data points
- function drawgraph(g, i) {
- if (g_ndata[g] == 0) {
- return;
- }
- sort(g);
- printf("G_%s: # graph no. %d\n", g_name[g], g + 1);
- if (g_lstyle[g] == "invis" || g_flags[g] == MARKED) {
- for (i = 0; i < g_ndata[g]; ++i) {
- printf("\"%s\" at %s.sw + (%g, %g)\n",
- g_ch[g, i] != "" ? g_ch[g, i] : (g_defch[g] != "" ? g_defch[g] : DEFCH),
- FNAME, xscale(g_x[g, i])*wid, yscale(g_y[g, i])*ht);
- }
- }
- if (g_lstyle[g] != "invis") {
- printf("%sline %s %s from %s.sw + (%g, %g)",
- g_spline[g], g_label[g], g_lstyle[g] == "solid" ? "" : g_lstyle[g],
- FNAME, xscale(g_x[g, 0])*wid, yscale(g_y[g, 0])*ht);
- for (i = 1; i < g_ndata[g]; ++i) {
- printf("\t\\\n\tthen to %s.sw + (%g, %g)", FNAME,
- xscale(g_x[g, i])*wid, yscale(g_y[g, i])*ht);
- }
- printf("\n");
- }
- }
- #vi: set tabstop=5 shiftwidth=5: