grap-1.46/0000775000175000017500000000000013670320205007376 500000000000000grap-1.46/grap.yy0000664000175000017500000007253413670046267010662 00000000000000/* -*-c++-*- */ %{ /* This code is (c) 1998-2001 Ted Faber (faber@lunabase.org) see the COPYRIGHT file for the full copyright and limitations of liabilities. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #ifdef STDC_HEADERS #include #endif #if defined(STDC_HEADERS) | defined(HAVE_STDLIB_H) #include #endif #ifdef HAVE_UNISTD_H #include #endif // We use RAND_MAX to scale random()/rand() values into doubles below. // This is a little defensive driving to find a usable value for it. #ifndef RAND_MAX #ifdef LONG_MAX #define RAND_MAX LONG_MAX #else // Shot in the dark, really - stdlib.h or limits.h should exist #define RAND_MAX 0x7fffffffL #endif #endif #include "grap.h" #include "grap_data.h" #include "grap_draw.h" doubleDictionary vars; graph *the_graph =0; lexStack lexstack; macroDictionary macros; stringSequence path; bool first_line; bool unaligned_default = false; // Should strings be unaligned by default bool clip_default = true; // Should strings be clipped by default extern bool do_sprintf; // true if it's acceptable to parse sprintf line* defline; coord *defcoord; string *graph_name; string *graph_pos; string *ps_param; // number of lines in a number list (used in grap_parse.cc) int nlines; // bison wants these defined.... int yyerror(const char*); int yylex(); void init_dict(); // defined in grap_lex.l extern bool include_file(string *, bool =false, bool=true); extern void lex_no_macro_expansion(); extern void lex_macro_expansion_ok(); extern void lex_begin_macro_text(); extern void lex_begin_rest_of_line(); extern void lex_no_coord(); extern void lex_coord_ok(); extern void lex_begin_copy( string*s=0); extern int include_string(string *, for_descriptor *f=0, grap_input i=GMACRO); extern void lex_hunt_macro(); extern int yyparse(void); // To shut yacc (vs. bison) up. void draw_graph(); void init_graph(); // Parsing utilities in grap_parse.cc. Locating them there reduces // compilation time (this file was getting very large) and eliminates // some code redundancy. extern graph *initial_graph(); extern linedesc* combine_linedesc(linedesc *, linedesc*); extern axis combine_logs(axis, axis); extern void draw_statement(string *, linedesc *, DisplayString *); extern void num_list(doublelist *); extern double assignment_statement(string *, double); extern stringlist *combine_strings(stringlist *, string *, strmod &); extern void plot_statement(double, DisplayString *, point *); extern void next_statement(string *, point *, linedesc *); extern ticklist *ticklist_elem(double, DisplayString *, ticklist *); extern ticklist *tick_for(coord *, double, double, bydesc, DisplayString *); extern void ticks_statement(sides, double, shiftlist *, ticklist *); extern void grid_statement(sides, int, linedesc *, shiftlist *, ticklist *); extern void line_statement(int, linedesc *, point *, point *, linedesc *); extern axisdesc axis_description(axis, double, double ); extern void coord_statement(string *, axisdesc&, axisdesc&, axis); extern void coord_statement(coord *, axisdesc&, axisdesc&, axis); extern void for_statement(string *, double, double, bydesc, string *); extern void process_frame(linedesc *, frame *, frame *); extern void define_macro(string *, string*); extern void bar_statement(coord *, sides, double, double, double, double, linedesc *); // adapters to return complex (complex-ish) functions void grap_srandom(double x) { srandom(static_cast(x)); } double grap_random() { return static_cast(random())/(static_cast(RAND_MAX)+1e-6); } double grap_getpid() { return static_cast(getpid());} double pow10(double x) { return pow(10,x); } double toint(double x) { return static_cast(int(x)); } double grap_min(double a, double b) { return (ab) ? a : b; } typedef void (*vfunction1)(double); typedef double (*function0)(); typedef double (*function1)(double); typedef double (*function2)(double, double); // jump tables for dispatching internal functions vfunction1 jtvf1[NVF1] = { grap_srandom }; function0 jtf0[NF0] = { grap_random, grap_getpid }; function1 jtf1[NF1] = { log10, pow10, toint, sin, cos, sqrt, exp, log, floor, ceil }; function2 jtf2[NF2] = { atan2, grap_min, grap_max}; %} %token NUMBER START END IDENT COPY SEP STRING COORD_NAME UNDEFINE %token SOLID INVIS DOTTED DASHED DRAW LPAREN RPAREN FUNC0 FUNC1 FUNC2 COMMA %token LINE PLOT FROM TO AT NEXT FRAME LEFT RIGHT TOP BOTTOM UP DOWN HT WID %token IN OUT NONE TICKS OFF BY GRID LJUST RJUST ABOVE BELOW ALIGNED %token PLUS MINUS TIMES DIV CARAT EQUALS SIZE UNALIGNED LABEL RADIUS CIRCLE %token ARROW XDIM YDIM LOG_X LOG_Y LOG_LOG COORD TEXT DEFINE IF THEN ELSE %token EQ NEQ LT GT LTE GTE NOT OR AND FOR DO MACRO COPYTEXT THRU %token GRAPH REST PRINT PIC TROFF UNTIL COLOR SPRINTF SH BAR FILL FILLCOLOR %token BASE ON LHS VFUNC1 CLIPPED UNCLIPPED THICKNESS MOD STRPTIME %token STRFTIME %start graphs %union { int val; double num; string *String; DisplayString *ds; frame *frameptr; shiftdesc *shift; shiftlist *shift_list; point *pt; linedesc *lined; stringlist *string_list; linelist *line_list; ticklist *tick_list; doublelist *double_list; doublevec *double_vec; macro *macro_val; coord *coordptr; line *lineptr; sides side; bydesc by; axisdesc axistype; axis axisname; strmod stringmod; copydesc *copyd; bar_param *bar_p; } %type NUMBER num_line_elem expr opt_expr direction radius_spec %type assignment_statement lexpr pure_lexpr right_hand_side time_expr %type strmod %type IDENT STRING opt_ident TEXT else_clause REST TROFF %type START string LHS %type opt_display_string %type VFUNC1 FUNC0 FUNC1 FUNC2 tickdir opt_tick_off line_token %type opt_coordname COORD_NAME autotick %type side bar_dir %type sides size size_elem final_size %type linedesc_elem linedesc opt_linedesc %type strlist %type num_line %type expr_list %type ticklist tickat tickfor tickdesc %type point coord_pair %type opt_shift %type shift %type by_clause %type x_axis_desc y_axis_desc %type log_list log_desc %type COPYTEXT %type MACRO %type until_clause %type bar_param bar_params %left OR AND %right NOT %left EQ NEQ LT GT LTE GTE %left PLUS MINUS %left TIMES DIV MOD %left CARAT %% graphs: | graphs graph ; graph : START { if ( !the_graph) the_graph = initial_graph(); the_graph->init(); init_dict(); first_line = true; the_graph->begin_block($1); } prog END { the_graph->draw(0); the_graph->end_block(); } ; prog : { } | prog statement { } ; statement: assignment_statement { first_line = false;} | num_list { first_line = false; the_graph->is_visible(true);} | frame_statement { first_line = false; the_graph->queue_frame(); the_graph->is_visible(true); } | draw_statement { first_line = false; } | next_statement { first_line = false; the_graph->is_visible(true);} | plot_statement { first_line = false; the_graph->is_visible(true);} | ticks_statement { first_line = false; the_graph->is_visible(true);} | grid_statement { first_line = false; the_graph->is_visible(true);} | label_statement { first_line = false; the_graph->is_visible(true);} | circle_statement { first_line = false; the_graph->is_visible(true);} | bar_statement { first_line = false; the_graph->is_visible(true);} | line_statement { first_line = false; the_graph->is_visible(true);} | coord_statement { first_line = false;} | copy_statement { first_line = false;} | define_statement { first_line = false;} | undefine_statement { first_line = false;} | if_statement { first_line = false;} | for_statement { first_line = false;} | graph_statement { first_line = false;} | print_statement { first_line = false;} | sh_statement { first_line = false;} | pic_statement { first_line = false;} | troff_line { first_line = false;} | void_function { first_line = false;} | SEP ; from: FROM | EQUALS ; opt_coordname: { $$= defcoord; } | COORD_NAME { $$= $1;} ; opt_ident: { $$ = 0; } | IDENT { $$ = $1; } ; opt_display_string: { $$ = 0; } | string strmod { $$ = new DisplayString(*$1, $2.just, $2.size, $2.rel, $2.clip, $2.color); } ; string: STRING { $$ = $1; } | SPRINTF LPAREN STRING COMMA expr_list RPAREN { if ( do_sprintf ) { const int len = $3->length() < 128 ? 256 : 2*$3->length(); char *buf = new char[len]; // I really dislike this, but I dislike trying to do it // incrementally more. switch ($5->size()) { case 0: snprintf(buf, len, "%s", $3->c_str()); break; case 1: snprintf(buf, len, $3->c_str(), (*$5)[0]); break; case 2: snprintf(buf, len, $3->c_str(), (*$5)[0], (*$5)[1]); break; case 3: snprintf(buf, len, $3->c_str(), (*$5)[0], (*$5)[1], (*$5)[2]); break; case 4: snprintf(buf, len, $3->c_str(), (*$5)[0], (*$5)[1], (*$5)[2], (*$5)[3]); break; case 5: snprintf(buf, len, $3->c_str(), (*$5)[0], (*$5)[1], (*$5)[2], (*$5)[3], (*$5)[4]); break; case 6: snprintf(buf, len, $3->c_str(), (*$5)[0], (*$5)[1], (*$5)[2], (*$5)[3], (*$5)[4], (*$5)[5]); break; case 7: snprintf(buf, len, $3->c_str(), (*$5)[0], (*$5)[1], (*$5)[2], (*$5)[3], (*$5)[4], (*$5)[5], (*$5)[6]); break; case 8: snprintf(buf, len, $3->c_str(), (*$5)[0], (*$5)[1], (*$5)[2], (*$5)[3], (*$5)[4], (*$5)[5], (*$5)[6], (*$5)[7]); break; case 9: snprintf(buf, len, $3->c_str(), (*$5)[0], (*$5)[1], (*$5)[2], (*$5)[3], (*$5)[4], (*$5)[5], (*$5)[6], (*$5)[7], (*$5)[8]); break; default: cerr << "more that 10 arguments to sprintf. " << "Ignoring more than 10." << endl; case 10: snprintf(buf, len, $3->c_str(), (*$5)[0], (*$5)[1], (*$5)[2], (*$5)[3], (*$5)[4], (*$5)[5], (*$5)[6], (*$5)[7], (*$5)[8], (*$5)[9]); break; } delete $5; delete $3; $$ = new string(buf); delete[] buf; } else $$ = $3; } | STRFTIME LPAREN string COMMA expr RPAREN { time_t t = $5; struct tm *tm = localtime(&t); const int len = 1024; char *buf = new char[len]; bool ok = false; if (tm) { if (strftime(buf, len, $3->c_str(), tm) != 0 ) { $$ = new string(buf); delete buf; ok = true; } } if ( !ok) { delete buf; cerr << "Cannot format " << $5 << " using format " << *$3 << endl; $$ = new string("error"); } } ; expr_list: expr { $$ = new doublevec; $$->push_back($1); } | expr_list COMMA expr { $$ = $1; $$->push_back($3); } ; opt_expr: { $$ = 0; } | expr { $$ = $1; } ; opt_linedesc: { $$ = new linedesc; $$ = 0;} | linedesc { $$ = $1;} ; opt_shift: { $$ = new shiftlist;} | shift opt_shift { $$ = $2; $$->push_back($1); } ; linedesc_elem: INVIS { $$ = new linedesc(invis); } | SOLID { $$ = new linedesc(solid); } | DOTTED opt_expr { $$ = new linedesc(dotted, $2); } | DASHED opt_expr { $$ = new linedesc(dashed, $2); } | COLOR string { $$ = new linedesc(def, 0, $2); } | FILL opt_expr { $$ = new linedesc(def, 0, 0, $2); } | FILLCOLOR string { $$ = new linedesc(def, 0, 0, 0, $2); } | THICKNESS opt_expr { $$ = new linedesc(def, 0, 0, 0, 0, $2); } ; linedesc: linedesc_elem { $$ = $1; } | linedesc linedesc_elem { $$ = combine_linedesc($1, $2); } ; draw_statement: DRAW { lex_no_coord(); } opt_ident opt_linedesc opt_display_string SEP { draw_statement($3, $4, $5); lex_coord_ok(); } ; num_list: num_line SEP { num_list($1); } ; num_line_elem: NUMBER { $$ = $1; } | MINUS NUMBER { $$ = -$2; } ; num_line: num_line_elem { $$ = new doublelist; $$->push_back($1); } | num_line num_line_elem { $$ = $1; $$->push_back($2); } | num_line COMMA num_line_elem { $$ = $1; $$->push_back($3); } ; expr: expr PLUS expr { $$ = $1 + $3; } | expr MINUS expr { $$ = $1 - $3; } | expr TIMES expr { $$ = $1 * $3; } | expr DIV expr { $$ = $1 / $3; } | expr MOD expr { $$ = static_cast($1) % static_cast($3); } | expr CARAT expr { $$ = pow($1,$3);} | MINUS expr %prec CARAT { $$ = - $2;} | FUNC0 LPAREN RPAREN { $$ = ( $1 >=0 && $1 < NF0 ) ? jtf0[$1]() : 0; } | FUNC1 LPAREN expr RPAREN { $$ = ( $1 >=0 && $1 < NF1 ) ? jtf1[$1]($3) : 0; } | FUNC2 LPAREN expr COMMA expr RPAREN { $$ = ( $1 >=0 && $1 < NF2 ) ? jtf2[$1]($3, $5) : 0; } | LPAREN expr RPAREN { $$ = $2; } | time_expr { $$ = $1; } | IDENT { doubleDictionary::iterator di; if ( (di = vars.find(*$1)) != vars.end()) $$ = *(*di).second; else { cerr << *$1 << " is uninitialized, using 0.0" << endl; $$ = 0.0; } delete $1; } | NUMBER { $$ = $1; } ; lexpr: expr { $$ = $1; } | LPAREN pure_lexpr RPAREN { $$ = $2; } | pure_lexpr { $$ = $1; } ; pure_lexpr: lexpr EQ lexpr { $$ = ($1 == $3); } | lexpr NEQ lexpr { $$ = ($1 != $3); } | lexpr LT lexpr { $$ = ($1 < $3); } | lexpr GT lexpr { $$ = ($1 > $3); } | lexpr LTE lexpr { $$ = ($1 <= $3); } | lexpr GTE lexpr { $$ = ($1 >= $3); } | lexpr AND lexpr { $$ = ($1 && $3); } | lexpr OR lexpr { $$ = ($1 || $3); } | NOT lexpr %prec PLUS { $$ = ! ( (int) $2); } | string EQ string { $$ = (*$1 == *$3); delete $1; delete $3; } | string NEQ string { $$ = (*$1 != *$3); delete $1; delete $3; } ; right_hand_side: expr SEP { $$ = $1; } | assignment_statement { $$ = $1; } ; assignment_statement: LHS right_hand_side { $$ = assignment_statement($1, $2); } ; coord_pair: expr COMMA expr { $$ = new point($1, $3, 0); } | LPAREN expr COMMA expr RPAREN { $$ = new point($2, $4, 0); } ; point: opt_coordname coord_pair { $$ = new point($2->x, $2->y, $1); delete $2; } ; time_expr: STRPTIME LPAREN string COMMA string RPAREN { struct tm tm = { 0 }; if (strptime($5->c_str(), $3->c_str(), &tm) != 0) { time_t t = mktime(&tm); $$ = t; } else { cerr << "Could not parse time/date " << *$5 << " using format " << *$3 << endl; $$ = 0.0; } } ; strmod: { $$.size = 0; $$.rel =0; $$.just = (unaligned_default) ? unaligned : 0; $$.clip = clip_default; $$.color = 0; } | strmod SIZE expr { $$.size = $3; $$.rel = ($3<0); } | strmod SIZE PLUS expr { $$.size = $4; $$.rel = 1; } | strmod LJUST { $$.just |= (int) ljust; } | strmod RJUST { $$.just |= (int) rjust; } | strmod ABOVE { $$.just |= (int) above; } | strmod BELOW { $$.just |= (int) below; } | strmod ALIGNED { $$.just |= (int) aligned; } | strmod UNALIGNED { $$.just |= (int) unaligned; } | strmod CLIPPED { $$.clip = true; } | strmod UNCLIPPED { $$.clip = false; } | strmod COLOR STRING { $$.color = $3; } ; strlist: string strmod { DisplayString *s; s = new DisplayString(*$1,$2.just,$2.size, $2.rel, $2.clip, $2.color); delete $1; $$ = new stringlist; $$->push_back(s); } | strlist string strmod { $$ = combine_strings($1, $2, $3); } ; plot_statement: strlist AT point SEP { the_graph->new_plot($1,$3); } | PLOT opt_expr opt_display_string AT point SEP { plot_statement($2, $3, $5); } ; next_statement: NEXT opt_ident AT point opt_linedesc SEP { next_statement($2, $4, $5); } ; size_elem: HT expr { $$ = new frame; $$->ht = $2; $$->wid = 0; } | WID expr { $$ = new frame; $$->wid = $2; $$->ht = 0; } ; size: size_elem { $$ = $1; } | size size_elem { $$ = $1; // Fill in non-default ht/wid if ( $2->ht != 0 ) $$->ht = $2->ht; if ( $2->wid != 0 ) $$->wid = $2->wid; } ; side: TOP { $$ = top_side;} | BOTTOM { $$= bottom_side;} | LEFT { $$ = left_side;} | RIGHT { $$ = right_side; } ; final_size: size { // This rule combines the explicit size settings with // the defaults. We create a new frame to have access // to the default sizes without needing to code them // explicitly (they're always implicit in a default // frame). N. B. that frames created by size (and // size_elem) use 0 to indicate no change to the ht or // wid. $$ = new frame; if ( $1->ht != 0) $$->ht = $1->ht; if ( $1->wid != 0) $$->wid = $1->wid; delete $1; } ; sides: side linedesc { $$ = new frame; $$->desc[$1] = *$2; delete $2; } | sides side linedesc { if ( !$1 ) $$ = new frame; else $$ = $1; $$->desc[$2] = *$3; delete $3; } ; /* Though this looks kludgy as Hell, it's about as clean as I can make it. Th * eproblem is that liesdescs are composed of lists of linedesc elements, and 2 * linedescs next to each other are impossible to tell apart. So, the global * linedesc for the frame cannot sit next to one of the linedescs for the * sides. for example is 'frame top dotted color "green"' a green frame with a * dotted top or a frame with a dotted green top? Writing a single list rule to * capture that constraint requires you to know where the size elements appear * in that list and life is horrible and complex. If it's even reasonably * tractable. This enumeration captures many of the possibilities that are * sane and minimizes the code complexity. You can't say things like 'frame * wid 3 dotted ht 5' to get a dotted 3x5 frame, but either 'frame dotted ht 3 * wid 5' or 'frame wid 3 ht 5 dotted' work. * This comment is primarily here to prevent me from wasting another hour * trying to clean this up. */ frame_statement: FRAME SEP { process_frame(0, 0, 0); } | FRAME linedesc SEP { process_frame($2, 0, 0); } | FRAME final_size SEP { process_frame(0, $2, 0); } | FRAME sides SEP { process_frame(0, 0, $2); } | FRAME final_size sides SEP { process_frame(0, $2, $3); } | FRAME linedesc sides SEP { process_frame($2, 0, $3); } | FRAME linedesc final_size SEP { process_frame($2, $3, 0); } | FRAME final_size linedesc SEP { process_frame($3, $2, 0); } | FRAME linedesc final_size sides SEP { process_frame($2, $3, $4);} | FRAME final_size linedesc sides SEP { process_frame($3, $2, $4); } ; shift: UP expr { $$ = new shiftdesc(top_side, $2); } | DOWN expr { $$ = new shiftdesc(bottom_side, $2); } | LEFT expr { $$ = new shiftdesc(left_side, $2); } | RIGHT expr { $$ = new shiftdesc(right_side, $2); } ; tickdir: IN { $$ = -1; } | OUT { $$ = 1; } ; direction: { $$ = 0.125; } | tickdir opt_expr { if ( $2 == 0 ) $$ = $1 * 0.125; else $$ = $1 * $2; } ; ticklist: expr opt_display_string { $$ = ticklist_elem($1, $2, 0); } | ticklist COMMA expr opt_display_string { $$ = ticklist_elem($3, $4, $1); } ; by_clause: { $$.op = PLUS; $$.expr = 1; } | BY expr { $$.op = PLUS; if ( $2 != 0.0 ) $$.expr = $2; else $$.expr = 1; } | BY PLUS expr { $$.op = PLUS; $$.expr = $3; } | BY TIMES expr { $$.op = TIMES; $$.expr = $3; } | BY DIV expr { $$.op = DIV; $$.expr = $3; } | BY MOD expr { $$.op = MOD; $$.expr = $3; } ; tickat: AT opt_coordname ticklist { $$ = $3; for (ticklist::iterator t= $3->begin(); t != $3->end(); t++) (*t)->c = $2; } ; tickfor: from opt_coordname expr TO expr by_clause opt_display_string { $$ = tick_for($2, $3, $5, $6, $7); } ; tickdesc : tickat { $$ = $1;} | tickfor { $$= $1; } ; autotick: ON opt_ident { coordinateDictionary::iterator ci; if ( $2 ) { ci = the_graph->coords.find(*$2); if ( ci != the_graph->coords.end()) $$ = (*ci).second; else { yyerror("Name must name a coordinate space"); } } else $$ = 0; } | { $$ = 0; } ; ticks_statement: TICKS side direction opt_shift tickdesc SEP { ticks_statement($2, $3, $4, $5); } | TICKS OFF SEP { for ( int i = 0; i< 4; i++ ) the_graph->base->tickdef[i].size = 0; } | TICKS side OFF SEP { the_graph->base->tickdef[$2].size = 0; } | TICKS side direction autotick SEP { the_graph->base->tickdef[$2].size = $3; if ( $4 ) the_graph->base->tickdef[$2].c = $4; } ; opt_tick_off: { $$ = 0; } | TICKS OFF { $$ = 1; } ; grid_statement: GRID side opt_tick_off opt_linedesc opt_shift tickdesc SEP { grid_statement($2, $3, $4, $5, $6); } | GRID side opt_tick_off opt_linedesc opt_shift autotick SEP { grid_statement($2, $3, $4, $5, 0); // Because turning on a grid on a given side disables // automatic tick generation there, this is sets up // that side with the proper coordinates. if ( $6 ) the_graph->base->griddef[$2].c = $6; } ; label_statement: LABEL side strlist opt_shift SEP { shiftlist *sl = new shiftlist; shiftdesc *sd; for (stringlist::iterator s = $3->begin(); s != $3->end(); s++) if ( ! ((*s)->j & unaligned) ) (*s)->j |= aligned; // Copy the label shifts into the frame while (!$4->empty() ) { sd = $4->front(); $4->pop_front(); sl->push_back(sd); } delete $4; the_graph->base->label[$2]->push_back(new label($3, sl)); } ; radius_spec: { $$ = 0.025; } | RADIUS expr { $$ = $2; } ; circle_statement: CIRCLE AT point radius_spec opt_linedesc SEP { the_graph->new_circle($3,$4,$5); delete $3; delete $5; } ; line_token: LINE { $$ = 1; } | ARROW { $$ = 0; } ; line_statement: line_token opt_linedesc FROM point TO point opt_linedesc SEP { line_statement($1, $2, $4, $6, $7); } ; x_axis_desc: { $$.which=none; } | XDIM expr COMMA expr { $$ = axis_description(x_axis, $2, $4); } ; y_axis_desc: { $$.which=none; } | YDIM expr COMMA expr { $$ = axis_description(y_axis, $2, $4); } ; log_list: log_list log_desc { $$ = combine_logs($1, $2); } | { $$ = none; } ; log_desc: LOG_X { $$ = x_axis; } | LOG_Y { $$ = y_axis; } | LOG_LOG { $$ = both; } ; coord_statement: COORD opt_ident x_axis_desc y_axis_desc log_list SEP { coord_statement($2, $3, $4, $5); delete $2; } ; until_clause: { $$ = 0; } | UNTIL string { unquote($2); $$ = new copydesc; $$->t = copydesc::until; $$->s = $2; } | string { unquote($1); $$ = new copydesc; $$->t = copydesc::fname; $$->s = $1; } ; // This is probably long enough to merit being removed to // grap_parse.cc, but because there are multiple actions in the same // rule, I want to leave them here where I can see how they // interrelate. copy_statement: COPY string SEP { unquote($2); if (!include_file($2, false)) return 0; } | COPY UNTIL string SEP { unquote($3); lex_begin_copy($3); } COPYTEXT { string s=""; while ($6 && !$6->empty() ) { string *ss; ss = $6->front(); $6->pop_front(); if ( ss ) { s+= *ss; s+= '\n'; delete ss; ss = 0; } } include_string(&s, 0, GINTERNAL); delete $6; } | COPY until_clause THRU { lex_hunt_macro(); } MACRO until_clause SEP { copydesc *c = 0; // To shut the compiler up about uninit if ( $2 && $6 ) { delete $2; delete $6; yyerror("Only specify 1 until or filename\n"); } else c = ($2) ? $2 : $6; // The else handles files with neither else clause, copying // text to the trailing .G2. Fix from Bruce Lilly if ( c ) { // lex_begin_copy takes command of the string that's // passed to it, so don't delete it. (I don't // remember why I did that...) if ( c->t == copydesc::until ) { lex_begin_copy(c->s); c->s = 0; } else { lex_begin_copy(0); include_file(c->s, false); } delete c; } else lex_begin_copy(0); } COPYTEXT { string *s; string *t; int lim; char end; stack st; while ( $9 && !$9->empty() ) { int i = 0; t = new string; s = $9->front(); $9->pop_front(); lim = s->length(); while ( i < lim ) { if ( (*s)[i] == ' ' || (*s)[i] == '\t' ) { if ( t->length() ) { if ( $5->add_arg(t)) t = new string; } } else *t += (*s)[i]; i++; } if ( t->length() ) $5->add_arg(t); else if (t) delete t; t = $5->invoke(); // "here" macros should end with a SEP. If the // user hasn't done so, we add a SEP for them. // Even named macros should get a sep when they're // copied through, end = (*t)[t->length()-1]; if ( end != ';' && end != '\n' ) *t += ';'; // Because include string stacks the strings, we stack them // here and call include_string in reverse order to ensure // correct ordered execution of multiple lines. st.push(t); delete s; } delete $9; while ( !st.empty() ) { include_string(st.top(), 0, GMACRO); delete st.top(); st.pop(); } // don't delete defined macros if ( !$5->name) delete $5; } ; define_statement: DEFINE { lex_no_coord(); lex_no_macro_expansion();} IDENT { lex_begin_macro_text(); } TEXT SEP { lex_macro_expansion_ok(); lex_coord_ok(); define_macro($3, $5); } ; undefine_statement: UNDEFINE { lex_no_coord(); lex_no_macro_expansion(); } IDENT SEP { lex_coord_ok(); lex_macro_expansion_ok(); macros.erase(*$3); delete $3; } ; sh_statement: SH { lex_begin_macro_text(); } TEXT SEP { int len = $3->length()+1 ; char *sys = new char [len]; int i=0; int srv = 0; // String to char* while ((sys[i] = (*$3)[i])) i++; delete $3; if ( (srv = system(sys)) ) cerr << "Warn: system returned " << srv << endl; } ; else_clause: { $$ = 0; } | ELSE {lex_begin_macro_text(); } TEXT { // force else clause to end with a SEP *$3+= ';'; $$ = $3; } ; if_statement: IF lexpr THEN { lex_begin_macro_text(); } TEXT else_clause SEP { // force all if blocks to be terminated by a SEP. *$5 += ';'; // We use epsilon in loop tests if ( fabs($2) > epsilon ) include_string($5,0,GINTERNAL); else if ( $6 ) include_string($6,0,GINTERNAL); delete $5; delete $6; } ; for_statement: FOR IDENT from expr TO expr by_clause DO { lex_begin_macro_text(); } TEXT SEP { for_statement($2, $4, $6, $7, $10); delete $2; } ; graph_statement: GRAPH { lex_no_coord(); } IDENT { lex_begin_rest_of_line(); } REST SEP { if ( !first_line ) { // Only draw the graph and clear its internals if // it is visible. This allows a user to declare // things like coordinate spaces before the graph // itself is named. This is a compatibility // feature for DWB grap. if ( the_graph->is_visible() ) { the_graph->draw(0); the_graph->init($3, $5); init_dict(); } else the_graph->setname($3); } else { the_graph->init($3, $5); init_dict(); } if ( $3 ) delete $3; if ( $5 ) delete $5; } ; print_statement: PRINT print_param SEP ; print_param: string { unquote($1); cerr << *$1 << endl; } | expr { cerr << $1 << endl; } ; pic_statement: PIC { lex_begin_rest_of_line(); } REST SEP { the_graph->passthru_string(*$3); delete $3;} ; troff_line: TROFF SEP { the_graph->passthru_string(*$1); delete $1;} ; bar_dir: RIGHT { $$ = right_side; } | UP { $$ = top_side; } ; /* NB: the tokenizer only allows one instance of wid or base or ht per line * (you could have all 3) */ bar_param: HT expr { $$ = new bar_param; $$->ht = $2; $$->have_ht = true; } | WID expr { $$ = new bar_param; $$->wid = $2; } | BASE expr { $$ = new bar_param; $$->base = $2; } ; bar_params: bar_param { $$ = $1; } | bar_params bar_param { $$ = $1; if ( $2 ) { if ($2->have_x ) { $$->x = $2->x; $$->have_x = true; } if ($2->have_ht ) { $$->ht = $2->ht; $$->have_ht = true; } if ( $2->wid != 1.0 ) { $$->wid = $2->wid; } if ( $2->base != 0.0 ) { $$->base = $2->base; } delete $2; } } ; bar_statement: BAR point COMMA point opt_linedesc SEP { // The point parsing has already autoscaled the // coordinate system to include those points. the_graph->new_box($2, $4, $5); delete $2; delete $4; delete $5; } | BAR bar_dir opt_coordname expr bar_params opt_linedesc SEP { if ( !$5 || !$5->have_ht ) { yyerror("bar must have a position and ht "); } else { bar_statement($3, $2, $4, $5->ht, $5->wid, $5->base, $6); } delete $5; } ; void_function: VFUNC1 LPAREN expr RPAREN { if ( $1 >=0 && $1 < NVF1 ) jtvf1[$1]($3); } ; %% grap-1.46/strerror.cc0000664000175000017500000000021013163474043011507 00000000000000#include char *strerror(int errnum) { static char rv[100]; sprintf(rv, "error number %d", errnum); return rv; } grap-1.46/grap.doc0000664000175000017500000010612713670047257010762 00000000000000.\"-*-nroff-*- .\" This file is (c) 1998-2006 Ted Faber (faber@lunabase.org) see .\" COPYRIGHT for the full copyright and limitations of liabilities. .Dd March 11, 2006 .Os .Dt GRAP 1 .Sh NAME .Nm grap .Nd Kernighan and Bentley's language for typesetting graphs .Sh SYNOPSIS .Nm .Op Fl d Ar defines_file .Op Fl D .Op Fl l .Op Fl M Ar include path .Op Fl R .Op Fl r .Op Fl v .Op Fl u .Op Fl C .Op Fl c .Op Fl h .Op Ar filename ... .Sh DESCRIPTION .Nm is an implementation of Kernighan and Bentley's language for typesetting graphs, as described in ``Grap-A Language for Typesetting Graphs, Tutorial and User Manual,'' by Jon L. Bentley and Brian W. Kernighan, revised May 1991, which is the primary source for information on how to use .Nm grap . As of this writing, it is available electronically at .Li http://www.kohala.com/start/troff/cstr114.ps . Additional documentation and examples, packaged with .Nm , may have been installed locally as well. If available, paths to them can be displayed using .Nm .Fl h or .Nm .Fl v (or .Nm .Fl -help / .Nm .Fl -version ) .Pp This version is a black box implementation of .Nm grap , and some inconsistencies are to be expected. The remainder of this manual page will briefly outline the .Nm language as implemented here. .Pp .Nm is a .Xr pic 1 pre-processor. It takes commands embedded in a .Xr troff 1 source file which are surrounded by .Ic .G1 and .Ic .G2 macros, and rewrites them into .Xr pic commands to display the graph. Other lines are copied. Output is always to the standard output, which is usually redirected. Input is from the given .Ar filename Ns No s , which are read in order. A .Ar filename of .Fl is the standard input. If no .Ar filename Ns No s are given, input is read from the standard input. .Pp Because .Nm is a .Xr pic preprocessor, and GNU .Xr pic will output TeX, it is possible to use .Nm with TeX. .Pp The .Fl d option specifies a file of macro definitions to be read at startup, and defaults to /usr/local/share/grap/grap.defines . The .Fl D option inhibits the reading of any initial macros file (the .Fl l flag is a synonym for .Fl D , though I do not remember why). The defines file can also be given using the .Ev GRAP_DEFINES environment variable. (See below). .Pp .Fl v prints the version information on the standard output and exits. .Fl -version is a synonym for .Fl v . .Pp .Fl u makes labels unaligned by default. This version of .Nm uses new features of GNU .Xr pic to align the left and right labels with the axes, that is that the left and right labels run at right angles to the text of the paper. This may be useful in porting old .Nm programs. .Fl c makes plot strings unclipped by default. Some versions of .Nm allow users to place a string anywhere in the coordinate space, rather than only in the frame. By default this version of .Nm does not plot any string centered outside the frame. .Fl c allows strings to be placed anywhere. See also the .Ic clipped and .Ic unclipped string modifiers described in the .Ic plot statement. .Pp .Fl M is followed by a colon-separated list of directories used to search for relative pathnames included via .Ic copy . The path is also used to locate the defines file, so if the .Fl d changes the defines file name to a relative name, it will be searched for in the path given by .Fl M . The search path always includes the current directory, and by default that directory is searched last. .Pp All numbers used internally by .Nm are double precision floating point values. Sometimes using floating point numbers has unintended consequences. To help avoid these problems, .Nm can use two thresholds for comparison of floating point numbers, set by .Fl R or .Fl r . The .Fl R flag sets coarse comparison mode, which is suitable for most applications. If you are plotting small values \(en less than 1e-6 or so \(en consider using .Fl r which uses very fine comparisons between numbers. You may also want to rescale your plotted values to be larger in magnitude. The coarse comarisons are used by default. .Pp To be precise, the value by which two numbers must differ for .Nm to consider them not equal is called the comparison limit and the smallest non-zero number is called the minimum value. The values a given version of .Nm uses for these are included in the output of .Fl v or .Fl h . .Pp All .Nm commands are included between .Ic .G1 and .Ic .G2 macros, which are consumed by .Nm grap . The output contains .Xr pic between .Ic .PS and .Ic .PE macros. Any arguments to the .Ic .G1 macro in the input are arguments to the .Ic .PS macro in the output, so graphs can be scaled just like .Xr pic diagrams. If .Fl C is given, any macro beginning with \&.G1 or \&.G2 is treated as a \&.G1 or \&.G2 macro, for compatibility with old versions of troff. Using .Fl C also forces pure troff syntax on embedded font change commands when strings have the .Ic size attribute, and all strings to be .Ic unclipped . .Pp The .Fl h flag prints a brief help message and exits. .Fl -help is a synonym for .Fl h . .Pp It is possible for someone to cause .Nm to fail by passing a bad format string and data to the .Ic sprintf command. If .Nm is integrated as part of the printing system, this could conceivably provided a path to breaching security on the machine. If you choose to use .Nm as part of a printing system run by the super-user, you should disable .Ic sprintf commands. This can be done by calling .Nm with the .Fl S flag, setting the .Ev GRAP_SAFER environment variable, or compiling with the GRAP_SAFER preprocessor symbol defined. (The GNU configure script included with .Nm will define that preprocessor symbol if the .Fl -with-grap-safe option is given.) .Pp The .Nm commands are sketched below. Refer to Kernighan and Bentley's paper for the details. .Pp New versions of .Xr groff 1 will invoke .Nm if .Fl G is given. .Ss Commands .Pp Commands are separated from one another by newlines or semicolons (;). .Pp .Ic frame .Op Ar line_description .Oo .Bk -words .Cm ht Ar height No \(or Cm wid Ar width .Ek .Oc .Oo .Bk -words .Oo .Sm off .Cm ( top No \(or Cm bottom No \(or .Cm left No \(or .Sm on .Cm right ) .Ar line_description .Ek .Oc \&... .Oc .sp .Ic frame .Oo .Bk -words .Cm ht Ar height No \(or Cm wid Ar width .Ek .Oc .Op Ar line_description .Oo .Bk -words .Oo .Sm off .Cm ( top No \(or Cm bottom No \(or .Cm left No \(or .Sm on .Cm right ) .Ar line_description .Ek .Oc \&... .Oc .Bd -filled -offset indent This describes how the axes for the graph are drawn. A .Ar line_description is a .Xr pic line description, e.g., .Li dashed .Li 0.5 , or the literal .Li solid . It may also include a .Ic color keyword followed by the color to draw the string in double quotes. Any color understood by the underlying groff system can be used. Color can only be used under GNU pic, and is not available in compatibility mode. Similarly, for pic implementations that understand .Ic thickness , that attribute may be used with a real valued parameter. .Ic Thickness is not available in compatibility mode. .Pp If the first .Ar line_description is given, the frame is drawn with that style. The default is .Li solid . The height and width of the frame can also be specified in inches. The default line style can be over-ridden for sides of the frame by specifying additional parameters to .Ic frame . .Pp If no plotting commands have been given before the .Ic frame command is issued, the frame will be output at that point in the plotting stream relative to embedded .Xr troff or .Xr pic commands. Otherwise the frame is output before the first plotted object (even invisible ones). .Pp .Ic ht and .Ic wid are in inches by default, but can be any .Xr groff unit. If omitted, the dimensions are 2 inches high by 3 inches wide. .Ed .Pp .Ic coord .Op Ar name .Op Cm x Ar expr , expr .Op Cm y Ar expr , expr .Oo .Cm log x No \(or .Cm log y No \(or .Cm log log .Oc .Bd -filled -offset indent The .Ic coord command specifies a new coordinate system or sets limits on the default system. It defines the largest and smallest values that can be plotted, and therefore the scale of the data in the frame. The limits for the x and y coordinate systems can be given separately. If a .Ar name is given, that coordinate system is defined, if not the default system is modified. .Pp A coordinate system created by one .Ic coord command may be modified by subsequent .Ic coord commands. A .Nm program may declare a coordinate space using .Ic coord , .Ic copy a file of data through a macro that plots the data and finds its maxima and minima, and then define the size of the coordinate system with a second .Ic coord statement. .Pp This command also determines if a scale is plotted logarithmically. .Cm log log means the same thing as .Cm log x log y . .Ed .Pp .Ic draw .Op Ar line_name .Op Ar line_description .Op Ar plot_string .Bd -filled -offset indent The .Ic draw command defines the style with which a given line will be plotted. If .Ar line_name is given, the style is associated with that name, otherwise the default style is set. .Ar line_description is a .Xr pic line description, and the optional .Ar plot_string is a string to be centered at each point. The default line description is .Li invis , and the default plotting string is a centered bullet, so by default each point is a filled circle, and they are unconnected. If points are being connected, each .Ic draw command ends any current line and begins a new one. .Pp When defining a line style, that is the first .Ic draw command for a given line name, specifying no plot string means that there are to be no plot strings. Omitting the plot string on subsequent .Ic draw commands addressing the same named line means not to change the plot string. If a line has been defined with a plot string, and the format is changed by a subsequent .Ic draw statement, the plot string can be removed by specifying "" in the .Ic draw statement. .Pp The plot string can have its format changed through several string_modifiers. String_modifiers are described in the description of the .Ic plot command. .Pp The standard defines file includes several macros useful as plot strings, including .Ic bullet , .Ic square , and .Ic delta . .Pp .Ic new is a synonym for .Ic draw . .Ed .Pp .Ic next .Op Ar line_name .Cm at .Op Ar coordinates_name .Ar expr , expr .Op Ar line_description .Bd -filled -offset indent The .Ic next command plots the given point using the line style given by .Ar line_name , or the default if none is given. If .Ar line_name is given, it should have been defined by an earlier .Ic draw command, if not a new line style with that name is created, initialized the same way as the default style. The two expressions give the point's x and y values, relative to the optional coordinate system. That system should have been defined by an earlier .Ic coord command, if not, grap will exit. If the optional .Ar line_description is given, it overrides the style's default line description. You cannot over-ride the plotting string. To use a different plotting string use the .Ic plot command. .Pp The coordinates may optionally be enclosed in parentheses: .Ar ( expr , expr ) .Ed .Pp .Ar quoted_string .Op Ar string_modifiers .Oo .No , Ar quoted_string .Oo .Ar string_modifiers .Oc .Oc \&... .Cm at .Op Ar coordinates_name .Ar expr , expr .Pp .Ic plot .Ar expr .Op Ar format_string .Cm at .Op Ar coordinates_name .Ar expr , expr .Bd -filled -offset indent These commands both plot a string at the given point. In the first case the literal strings are stacked above each other. The string_modifiers include the .Xr pic justification modifiers .Ns No ( Ic ljust , .Ic rjust , .Ic above , and .Ic below Ns No ), and absolute and relative .Li size modifiers. See the .Xr pic documentation for the description of the justification modifiers. .Nm also supports the .Ic aligned and .Ic unaligned modifiers which are briefly noted in the description of the .Ic label command. .Pp The standard defines file includes several macros useful as plot strings, including .Ic bullet , .Ic square , and .Ic delta . .Pp Strings placed by either format of the .Ic plot command are restricted to being within the frame. This can be overridden by using the .Ic unclipped attribute, which allows a string to be plotted in or out of the frame. The .Fl c and .Fl C flags set .Ic unclipped on all strings, and to prevent a string from being plotted outside the frame when those flags are active, the .Ic clipped attribute can be used to retore clipping behavior. Though .Ic clipped or .Ic unclipped can be applied to any string, it only has meaning for .Ic plot statements. .Pp .Li size .Ar expr sets the string size to .Ar expr points. If .Ar expr is preceded by a + or -, the size is increased or decreased by that many points. .Pp If .Ic color and a color name in double quotes appears, the string will be rendered in that color under a version of GNU troff that supports color. Color is not available in compatibility mode. .Pp In the second version, the .Ar expr is converted to a string and placed on the graph. .Ar format_string is a .Xr printf 3 format string. Only formatting escapes for printing floating point numbers make sense. The format string is only respected if the .Ic sprintf command is also active. See the description of .Ic sprintf for the various ways to disable it. .Ic Plot and .Ic sprintf respond differently when .Nm is running safely. .Ic Sprintf ignores any arguments, passing the format string through without substitution. .Ic plot ignores the format string completely, plotting .Ar expr using the .Qq %g format. .Pp Points are specified the same way as for .Ic next commands, with the same consequences for undefined coordinate systems. .Pp The second form of this command is because the first form can be used with a .Nm .Ic sprintf expression (See .Sx Expressions ) . .Ed .Pp .Ic ticks .Sm off .Xo ( Cm left No \(or Cm right .No \(or Cm top No \(or Cm bottom ) .Xc .Oo .Sm on .Xo ( Cm in Ns No \(or Ns Cm out ) .Xc .Op Ar expr .Oc .Sm off .Oo .Cm on \(or Cm auto .Sm on .Ar coord_name .Oc .Pp .Ic ticks .Sm off .Xo ( Cm left No \(or Cm right No \(or Cm top No \(or Cm bottom ) .Xc .Sm on .Xo ( Cm in Ns No \(or Ns Cm out ) .Xc .Op Ar expr .Oo .Cm up Ar expr No \(or .Cm down Ar expr No \(or .Cm left Ar expr No \(or .Cm right Ar expr .Oc .Cm at .Op Ar coord_name .Ar expr .Op Ar format_string .Oo .Oo .No , Ar expr .Oo .Ar format_string .Oc .Oc .No ... .Oc .Pp .Ic ticks .Sm off .Xo ( Cm left No \(or Cm right .No \(or Cm top No \(or Cm bottom ) .Xc .Sm on .Xo ( Cm in Ns No \(or Ns Cm out ) .Xc .Op Ar expr .Oo .Cm up Ar expr No \(or .Cm down Ar expr No \(or .Cm left Ar expr No \(or .Cm right Ar expr .Oc .Cm from .Op coord_name .Ar start_expr .Cm to .Ar end_expr .Oo .Cm by .Sm off .Oo .No + \(or - \(or * \(or / .Sm on .Oc .Ar by_expr .Oc .Op format_string .Pp .Ic ticks .Sm off .Oo .Cm left Xo No \(or Cm right .No \(or Cm top No \(or Cm bottom .Oc .Xc .Sm on .Cm off .Bd -filled -offset indent This command controls the placement of ticks on the frame. By default, ticks are automatically generated on the left and bottom sides of the frame. .Pp The first version of this command turns on the automatic tick generation for a given side. The .Cm in or .Cm out parameter controls the direction and length of the ticks. If a .Ar coord_name is specified, the ticks are automatically generated using that coordinate system. If no system is specified, the default coordinate system is used. As with .Ic next and .Ic plot , the coordinate system must be declared before the .Ic ticks statement that references it. This syntax for requesting automatically generated ticks is an extension, and will not port to older .Nm implementations. .Pp The second version of the .Ic ticks command overrides the automatic placement of the ticks by specifying a list of coordinates at which to place the ticks. If the ticks are not defined with respect to the default coordinate system, the .Ar coord_name parameter must be given. For each tick a .Xr printf 3 style format string can be given. The .Ar format_string defaults to .Qq %g . The format string can also take string modifiers as described in the .Ic plot command. To place ticks with no labels, specify .Ar format_string as .Qq \& . .Pp If .Ic sprintf is disabled, .Ic ticks behaves as .Ic plot with respect to the format string. .Pp The labels on the ticks may be shifted by specifying a direction and the distance in inches to offset the label. That is the optional direction and expression immediately preceding the .Cm at . .Pp The third format of the .Ic ticks command over-rides the default tick generation with a set of ticks ar regular intervals. The syntax is reminiscent of programming language for loops. Ticks are placed starting at .Ar start_expr ending at .Ar end_expr one unit apart. If the .Cm by clause is specified, ticks are .Ar by_expr units apart. If an operator appears before .Ar by_expr each tick is operated on by that operator instead of +. For example .Bd -literal -offset indent-two ticks left out from 2 to 32 by *2 .Ed .Pp will put ticks at 2, 4, 8, 16, and 32. If .Ar format_string is specified, all ticks are formatted using it. .Pp The parameters preceding the .Cm from act as described above. .Pp The .Cm at and .Cm for forms of tick command may both be issued on the same side of a frame. For example: .Bd -literal -offset indent-two ticks left out from 2 to 32 by *2 ticks left in 3, 5, 7 .Ed .Pp will put ticks on the left side of the frame pointing out at 2, 4, 8, 16, and 32 and in at 3, 5, and 7. .Pp The final form of .Ic ticks turns off ticks on a given side. If no side is given the ticks for all sides are cancelled. .Pp .Ic tick is a synonym for .Ic ticks . .Ed .Pp .Ic grid .Sm off .Xo ( Cm left No \(or Cm right .No \(or Cm top No \(or Cm bottom ) .Xc .Sm on .Op Li ticks off .Op Ar line_description .Oo .Cm up Ar expr No \(or .Cm down Ar expr No \(or .Cm left Ar expr No \(or .Cm right Ar expr .Oc .Oo .Sm off .Cm on \(or Cm auto .Sm on .Op Ar coord_name .Oc .Pp .Ic grid .Sm off .Xo ( Cm left No \(or Cm right .No \(or Cm top No \(or Cm bottom ) .Xc .Sm on .Op Li ticks off .Op Ar line_description .Oo .Cm up Ar expr No \(or .Cm down Ar expr No \(or .Cm left Ar expr No \(or .Cm right Ar expr .Oc .Cm at .Op Ar coord_name .Ar expr .Op Ar format_string .Oo .Oo .No , Ar expr .Oo .Ar format_string .Oc .Oc .No ... .Oc .Pp .Ic grid .Sm off .Xo ( Cm left No \(or Cm right .No \(or Cm top No \(or Cm bottom ) .Xc .Sm on .Op Li ticks off .Op Ar line_description .Oo .Cm up Ar expr No \(or .Cm down Ar expr No \(or .Cm left Ar expr No \(or .Cm right Ar expr .Oc .Cm from .Op coord_name .Ar start_expr .Cm to .Ar end_expr .Oo .Cm by .Sm off .Oo .No + \(or - \(or * \(or / .Sm on .Oc .Ar by_expr .Oc .Op format_string .Bd -filled -offset indent The .Ic grid command is similar to the .Ic ticks command except that .Ic grid specifies the placement of lines in the frame. The syntax is similar to .Ic ticks as well. .Pp By specifying .Li ticks off in the command, no ticks are drawn on that side of the frame. If ticks appear on a side by default, or have been declared by an earlier .Ic ticks command, .Ic grid does not cancel them unless .Li ticks off is specified. .Pp Instead of a direction for ticks, .Ic grid allows the user to pick a line description for the grid lines. The usual .Xr pic line descriptions are allowed. .Pp Grids are labelled by default. To omit labels, specify the format string as .Qq \& . .Pp If .Ic sprintf is disabled, .Ic grid behaves as .Ic plot with respect to the format string. .Ed .Pp .Ic label .Sm off .Xo ( Cm left No \(or Cm right .No \(or Cm top No \(or Cm bottom ) .Xc .Sm on .Ar quoted_string .Op Ar string_modifiers .Oo .No , Ar quoted_string .Oo .Ar string_modifiers .Oc .Oc \&... .Oo .Cm up Ar expr No \(or .Cm down Ar expr No \(or .Cm left Ar expr No \(or .Cm right Ar expr .Oc .Bd -filled -offset indent The .Ic label command places a label on the given axis. It is possible to specify several labels, which will be stacked over each other as in .Xr pic . The final argument, if present, specifies how many inches the label is shifted from the axis. .Pp By default the labels on the left and right labels run parallel to the frame. You can cancel this by specifying .Li unaligned as a .Ar string_modifier . .Ed .Pp .Ic circle .Cm at .Op Ar coordinate_name .Ar expr , expr .Op Cm radius Ar expr .Op Ar linedesc .Bd -filled -offset indent This draws an circle at the point indicated. By default, the circle is small, 0.025 inches. This can be over-ridden by specifying a radius. The coordinates of the point are relative to the named coordinate system, or the default system if none is specified. .Pp This command has been extended to take a line description, e.g., .Li dotted . It also accepts the filling extensions described below in the .Ic bar command. It will also accept a .Ic color keyword that gives the color of the outline of the circle in double quotes and a .Ic fillcolor command that sets the color to fill the circle with similarly. Colors are only available when compatibility mode is off, and using a version of GNU pic that supports color. .Ed .Pp .Ic line .Op Ar line_description .Cm from .Op Ar coordinate_name .Ar expr , expr .Cm to .Op Ar coordinate_name .Ar expr , expr .Op Ar line_description .Pp .Ic arrow .Op Ar line_description .Cm from .Op Ar coordinate_name .Ar expr , expr .Cm to .Op Ar coordinate_name .Ar expr , expr .Op Ar line_description .Bd -filled -offset indent This draws a line or arrow from the first point to the second using the given style. The default line style is .Li solid . The .Ar line_description can be given either before the .Cm from or after the .Cm to clause. If both are given the second is used. It is possible to specify one point in one coordinate system and one in another, note that if both points are in a named coordinate system (even if they are in the same named coordinate system), both points must have .Ar coordinate_name given. .Ed .Pp .Pp .Ic copy .Op Qq Ar filename .Op Cm until Qq Ar string .Op Cm thru Ar macro .Bd -filled -offset indent The .Ic copy command imports data from another file into the current graph. The form with only a filename given is a simple file inclusion; the included file is simply read into the input stream and can contain arbitrary .Nm commands. The more common case is that it is a number list; see .Sx Number Lists below. .Pp The second form takes lines from the file, splits them into words delimited by one or more spaces, and calls the given macro with those words as parameters. The macro may either be defined here, or be a macro defined earlier. See .Sx Macros for more information on macros. .Pp The .Ar filename may be omitted if the .Cm until clause is present. If so the current file is treated as the input file until .Ar string is encountered at the beginning of the line. .Pp .Ic copy is one of the workhorses of .Nm grap . Check out the paper and .Pa /usr/local/share/examples/grap for more details. Confirm the location of the examples directory using the .Fl v flag. .Ed .Ic print .Sm off .Ar ( expr \(or string ) .Sm on .Bd -filled -offset indent Prints its argument to the standard error. .Ed .Pp .Ic sh Ar block .Bd -filled -offset indent This passes .Ar block to .Xr sh 1 . Unlike K&B .Nm no macro or variable expansion is done. I believe that this is also true for GNU .Xr pic version 1.10. See the .Sx Macros section for information on defining blocks. .Ed .Pp .Ic pic Ar pic_statement .Bd -filled -offset indent This issues the given .Xr pic statements in the enclosing .Ic .PS and .Ic .PE at the point where the command is issued. .Pp Statements that begin with a period are considered to be .Xr troff statements and are output in the enclosing .Ic .PS and .Ic .PE at the point where the command appears. .Pp For the purposes of relative placement of .Xr pic or .Xr troff commands, the frame is output immediately before the first plotted object, or the .Ic frame statement, if any. If the user specifies .Xr pic or .Xr troff commands and neither any plotable object nor a .Ic frame command, the commands will not be output. .Ed .Pp .Ic graph Ar Name pic_commands .Bd -filled -offset indent This command is used to position graphs with respect to each other. The current graph is given the .Xr pic name .Ar Name (names used by .Xr pic begin with capital letters). Any .Xr pic commands following the graph are used to position the next graph. The frame of the graph is available for use with .Xr pic name .Li Frame. The following places a second graph below the first: .Bd -literal -offset indent-two graph Linear [ graph description ] graph Exponential with .Frame.n at \\ Linear.Frame.s - (0, .05) [ graph description ] .Ed .Ed .Pp .Ar name = expr .Bd -filled -offset indent This assigns .Ar expr to the variable .Ar name . .Nm has only numeric (double) variables. .Pp Assignment creates a variable if it does not exist. Variables persist across graphs. Assignments can cascade; .Li a = b = 35 assigns 35 to .Li a and .Li b . .Ed .Pp .Ic bar .Sm off .No ( Cm up No \(or Cm right ) .Sm on .Op Ar coordinates_name .Ar offset .Cm ht .Ar height .Op Cm wid Ar width .Op Cm base Ar base_offset .Op Ar line_description .Pp .Ic bar .Op Ar coordinates_name .Ar expr , expr , .Op Ar coordinates_name .Ar expr , expr , .Op Ar line_description .Bd -filled -offset indent The .Ic bar command facilitates drawing bar graphs. The first form of the command describes the bar somewhat generally and has .Nm place it. The bar may extend up or to the right, is centered on .Ar offset and extends up or right .Ar height units (in the given coordinate system). For example .Bd -literal -offset indent-two bar up 3 ht 2 .Ed .Pp draws a 2 unit high bar sitting on the x axis, centered on x=3. By default bars are 1 unit wide, but this can be changed with the .Ic wid keyword. By default bars sit on the base axis, i.e., bars directed up will extend from y=0. That may be overridden by the .Ic base keyword. (The bar described above has corners (2.5, 0) and (3.5, 2).) .Pp The line description has been extended to include a .Ic fill Ar expr keyword that specifies the shading inside the bar. Bars may be drawn in any line style. They support the .Ic color and .Ic fillcolor keywords described under .Ic circle . .Pp The second form of the command draws a box with the two points as corners. This can be used to draw boxes highlighting certain data as well as bar graphs. Note that filled bars will cover data drawn under them. .Ed .Ss Control Flow .Pp .Ic if Ar expr Ic then Ar block .Op Ic else Ar block .Bd -filled -offset indent The .Ic if statement provides simple conditional execution. If .Ar expr is non-zero, the .Ar block after the .Ic then statement is executed. If not the .Ar block after the .Ic else is executed, if present. See .Sx Macros for the definition of blocks. Early versions of this implementation of .Nm treated the blocks as macros that were defined and expanded in place. This led to unnecessary confusion because explicit separators were sometimes called for. Now, .Nm inserts a separator (;) after the last character in .Ar block , so constructs like .Bd -literal if (x == 3) { y = y + 1 } x = x + 1 .Ed behave as expected. A separator is also appended to the end of a .Ic for block. .Ed .Pp .Ic for Ar name Ic from Ar from_expr Ic to Ar to_expr .Oo .Ic by .Op No +\(or-\(or*\(or/ .Ar by_expr .Oc .Ic do .Ar block .Bd -filled -offset indent This command executes .Ar block iteratively. The variable .Ar name is set to .Ar from_expr and incremented by .Ar by_expr until it exceeds .Ar to_expr . The iteration has the semantics defined in the .Ic ticks command. The definition of .Ar block is discussed in .Sx Macros . See also the note about implicit separators in the description of the .Ic if command. .Pp An .Ic = can be used in place of .Ic from . .Ed .Ss Expressions .Pp .Nm supports most standard arithmetic operators: + - / * ^. The carat (^) is exponentiation. In an .Ic if statement .Nm also supports the C logical operators ==, !=, &&, || and unary !. Also in an .Ic if , == and != are overloaded for the comparison of quoted strings. Parentheses are used for grouping. .Pp Assignment is not allowed in an expression in any context, except for simple cascading of assignments. .Li a = b = 35 works as expected; .Li a = 3.5 * (b = 10) does not execute. .Pp .Nm supports the following functions that take one argument: .Ic log , exp , int , sin , cos , sqrt , rand , floor , ceil . The logarithms are base 10 and the trigonometric functions are in radians. .Ic eexp returns Euler's number to the given power and .Ic ln returns the natural logarithm. The natural log, exponentiation functions and floor and ceil are extensions and are probably not available in other .Nm implementations. .Pp .Ic rand returns a random number uniformly distributed on [0,1). The following two-argument functions are supported: .Ic atan2 , min , max . .Ic atan2 works just like .Xr atan2 3 . The random number generator can be seeded by calling .Ic srand with a single parameter (converted internally to an integer). Because its return value is of no use, you must use .Ic srand as a separate statement, it is not part of a valid expression. .Ic srand is not portable. .Pp The .Ic getpid function takes no arguments and returns the process id. This may be used to seed the random number generator, but do not expect cryptographically random values to result. .Pp Other than string comparison, no expressions can use strings. One string valued function exists: .Ic sprintf ( Ar format , .Oo .Ar expr .Op Ar \&, expr .Oc ). It operates like .Xr sprintf 3 , except returning the value. It can be used anywhere a quoted string is used. If .Nm is run with .Fl S , the environment variable .Ev GRAP_SAFER is defined, or .Nm has been compiled for safer operation, the .Ic sprintf command will return the format string. This mode of operation is only intended to be used only if .Nm is being used as part of a super-user enabled print system. .Pp .Nm version 1.44 and beyond support two functions for date and time manipulation, .Ic strptime and .Ic strptime . .Ic strptime parses a time using the .Xr strptime 3 function. It takes two parameters, both strings, the format and a string to parse using that format and returns a number that can be sorted directly - the number of seconds since the UNIX epoch. .Ic strftime does the reverse. It takes a string and a number and formats the number into a date. In both functions, the format is the first parameter. The formats are defined in the documentation for .Xr strftime 3 . .Ss Macros .Nm has a simple but powerful macro facility. Macros are defined using the .Ic define command : .Pp .Ic define Ar name block .br .Ic undefine Ar name .Bd -filled -offset indent Every occurrence of .Ar name in the program text is replaced by the contents of .Ar block . .Ar block is defined by a series of statements in nested { }'s, or a series of statements surrounded by the same letter. An example of the latter is .Bd -literal -offset indent-two define foo X coord x 1,3 X .Ed Each time .Li foo appears in the text, it will be replaced by .Li coord x 1,3 . Macros are literal, and can contain newlines. If a macro does not span multiple lines, it should end in a semicolon to avoid parsing errors. .Pp Macros can take parameters, too. If a macro call is followed by a parenthesized, comma-separated list the values starting with $1 will be replaced in the macro with the elements of the list. A $ not followed by a digit is left unchanged. This parsing is very rudimentary; no nesting or parentheses or escaping of commas is allowed. Also, there is no way to say argument 1 followed by a digit (${1}0 in sh(1)). .Pp The following will draw a line with slope 1. .Bd -literal -offset indent-two define foo { next at $1, $2 } for i from 1 to 5 { foo(i,i) } .Ed Macros persist across graphs. The file .Pa /usr/local/share/grap/grap.defines contains simple macros for plotting common characters. The .Ic undefine command deletes a macro. .Pp See the directory .Pa /usr/local/share/examples/grap for more examples of macros. Confirm the location of the examples directory using the .Fl v flag. .Ed .Ss Number Lists .Pp A whitespace-separated list of numbers is treated specially. The list is taken to be points to be plotted using the default line style on the default coordinate system. If more than two numbers are given, the extra numbers are taken to be additional y values to plot at the first x value. Number lists in DWB .Nm can be comma-separated, and this .Nm supports that as well. More precisely, numbers in number lists can be separated by either whitespace, commas, or both. .Bd -literal -offset indent 1 2 3 4 5 6 .Ed .sp Will plot points using the default line style at (1,2), (1,3),(4,5) and (4,6). A simple way to plot a set of numbers in a file named .Pa ./data is: .Bd -literal -offset indent \&.G1 copy "./data" \&.G2 .Ed .Ss Pic Macros .Pp .Nm defines pic macros that can be used in embedded pic code to place elements in the graph. The macros are .Ic x_gg , .Ic y_gg , and .Ic xy_gg . These macros define pic distances that correspond to the given argument. They can be used to size boxes or to plot pic constructs on the graph. To place a given construct on the graph, you should add Frame.Origin to it. Other coordinate spaces can be used by replacing .Ic gg with the name of the coordinate space. A coordinate space named .Ic gg cannot be reliably accessed by these macros. .Pp The macros are emitted immediately before the frame is drawn. .Pp DWB .Nm may use these as part of its implementation. This .Nm provides them only for compatibility. Note that these are very simple macros, and may not do what you expect under complex conditions. .Sh ENVIRONMENT VARIABLES .Pp If the environment variable .Ev GRAP_DEFINES is defined, .Nm will look for its defines file there. If that value is a relative path name the path specified in the .Fl M option will be searched for it. .Ev GRAP_DEFINES overrides the compiled in location of the defines file, but may be overridden by the .Fl d or .Fl D flags. .Pp If .Ev GRAP_SAFER is set, .Ic sprintf is disabled to prevent forcing .Nm to core dump or smash the stack. .Sh FILES .Pa /usr/local/share/grap/grap.defines .Sh SEE ALSO .Xr atan2 3 , .Xr groff 1 , .Xr pic 1 , .Xr printf 3 , .Xr sh 1 , .Xr sprintf 3 , .Xr troff 1 .Pp If documentation and examples have been installed, .Nm .Fl -version or .Nm .Fl -help will display the locations. .Sh BUGS .Pp There are several small incompatibilities with K&R .Nm grap . They include the .Ic sh command not expanding variables and macros, and a more strict adherence to parameter order in the internal commands. .Pp Although much improved, the error reporting code can still be confused. Notably, an error in a macro is not detected until the macro is used, and it produces unusual output in the error message. .Pp Iterating many times over a macro with no newlines can run .Nm out of memory. .Sh AUTHOR This implementation was done by .An Ted Faber Ao faber@lunabase.org Ac Ns . .An Bruce Lilly Ao bruce.lilly@gmail.com Ac contributed many bug fixes, including a considerable revamp of the error reporting code. If you can actually find an error in your .Nm code, you can probably thank him. .Nm was designed and specified by .An Brian Kernighan and .An Jon Bentley . grap-1.46/grap_lex.ll0000664000175000017500000006475213667273355011511 00000000000000/* -*-c++-*- */ %{ /* This code is (c) 1998-2001 Ted Faber see COPYRIGHT for the full copyright and limitations of liabilities. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef STDC_HEADERS #include #include #endif #if defined(STDC_HEADERS) | defined(HAVE_STDLIB_H) #include #else extern "C" { void free(void*); }; #endif #include #include #include #include #include "grap.h" #include "grap_data.h" #include "grap_draw.h" #include "y.tab.h" extern int errno; #ifndef STRERROR_DECLARED #if HAVE_STRERROR extern "C" { char *strerror(int errnum); } #else extern char *strerror(int errnum); #endif #endif // CGYWIN needs errno if we have it: #ifdef HAVE_ERRNO_H #include #endif int return_macro = 0; int slashcount = 0; int macro_end = 0; string *macrotext; int in_str = 0; int braces = 0; int stack_init =0; int copystate =0; int continuation =0; unsigned int tokenpos =0; bool print_lex_debug = false; bool lex_expand_macro = true; linelist *sl=0; string *copy_end, *copy_backstop; string linebuf; extern macroDictionary macros; extern doubleDictionary vars; extern graph *the_graph; extern stringSequence path; extern bool compat_mode; extern bool id_letter[]; // Templates for debugging. Print the parameters to cerr. //#define LEX_DEBUG template inline void debug(T p) { if ( print_lex_debug) cerr << p << endl; } template inline void debug(T p1, U p2) { if ( print_lex_debug) cerr << p1 << p2 << endl; } int include_string(string *, for_descriptor *f=0, grap_input i=GMACRO); void lex_begin_macro_text(); void lex_end_expr(); void macro_args(macro*); void expand_macro(macro*); bool is_macro(const string&); void newline(); #ifndef HAVE_STRDUP char *strdup(const char *); #endif const char *vf1names[NVF1] = { "srand" }; const char *f0names[NF0] = { "rand", "getpid" }; const char *f1names[NF1] = { "log", "exp", "int", "sin", "cos", "sqrt", "eexp","ln", "floor", "ceil" }; const char *f2names[NF2] = { "atan2", "min", "max" }; #define ECHO /* */ // Set of currently active keywords set active; // Commonly used keyword sets extern vector grap_keys; extern keywordDictionary keywords; // There are a couple times when the possiblity of a COORD_NAME can be // ruled out. If this is set, this is one of those times. bool no_coord=false; %} %x GRAP %x REJECTED_COORD %x MACROTEXT %x COPYSTATE %x HUNTMACRO %x RESTOFLINE identifier [A-Za-z][A-Za-z0-9_]* keyword above|aligned|arrow|auto|bar|base|below|bot|bottom|by|circle|color|coord|copy|dashed|define|do|dotted|down|draw|else|fill|fillcolor|for|frame|from|graph|grid|ht|if|in|invis|label|left|line|ljust|new|next|off|on|out|pic|plot|print|rad|radius|right|rjust|sh|size|solid|sprintf|then|through|thru|tick|ticks|to|top|unaligned|until|up|wid|x|y|undefine|clipped|unclipped|thickness|strftime %% { ^.*$ { linebuf = yytext; tokenpos = 0; REJECT; } \n { debug(" newline"); newline(); tokenpos += yyleng; cout << yytext; } .G1.* { if ( yyleng > 3 && yytext[3] != '\t' && yytext[3] != ' ' ) if ( !compat_mode ) REJECT; if ( yyleng > 3) { // Some extra characters after the macro invocation (or an // extension of the macro under compat mode). char *c; for (c = yytext; *c != '\t' && *c != ' '&& *c != '\0'; c++ ) ; yylval.String = ( *c != '\0' ) ? new string(yytext+3) : 0; } else yylval.String = 0; tokenpos += yyleng; BEGIN(GRAP); debug("START"); active.clear(); active.insert(grap_keys.begin(), grap_keys.end()); return START; } .+ { tokenpos += yyleng; cout << yytext; } } { ^.*$ { linebuf = yytext; tokenpos = 0; REJECT; } \\\n { newline(); tokenpos = 0;} \n { tokenpos = 0; newline(); // Back to square 1 after a SEP active.clear(); active.insert(grap_keys.begin(), grap_keys.end()); debug("SEP"); BEGIN(GRAP); return SEP; } \#.*$ [ \t]+ tokenpos += yyleng; ([0-9]*\.?[0-9]+)|([0-9]*\.?[0-9]+[eE](\+|\-)?[0-9]+)|([0-9]+\.) { debug("Number: ",yytext); yylval.num = atof(yytext); tokenpos += yyleng; BEGIN(GRAP); return NUMBER; } {identifier}[ \t]*=/[^=] { if ( is_macro(yytext) ) REJECT; // in a for statement, identifier = is a // synonym for identifier FROM, so don't // identify it as a LHS. if ( active.count("do") && active.count("from")) REJECT; tokenpos += yyleng; for ( unsigned i = 0; i < static_cast(yyleng); i++ ) if ( yytext[i] == ' ' || yytext[i] == '\t' || yytext[i] == '=' ) { yytext[i] = '\0'; break; } yylval.String = new string(yytext); debug("LHS: ", yytext); BEGIN(GRAP); return LHS; } ; { tokenpos += yyleng; debug("SEP"); // Back to square 1 after a SEP active.clear(); active.insert(grap_keys.begin(), grap_keys.end()); BEGIN(GRAP); return SEP; } \( tokenpos += yyleng; debug("LPAREN"); return LPAREN; \) tokenpos += yyleng; debug("RPAREN"); return RPAREN; , tokenpos += yyleng; debug("COMMA"); return COMMA; \+ tokenpos += yyleng; debug("PLUS"); return PLUS; \% tokenpos += yyleng; debug("MOD"); return MOD; \- tokenpos += yyleng; debug("MINUS"); return MINUS; \* tokenpos += yyleng; debug("TIMES"); return TIMES; \/ tokenpos += yyleng; debug("DIV"); return DIV; \^ tokenpos += yyleng; debug("CARAT"); return CARAT; \= { tokenpos += yyleng; // if this is in a for statement, the EQUALS // has taken the place of the from, so // remove the from from active. if ( active.count("do") && active.count("from")) active.erase("from"); debug("EQUALS"); BEGIN(GRAP); return EQUALS; } \=\= tokenpos += yyleng; debug("EQ"); return EQ; \!\= tokenpos += yyleng; debug("NEQ"); return NEQ; \< tokenpos += yyleng; debug("LT"); return LT; \> tokenpos += yyleng; debug("GT"); return GT; \<\= tokenpos += yyleng; debug("LTE"); return LTE; \>\= tokenpos += yyleng; debug("GTE"); return GTE; \&\& tokenpos += yyleng; debug("AND"); return AND; \|\| tokenpos += yyleng; debug("OR"); return OR; \! tokenpos += yyleng; debug("NOT"); return NOT; log[ \t]+(x|y|log) { int rc = LOG_LOG; string ls(yytext); if (active.count("log") ) { tokenpos += yyleng; // LOG_whatever doesn't change the active // state. debug(yytext); BEGIN(GRAP); if ( ls.find('x') != string::npos ) rc = LOG_X; else if ( ls.find('y') != string::npos) rc = LOG_Y; return rc; } else { debug(yytext, " not active"); REJECT; } } } {identifier}[ \t][ \t]*{identifier} { // The yyless/YY_BREAK allows us to redo the // match under the new start condition. debug("starting ident white ident"); if ( is_macro(yytext) ) { BEGIN(REJECTED_COORD); yyless(0); YY_BREAK; } // Early rejection if a COORD_NAME is // illegal here. if ( no_coord ) { debug(""); BEGIN(REJECTED_COORD); yyless(0); YY_BREAK; } // Here we go - parse out the two // identifiers. If the first is an active // keyword, REJECT. If the second // identifier is not an active keyword, // then this is a coordinate name, so put // the whitespace and the second identifier // back into the input and return the // coordinate name. If no REJECT. string first(yytext); // first id string second; string::size_type f, l; coordinateDictionary::iterator ci; coord *c; for (f = 0;isalnum(first[f]) ||first[f] == '_'; f++) ; // Now f is on the first whitespace character; for (l = f; first[l] == ' '|| first[l] =='\t'; l++) ; // l is now the first character of the // second identifier. second = first.substr(l); first.erase(f); debug("Coord search"); debug(first, second); debug(active.count(first), active.count(second)); if (active.count(first) || active.count(second)) { debug(""); BEGIN(REJECTED_COORD); yyless(0); YY_BREAK; } ci = the_graph->coords.find(first); if ( ci != the_graph->coords.end()) { c = (*ci).second; yylval.coordptr = c; } else { yylval.coordptr = new coord(first); the_graph->coords[first] = yylval.coordptr; } yyless(first.length()); tokenpos += first.length(); debug("COORD_NAME"); return COORD_NAME; } { {identifier}/[ \t][ \t]*-[ \t]*[0123456789\.(] { // This is close to the case below, which is more // clearly a coordinate space modifying a number. // This case includes things like // ident -3 // It's often literally impossible to decide if that // means -3 in the ident coordinate space or the // variable ident minus 3. This code rules that if // ident is a keyword, macro, or initialized // variable, ident will be treated as one of those, // and this rule will be rejected. Otherwise it is // a coordinate space and, if neceaasry, a new space // will be allocated for it. // // I don't expect that this is the last piece of // pain to come from here. coordinateDictionary::iterator ci; coord *c; debug("testing (minus sign): ",yytext); debug("count ", active.count(yytext)); if ( is_macro(yytext) ) REJECT; if ( active.count(yytext) ) REJECT; if ( vars.count(yytext) ) REJECT; ci = the_graph->coords.find(yytext); if ( ci != the_graph->coords.end()) { c = (*ci).second; yylval.coordptr = c; } else { yylval.coordptr = new coord(yytext); the_graph->coords[yytext] = yylval.coordptr; } tokenpos += yyleng; debug("COORD_NAME: ",yytext); return COORD_NAME; } {identifier}/[ \t][ \t]*[0123456789\.(] { coordinateDictionary::iterator ci; coord *c; debug("testing: ",yytext); debug("count ", active.count(yytext)); if ( is_macro(yytext) ) REJECT; if ( active.count(yytext) ) REJECT; ci = the_graph->coords.find(yytext); if ( ci != the_graph->coords.end()) { c = (*ci).second; yylval.coordptr = c; } else { yylval.coordptr = new coord(yytext); the_graph->coords[yytext] = yylval.coordptr; } tokenpos += yyleng; debug("COORD_NAME: ",yytext); return COORD_NAME; } {keyword} { macroDictionary::iterator mi; if ( lex_expand_macro && ( mi = macros.find(yytext)) != macros.end() ) { expand_macro((*mi).second); tokenpos += yyleng; BEGIN(GRAP); } else { if (active.count(yytext) ) { keywordDictionary::iterator ki; unsigned int i; if ( (ki = keywords.find(yytext)) == keywords.end()) { cerr << "keyword not in map!?" << endl; return(0); } // The alias runs faster const keyword& k = (*ki).second; if ( k.clear ) active.clear(); for ( i = 0; i < k.add.size(); i++ ) active.insert(k.add[i]); for ( i = 0; i < k.remove.size(); i++) active.erase(k.remove[i]); debug("keyword: ", yytext); tokenpos += yyleng; BEGIN(GRAP); return(k.token); } else { debug(yytext, " not active"); REJECT; } } } at { if (active.count(yytext) ) { tokenpos += yyleng; // AT can be active for 2 reasons. It's // been found in an expression that // recognizes AT, or it's following an // implicit PLOT statement - "string" at // x, y. In the first case, no more // keywords need to be detected. In the // second just delete the AT from the // list. If COPY, which doesn't take an // AT, is in active, this is an implicit // PLOT because active is in the initial // state. if ( active.count("plot")) active.clear(); else active.erase("at"); debug("AT"); BEGIN(GRAP); return AT; } else { debug("AT not active"); REJECT; } } strptime { debug("STRPTIME"); BEGIN(GRAP); return STRPTIME; } srand { debug("VFUNC1"); for ( int i = 0 ; i < NVF1; i++ ) if ( !strcmp(yytext,vf1names[i]) ) yylval.val = i; tokenpos += yyleng; BEGIN(GRAP); return VFUNC1; } rand|getpid { debug("FUNC0"); for ( int i = 0 ; i < NF0; i++ ) if ( !strcmp(yytext,f0names[i]) ) yylval.val = i; tokenpos += yyleng; BEGIN(GRAP); return FUNC0; } log|exp|int|sin|cos|sqrt|eexp|ln|floor|ceil { debug("FUNC1"); for ( int i = 0 ; i < NF1; i++ ) if ( !strcmp(yytext,f1names[i]) ) yylval.val = i; tokenpos += yyleng; BEGIN(GRAP); return FUNC1; } atan2|min|max { debug("FUNC2"); for ( int i = 0 ; i < NF2; i++ ) if ( !strcmp(yytext,f2names[i]) ) yylval.val = i; tokenpos += yyleng; BEGIN(GRAP); return FUNC2; } [.\'][ \t]*[^\t 0-9].*$ { tokenpos += yyleng; if ( !strncmp(".G1", yytext, 3) ) { if ( lexstack.empty() || lexstack.front()->report_start == 1 ) { debug("Start: ", yytext); BEGIN(GRAP); return START; } else YY_BREAK; } if ( !strncmp(".G2", yytext, 3) ) { if ( lexstack.empty() || lexstack.front()->report_start == 1) { debug("End: ",yytext); BEGIN(INITIAL); // Eat the newline yyinput(); newline(); tokenpos = 0; return END; } else YY_BREAK; } yylval.String = new string(yytext); debug("Troff: ", yytext); BEGIN(GRAP); return TROFF; } \"([^\"\n]|\\\")*\" { debug("String: ", yytext); yylval.String = new string(yytext); tokenpos += yyleng; BEGIN(GRAP); return STRING; } {identifier} { macroDictionary::iterator mi; string *id; debug("ident: ", yytext); id = new string(yytext); if ( lex_expand_macro && ( mi = macros.find(*id)) != macros.end() ) { delete id; expand_macro((*mi).second); tokenpos += yyleng; } else { tokenpos += yyleng; yylval.String = id; BEGIN(GRAP); return IDENT; } } . tokenpos += yyleng; debug("unknown: ", yytext); return 0; } { ^.*$ { linebuf = yytext; REJECT; } [ \t]+ { slashcount = 0; tokenpos += yyleng; if ( macro_end != 0) *macrotext += yytext; } \\ { *macrotext += *yytext; tokenpos += yyleng; slashcount ++; } \" { *macrotext += *yytext; tokenpos += yyleng; if ( in_str ) { if ( slashcount % 2 == 0) in_str=0; } else { if ( slashcount % 2 == 0) in_str=1; } slashcount = 0; } \{ { if ( macro_end == 0 ) { macro_end = '}'; braces = 1; } else { if ( !in_str ) braces++; *macrotext += *yytext; slashcount =0; } tokenpos += yyleng; } \} { tokenpos += yyleng; if ( macro_end == 0 ) return 0; else { if ( !in_str ) braces--; if ( macro_end == '}' && !braces ) { BEGIN(GRAP); if ( !return_macro) { yylval.String = macrotext; debug("TEXT"); return TEXT; } else { macro *m = new macro(macrotext); yylval.macro_val = m; debug("MACRO: ",macrotext->c_str()); macrotext = 0; return MACRO; } } else { *macrotext += *yytext; slashcount =0; } } } \n { *macrotext += *yytext; slashcount =0; tokenpos = 0; newline(); // don't return SEP here } . { tokenpos += yyleng; if ( macro_end == 0 ) macro_end = *yytext; else { if ( *yytext == macro_end ) { BEGIN(GRAP); if ( !return_macro ) { yylval.String = macrotext; return TEXT; } else { macro *m = new macro(macrotext); yylval.macro_val = m; macrotext = 0; return MACRO; } } else { *macrotext += *yytext; slashcount =0; } } } } { ^.*$ { linebuf = yytext; REJECT; } \n { tokenpos = 0; newline(); } .+ { string *s; if ( *copy_end != yytext && *copy_backstop != yytext ) { s = new string(yytext); sl->push_back(s); } else { // If we're stopped by an END symbol, we have to put it back if ( !strncmp(".G2",yytext,3) ) { debug("End: ", yytext); yyless(0); unput('\n'); lexstack.front()->line--; tokenpos = 0; } else tokenpos += yyleng; BEGIN(GRAP); yylval.line_list = sl; sl = 0; copystate = 0; debug("COPYTEXT ", yylval.line_list->size()); return COPYTEXT; } } } { [ \t]+ tokenpos += yyleng; [A-Za-z0-9_]* { macro *m; macroDictionary::iterator mi; string *id = new string(yytext); if ( ( mi = macros.find(*id)) != macros.end()) { m = (*mi).second; delete id; tokenpos += yyleng; BEGIN(GRAP); yylval.macro_val = m; return MACRO; } else { char *c = strdup(yytext); delete id; lex_begin_macro_text(); return_macro =1; yyless(0); free(c); tokenpos += yyleng; } } . { debug(" ", yytext); unput(*yytext); lex_begin_macro_text(); return_macro = 1; } } { .*$ { BEGIN(GRAP); tokenpos += yyleng; debug("REST: ",yytext); if ( strcmp("\n",yytext) ) yylval.String = new string(yytext); else yylval.String = 0; no_coord = false; return REST; } } <> { debug("EOF"); if ( copystate && !lexstack.empty()) { copystate = 0; tokenpos = 0; BEGIN(GRAP); yylval.line_list = sl; sl = 0; debug("COPYTEXT(EOF)"); return COPYTEXT; } else yyterminate(); } %% // Most of these that begin with lex_ are an interface from the parser // (grap.y) // XXX: Store the line number info in the output text as a .lf. This isn't // quite right yet. It's nulled out because it was worse than "not right" it // was emitting text outside the PS/PE. void linenum() { } // Put the given file into the input stream. If rs is true, report // start tokens from that buffer. If usepath is true the grap path is // used to search for the file. bool include_file(string *s, bool rs /* =false */ , bool usepath /* =true*/) { FILE *f=0; grap_buffer_state *g = new grap_buffer_state(0, 0, 0, 1, rs, GFILE); grap_buffer_state *gg = lexstack.empty() ? 0 : lexstack.front(); if ( s ) { debug("include_file: ",s->c_str()); if ( gg ) { gg->tokenpos = tokenpos; tokenpos = 0; } if ( *s != "-" ) { if ( (*s)[0] != '/' && usepath ) { // use path to look up relative path for ( stringSequence::iterator i = path.begin(); i != path.end(); i++) { string str = *(*i); str += "/"; str += *s; if ( ( f = fopen(str.c_str(),"r"))) break; } } else f = fopen(s->c_str(),"r"); if ( !f ) { cerr << "Can't open " << *s << " " << strerror(errno) << endl; return 0; } g->yy = yy_create_buffer(f,YY_BUF_SIZE); g->name = new string(*s); } else { g->yy = yy_create_buffer(stdin,YY_BUF_SIZE); g->name = new string("-"); } lexstack.push_front(g); yy_switch_to_buffer(g->yy); return 1; } else return 0; } // Include the given string into the input stream. Additional // parameters are a for descriptor associated with the buffer (if its // part of a for loop) and an input type (that's usualy GMACRO) int include_string(string *s, for_descriptor *f /* =0 */, grap_input it /*=GMACRO */) { char *cbuf; int len; grap_buffer_state *g; grap_buffer_state *gg = lexstack.empty() ? 0 : lexstack.front(); debug("include string ",s->c_str()); if ( gg ) { gg->tokenpos = tokenpos; tokenpos = 0; } g = new grap_buffer_state(0, f, 0, 1, 1, it); cbuf = new char[len = s->length()+1]; strncpy(cbuf,s->c_str(),len-1); cbuf[len-1] = '\0'; lexstack.push_front(g); g->yy = yy_scan_string(cbuf); delete cbuf; return 1; } // Disable macro expansion of identifers (used in definingin new macros) void lex_no_macro_expansion() { lex_expand_macro = false; } // Disable macro expansion of identifers (used in definingin new macros) void lex_macro_expansion_ok() { lex_expand_macro = true; } // Begin parsing macro text. Set the lexer into the appropriate start // condition and initialize the appropriate internals. void lex_begin_macro_text() { BEGIN(MACROTEXT); debug(" lex_begin_macro_text()"); lex_expand_macro = true; slashcount = 0; macro_end = 0; return_macro=0; macrotext = new string; in_str = 0; braces = 0; } // Parse the arguments to a macro invocation and call macro::add_arg // on them. void macro_args(macro *m) { string *arg; int c; int parens = 0; int slashcount = 0; int in_str = 0; arg = new string; for ( c = yyinput(); c != EOF && ( c != ')' || parens ); c = yyinput()) { if ( c == ',' && !in_str && !parens) { // End of arg if ( m->add_arg(arg)) arg = new string; continue; } if ( c == '(' ) parens++; if ( c == ')' ) parens --; if ( c == '"' && (slashcount % 2 ) == 0 ) { if ( in_str ) in_str = 0; else in_str = 1; } if ( c == '\\' ) slashcount++; else slashcount = 0; *arg += (char) c; tokenpos++; } if ( c == ')' && arg->length() ) { if ( !m->add_arg(arg)) delete arg; } else if (arg) delete arg; tokenpos++; } // prepare to copy text from the input for a copy statement. Set the // start condition and the internal state. void lex_begin_copy(string *s /* =0 */) { debug("COPYSTATE (lex_begin_copy)"); BEGIN(COPYSTATE); copystate = 1; if ( !copy_backstop ) copy_backstop = new string(".G2"); if ( copy_end) delete copy_end; if ( s ) copy_end = s; else copy_end = new string(".G2"); if ( sl ) delete sl; sl = new linelist; } // Change start condition void lex_hunt_macro() { BEGIN(HUNTMACRO); } // Change start condition void lex_begin_rest_of_line() { BEGIN(RESTOFLINE); } // Tell if coordinate names are allowed here void lex_no_coord() { no_coord = true; } // Tell if coordinate names are allowed here void lex_coord_ok() { no_coord = false; } // This buffer is empty, go to the next one on the stack. If there is // an associated for descriptor, do the for processing and replace the // buffer on the stack if the loop is continuing. int yywrap() { grap_buffer_state *g; debug("(yywrap)"); if ( lexstack.empty() ) yyterminate(); else { g = lexstack.front(); lexstack.pop_front(); } if ( g->f ) { for_descriptor *f = g->f; // we're processing a for statement switch (f->by_op ) { case PLUS: default: *f->loop_var += f->by; break; case MINUS: *f->loop_var -= f->by; break; case TIMES: *f->loop_var *= f->by; break; case DIV: *f->loop_var /= f->by; break; case MOD: *f->loop_var = static_cast(*f->loop_var) % static_cast(f->by); break; } if ( (*f->loop_var - f->limit) * f->dir < epsilon ) { // still iterating redo this stack frame yy_delete_buffer(g->yy); // *do not delete g->f because include string will attach // it to the new grap_buffer_state that it allocates. g->f = 0; delete g; include_string(f->anything, f); return 0; } } // If we get here, we need to switch to the previous buffer yy_delete_buffer(g->yy); if ( lexstack.empty() ) { // groff line marker delete g; return 1; } else { delete g; g = lexstack.front(); tokenpos = g->tokenpos; yy_switch_to_buffer(g->yy); } return copystate ? 1 : 0; } // Newline processing. Inrement the current line number void newline() { if ( !lexstack.empty() ) { grap_buffer_state *g = lexstack.front(); g->line++; } } // Error message printing. string pre_context(void) { if (!tokenpos) return ""; else return linebuf.substr(0,tokenpos-yyleng); } char *token_context(void) { return (yytext); } string post_context(void) { return (tokenpos < linebuf.size()) ? linebuf.substr(tokenpos) : "" ; } void expand_macro(macro *m) { char ch = yyinput(); string *exp; if ( ch == '(') { macro_args(m); tokenpos++; } else { // flex 2.3.51+ undefs yytext_ptr which breaks the unput macro outside the // first %% section. This is a kludge to expand the macro by hand if this bad // thing has happened. I think I'll try to convince them this is a bad idea. #ifndef yytext_ptr yyunput(ch, yytext); #else unput(ch); #endif } exp = m->invoke(); include_string(exp); delete exp; } bool is_macro(const string& s) { int i = (int) s.length()-1; string mname; while ( i >=0 && !id_letter[static_cast(s[i])]) i--; if ( i < 0 ) return false; mname = s.substr(0, i+1); return (macros.find(mname) != macros.end()); } grap-1.46/install-sh0000775000175000017500000001273613163474043011342 00000000000000#!/bin/sh # # install - install a program, script, or datafile # This comes from X11R5 (mit/util/scripts/install.sh). # # Copyright 1991 by the Massachusetts Institute of Technology # # Permission to use, copy, modify, distribute, and sell this software and its # documentation for any purpose is hereby granted without fee, provided that # the above copyright notice appear in all copies and that both that # copyright notice and this permission notice appear in supporting # documentation, and that the name of M.I.T. not be used in advertising or # publicity pertaining to distribution of the software without specific, # written prior permission. M.I.T. makes no representations about the # suitability of this software for any purpose. It is provided "as is" # without express or implied warranty. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. It can only install one file at a time, a restriction # shared with many OS's install programs. # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" transformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 else true fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d $dst ]; then instcmd=: chmodcmd="" else instcmd=mkdir fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f $src -o -d $src ] then true else echo "install: $src does not exist" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 else true fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` else true fi fi ## this sed command emulates the dirname command dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-${defaultIFS}}" oIFS="${IFS}" # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` IFS="${oIFS}" pathcomp='' while [ $# -ne 0 ] ; do pathcomp="${pathcomp}${1}" shift if [ ! -d "${pathcomp}" ] ; then $mkdirprog "${pathcomp}" else true fi pathcomp="${pathcomp}/" done fi if [ x"$dir_arg" != x ] then $doit $instcmd $dst && if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename $dst` else dstfile=`basename $dst $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename $dst` else true fi # Make a temp file name in the proper directory. dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp && trap "rm -f ${dsttmp}" 0 && # and set any options; do chmod last to preserve setuid bits # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && # Now rename the file to the real destination. $doit $rmcmd -f $dstdir/$dstfile && $doit $mvcmd $dsttmp $dstdir/$dstfile fi && exit 0 grap-1.46/Makefile.in0000664000175000017500000010257113670320172011374 00000000000000# Makefile.in generated by automake 1.15.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2017 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : bin_PROGRAMS = grap$(EXEEXT) subdir = . ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/grap.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ $(am__configure_deps) $(dist_defines_DATA) $(dist_doc_DATA) \ $(dist_example_DATA) $(am__DIST_COMMON) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(install_sh) -d CONFIG_HEADER = config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" \ "$(DESTDIR)$(definesdir)" "$(DESTDIR)$(docdir)" \ "$(DESTDIR)$(exampledir)" PROGRAMS = $(bin_PROGRAMS) am_grap_OBJECTS = grap_draw.$(OBJEXT) grap_pic.$(OBJEXT) \ grap_parse.$(OBJEXT) grap_tokenizer.$(OBJEXT) nodist_grap_OBJECTS = grap.$(OBJEXT) grap_lex.$(OBJEXT) grap_OBJECTS = $(am_grap_OBJECTS) $(nodist_grap_OBJECTS) am__DEPENDENCIES_1 = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) AM_V_CXX = $(am__v_CXX_@AM_V@) am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) am__v_CXX_0 = @echo " CXX " $@; am__v_CXX_1 = CXXLD = $(CXX) CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ -o $@ AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) am__v_CXXLD_0 = @echo " CXXLD " $@; am__v_CXXLD_1 = AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = LEXCOMPILE = $(LEX) $(AM_LFLAGS) $(LFLAGS) AM_V_LEX = $(am__v_LEX_@AM_V@) am__v_LEX_ = $(am__v_LEX_@AM_DEFAULT_V@) am__v_LEX_0 = @echo " LEX " $@; am__v_LEX_1 = YLWRAP = $(top_srcdir)/ylwrap am__yacc_c2h = sed -e s/cc$$/hh/ -e s/cpp$$/hpp/ -e s/cxx$$/hxx/ \ -e s/c++$$/h++/ -e s/c$$/h/ YACCCOMPILE = $(YACC) $(AM_YFLAGS) $(YFLAGS) AM_V_YACC = $(am__v_YACC_@AM_V@) am__v_YACC_ = $(am__v_YACC_@AM_DEFAULT_V@) am__v_YACC_0 = @echo " YACC " $@; am__v_YACC_1 = COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(grap_SOURCES) $(EXTRA_grap_SOURCES) $(nodist_grap_SOURCES) DIST_SOURCES = $(grap_SOURCES) $(EXTRA_grap_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } man1dir = $(mandir)/man1 NROFF = nroff MANS = $(dist_man1_MANS) DATA = $(dist_defines_DATA) $(dist_doc_DATA) $(dist_example_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \ $(LISP)config.h.in # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags CSCOPE = cscope AM_RECURSIVE_TARGETS = cscope am__DIST_COMMON = $(dist_man1_MANS) $(srcdir)/Makefile.in \ $(srcdir)/config.h.in AUTHORS COPYING ChangeLog INSTALL NEWS \ README depcomp install-sh missing ylwrap DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ if test -d "$(distdir)"; then \ find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -rf "$(distdir)" \ || { sleep 5 && rm -rf "$(distdir)"; }; \ else :; fi am__post_remove_distdir = $(am__remove_distdir) DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best DIST_TARGETS = dist-gzip distuninstallcheck_listfiles = find . -type f -print am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' distcleancheck_listfiles = find . -type f -print ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CPPFLAGS = @CPPFLAGS@ CX0FLAGS = @CX0FLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFINES_DIR = @DEFINES_DIR@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DOC_DIR = @DOC_DIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXAMPLE_DIR = @EXAMPLE_DIR@ EXEEXT = @EXEEXT@ # Support for compiling our own strdup and strerror if needed. We don't use # LIBOBJS directly because automake thinks the sources for LIBOBJS are C files. GRAPLIBOBJS = @GRAPLIBOBJS@ GREP = @GREP@ GXXFLAGS = @GXXFLAGS@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_DEPS = @INSTALL_DEPS@ INSTALL_DOCS = @INSTALL_DOCS@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NO_UNDEF = @NO_UNDEF@ OBJEXT = @OBJEXT@ OS_VERSION = @OS_VERSION@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ SUPPRESS_OPT = @SUPPRESS_OPT@ VERSION = @VERSION@ YACC = @YACC@ YFLAGS = @YFLAGS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CXX = @ac_ct_CXX@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ # Other docs docdir = @DOC_DIR@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ grap_SOURCES = grap_draw.cc grap_pic.cc grap_parse.cc grap_tokenizer.cc nodist_grap_SOURCES = grap.yy grap_lex.ll y.tab.h EXTRA_DIST = grap.h grap_data.h grap_draw.h grap_pic.h grap_string.h snprintf.h\ grap.yy grap_lex.ll grap.spec BUILT_SOURCES = y.tab.h grap_LDADD = $(GRAPLIBOBJS) grap_DEPENDENCIES = $(GRAPLIBOBJS) EXTRA_grap_SOURCES = strdup.cc strerror.cc # Delete generated files on clean CLEANFILES = grap.cc grap_lex.cc grap.man y.tab.h # Man page dist_man1_MANS = grap.doc # Where to put grap.defines definesdir = @DEFINES_DIR@ dist_defines_DATA = grap*.defines # Examples exampledir = @EXAMPLE_DIR@ dist_example_DATA = examples/*.d examples/*.result examples/Makefile \ examples/example.ms dist_doc_DATA = README CHANGES COPYRIGHT grap.man # Configure supplied C++ flags AM_CXXFLAGS = @GXXFLAGS@ @CX0FLAGS@ all: $(BUILT_SOURCES) config.h $(MAKE) $(AM_MAKEFLAGS) all-am .SUFFIXES: .SUFFIXES: .cc .ll .o .obj .yy am--refresh: Makefile @: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ echo ' cd $(srcdir) && $(AUTOMAKE) --gnu'; \ $(am__cd) $(srcdir) && $(AUTOMAKE) --gnu \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ echo ' $(SHELL) ./config.status'; \ $(SHELL) ./config.status;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck $(top_srcdir)/configure: $(am__configure_deps) $(am__cd) $(srcdir) && $(AUTOCONF) $(ACLOCAL_M4): $(am__aclocal_m4_deps) $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) $(am__aclocal_m4_deps): config.h: stamp-h1 @test -f $@ || rm -f stamp-h1 @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1 stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status @rm -f stamp-h1 cd $(top_builddir) && $(SHELL) ./config.status config.h $(srcdir)/config.h.in: $(am__configure_deps) ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) rm -f stamp-h1 touch $@ distclean-hdr: -rm -f config.h stamp-h1 install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) grap$(EXEEXT): $(grap_OBJECTS) $(grap_DEPENDENCIES) $(EXTRA_grap_DEPENDENCIES) @rm -f grap$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(grap_OBJECTS) $(grap_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/grap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/grap_draw.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/grap_lex.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/grap_parse.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/grap_pic.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/grap_tokenizer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strdup.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strerror.Po@am__quote@ .cc.o: @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< .cc.obj: @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .ll.cc: $(AM_V_LEX)$(am__skiplex) $(SHELL) $(YLWRAP) $< $(LEX_OUTPUT_ROOT).c $@ -- $(LEXCOMPILE) grap_lex.cc: grap_lex.ll $(AM_V_LEX) \ $(SHELL) $(YLWRAP) `test -f 'grap_lex.ll' || echo '$(srcdir)/'`grap_lex.ll $(LEX_OUTPUT_ROOT).c grap_lex.cc -- $(LEX) $(AM_LFLAGS) $(LFLAGS) .yy.cc: $(AM_V_YACC)$(am__skipyacc) $(SHELL) $(YLWRAP) $< y.tab.c $@ y.tab.h `echo $@ | $(am__yacc_c2h)` y.output $*.output -- $(YACCCOMPILE) grap.cc: grap.yy $(AM_V_YACC) \ $(SHELL) $(YLWRAP) `test -f 'grap.yy' || echo '$(srcdir)/'`grap.yy y.tab.c grap.cc y.tab.h `echo grap.cc | $(am__yacc_c2h)` y.output grap.output -- $(YACC) $(AM_YFLAGS) $(YFLAGS) install-man1: $(dist_man1_MANS) @$(NORMAL_INSTALL) @list1='$(dist_man1_MANS)'; \ list2=''; \ test -n "$(man1dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.1[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \ done; } uninstall-man1: @$(NORMAL_UNINSTALL) @list='$(dist_man1_MANS)'; test -n "$(man1dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir) install-dist_definesDATA: $(dist_defines_DATA) @$(NORMAL_INSTALL) @list='$(dist_defines_DATA)'; test -n "$(definesdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(definesdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(definesdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(definesdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(definesdir)" || exit $$?; \ done uninstall-dist_definesDATA: @$(NORMAL_UNINSTALL) @list='$(dist_defines_DATA)'; test -n "$(definesdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(definesdir)'; $(am__uninstall_files_from_dir) install-dist_docDATA: $(dist_doc_DATA) @$(NORMAL_INSTALL) @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(docdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(docdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(docdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(docdir)" || exit $$?; \ done uninstall-dist_docDATA: @$(NORMAL_UNINSTALL) @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(docdir)'; $(am__uninstall_files_from_dir) install-dist_exampleDATA: $(dist_example_DATA) @$(NORMAL_INSTALL) @list='$(dist_example_DATA)'; test -n "$(exampledir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(exampledir)'"; \ $(MKDIR_P) "$(DESTDIR)$(exampledir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(exampledir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(exampledir)" || exit $$?; \ done uninstall-dist_exampleDATA: @$(NORMAL_UNINSTALL) @list='$(dist_example_DATA)'; test -n "$(exampledir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(exampledir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscope: cscope.files test ! -s cscope.files \ || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) clean-cscope: -rm -f cscope.files cscope.files: clean-cscope cscopelist cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags -rm -f cscope.out cscope.in.out cscope.po.out cscope.files distdir: $(DISTFILES) $(am__remove_distdir) test -d "$(distdir)" || mkdir "$(distdir)" @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done -test -n "$(am__skip_mode_fix)" \ || find "$(distdir)" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r "$(distdir)" dist-gzip: distdir tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz $(am__post_remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 $(am__post_remove_distdir) dist-lzip: distdir tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz $(am__post_remove_distdir) dist-xz: distdir tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz $(am__post_remove_distdir) dist-tarZ: distdir @echo WARNING: "Support for distribution archives compressed with" \ "legacy program 'compress' is deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__post_remove_distdir) dist-shar: distdir @echo WARNING: "Support for shar distribution archives is" \ "deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz $(am__post_remove_distdir) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__post_remove_distdir) dist dist-all: $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' $(am__post_remove_distdir) # This target untars the dist file and tries a VPATH configuration. Then # it guarantees that the distribution is self-contained by making another # tarfile. distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.lz*) \ lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ *.tar.xz*) \ xz -dc $(distdir).tar.xz | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ esac chmod -R a-w $(distdir) chmod u+w $(distdir) mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst chmod a-w $(distdir) test -d $(distdir)/_build || exit 0; \ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && am__cwd=`pwd` \ && $(am__cd) $(distdir)/_build/sub \ && ../../configure \ $(AM_DISTCHECK_CONFIGURE_FLAGS) \ $(DISTCHECK_CONFIGURE_FLAGS) \ --srcdir=../.. --prefix="$$dc_install_base" \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) dvi \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ } || { rm -rf "$$dc_destdir"; exit 1; }) \ && rm -rf "$$dc_destdir" \ && $(MAKE) $(AM_MAKEFLAGS) dist \ && rm -rf $(DIST_ARCHIVES) \ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ && cd "$$am__cwd" \ || exit 1 $(am__post_remove_distdir) @(echo "$(distdir) archives ready for distribution: "; \ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' distuninstallcheck: @test -n '$(distuninstallcheck_dir)' || { \ echo 'ERROR: trying to run $@ with an empty' \ '$$(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ $(am__cd) '$(distuninstallcheck_dir)' || { \ echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ fi ; \ $(distuninstallcheck_listfiles) ; \ exit 1; } >&2 distcleancheck: distclean @if test '$(srcdir)' = . ; then \ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ exit 1 ; \ fi @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left in build directory after distclean:" ; \ $(distcleancheck_listfiles) ; \ exit 1; } >&2 check-am: all-am check: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-am all-am: Makefile $(PROGRAMS) $(MANS) $(DATA) config.h installdirs: for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(definesdir)" "$(DESTDIR)$(docdir)" "$(DESTDIR)$(exampledir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -rm -f grap.cc -rm -f grap_lex.cc -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) clean: clean-am clean-am: clean-binPROGRAMS clean-generic mostlyclean-am distclean: distclean-am -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-hdr distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dist_definesDATA install-dist_docDATA \ install-dist_exampleDATA install-man install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-man1 install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-dist_definesDATA \ uninstall-dist_docDATA uninstall-dist_exampleDATA \ uninstall-man uninstall-man: uninstall-man1 .MAKE: all check install install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--refresh check check-am clean \ clean-binPROGRAMS clean-cscope clean-generic cscope \ cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \ dist-gzip dist-lzip dist-shar dist-tarZ dist-xz dist-zip \ distcheck distclean distclean-compile distclean-generic \ distclean-hdr distclean-tags distcleancheck distdir \ distuninstallcheck dvi dvi-am html html-am info info-am \ install install-am install-binPROGRAMS install-data \ install-data-am install-dist_definesDATA install-dist_docDATA \ install-dist_exampleDATA install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-man1 \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-binPROGRAMS \ uninstall-dist_definesDATA uninstall-dist_docDATA \ uninstall-dist_exampleDATA uninstall-man uninstall-man1 .PRECIOUS: Makefile # Rules for y.tab.h and grap.man y.tab.h: grap.yy ${YACC} -d grap.yy && rm -f y.tab.c grap.man: grap.doc groff -mdoc -Tascii grap.doc > grap.man # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: grap-1.46/grap_draw.cc0000664000175000017500000001160013163474043011600 00000000000000#ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include "grap.h" #include "grap_data.h" #include "grap_draw.h" // This file is (c) 1998-2001 Ted Faber (faber@lunabase.org) see COPYRIGHT // for the full copyright and limitations of liabilities. void coord::newx(double x) { // Specific code to add the x value. If the axis is being autoscaled, // see if this point expands it. Otherwise, sanity check it. if ( xautoscale == 2) { xmax = (x > xmax ) ? x : xmax; xmin = (x < xmin ) ? x : xmin; } if ( xautoscale == 1 ) { // first point xmax = xmin = x; xautoscale = 2; } if ( (logscale & x_axis) ) { if ( xmin < min_double ) { cerr << "Logscale with non-positive value (within precision)" << endl; xmin = min_double; } if ( xmax < min_double ) { cerr << "Logscale with non-positive value (within precision)" << endl; xmax = min_double; } } } void coord::newy(double y) { // Specific code to add the x value. If the axis is being autoscaled, // see if this point expands it. Otherwise, sanity check it. if ( yautoscale == 2) { ymax = (y > ymax ) ? y : ymax; ymin = (y < ymin ) ? y : ymin; } if ( yautoscale == 1 ) { // first point ymax = ymin = y; yautoscale = 2; } if ( (logscale & y_axis) ) { if ( ymin < min_double ) { cerr << "Logscale with non-positive value (within precision)" << endl; ymin = min_double; } if ( ymax < min_double ) { cerr << "Logscale with non-positive value (within precision)" << endl; ymax = min_double; } } } void coord::addmargin(double mf) { // Add a margin to the coordinate system to center the plot better. // The margin factor(mf) is given as a multiplier to the current size // (0.07 is 7% on either size). If the axis is logarithmic, we have // to work in that space. double range; // The size of the axis we're working on // Log sale must be positive if ( (logscale & x_axis) ) { if ( xmin < min_double ) xmin = min_double; if ( xmax < min_double ) xmax = min_double; } if ( (logscale & y_axis) ) { if ( ymin < min_double ) ymin = min_double; if ( ymax < min_double ) ymax = min_double; } if ( xautoscale ) { if ( logscale & x_axis) { double b, t; // bottom and top of the logscale range // Solving the log mapping equation for 1+mf and -mf // Isn't math cool? b = pow(xmax,-mf) / pow(xmin,(-mf-1)); t = pow(xmax,1+mf) / pow(xmin,mf); xmin = b; xmax = t; } else { range = xmax - xmin; xmin = xmin - mf * range; xmax = xmax + mf * range; } } if ( yautoscale ) { if ( logscale & y_axis) { double b, t; // bottom and top of the logscale range // Solving the log mapping equation for 1+mf and -mf // Isn't math cool? b = pow(ymax,-mf) / pow(ymin,(-mf-1)); t = pow(ymax,1+mf) / pow(ymin,mf); ymin = b; ymax = t; } else { range = ymax - ymin; ymin = ymin - mf * range; ymax = ymax + mf * range; } } // If they're too close together, just punt. (Actually this is less a punt // than it looks like. Adding 1 works if no points have been added that // would define a grid - xmin == xmax == 0 and if you do almost nothing you // get a (0,1) x (0,1) frame). if ( xmax == xmin) xmax += 1.0; if ( ymax == ymin) ymax += 1.0; } double coord::map(double v, axis ax ) { // map the coordinate from data space to [0,1]. 1 is the top of the axis, // 0 the bottom. Do it right for logscale or cartesian coordinates switch ( ax ) { case x_axis: if (logscale & x_axis ) { if ( v > min_double ) return ((log(v) -log(xmin)) / (log(xmax)-log(xmin))); else throw range_error("Negative or zero logscale coordinate"); } else return ( (v - xmin) / (xmax - xmin ) ); break; case y_axis: if (logscale & y_axis ) { if ( v > min_double ) return ((log(v) -log(ymin)) / (log(ymax)-log(ymin))); else throw range_error("Negative or zero logscale coordinate"); } else return ( (v - ymin) / (ymax - ymin ) ); break; default: return -1; break; } } // Linesegment constructor. Too long for a header, but // straightforward. Connect this segment to the previous point in the // line. linesegment::linesegment(double xx, double yy, coord* cc, line *ll, DisplayString *s /* =0 */, linedesc *l /* =0 */, bool a /* =false */) : to(xx,yy,cc), from(0) { point *p; // The last point on line ll. // If a null linedesc is passed in, use the one in the line if ( l ) desc = *l; else desc = ll->desc; if ( s ) plotstr = new DisplayString(*s); else { if ( ll->plotstr ) plotstr = new DisplayString(*ll->plotstr); else plotstr = 0; } arrow = a; if ((p = ll->lastplotted())) from = new point(p); ll->lastplotted(&to); } grap-1.46/ylwrap0000755000175000017500000001531313256032133010563 00000000000000#! /bin/sh # ylwrap - wrapper for lex/yacc invocations. scriptversion=2016-01-11.22; # UTC # Copyright (C) 1996-2017 Free Software Foundation, Inc. # # Written by Tom Tromey . # # This program 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 2, or (at your option) # any later version. # # This program 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 . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . get_dirname () { case $1 in */*|*\\*) printf '%s\n' "$1" | sed -e 's|\([\\/]\)[^\\/]*$|\1|';; # Otherwise, we want the empty string (not "."). esac } # guard FILE # ---------- # The CPP macro used to guard inclusion of FILE. guard () { printf '%s\n' "$1" \ | sed \ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' \ -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g' \ -e 's/__*/_/g' } # quote_for_sed [STRING] # ---------------------- # Return STRING (or stdin) quoted to be used as a sed pattern. quote_for_sed () { case $# in 0) cat;; 1) printf '%s\n' "$1";; esac \ | sed -e 's|[][\\.*]|\\&|g' } case "$1" in '') echo "$0: No files given. Try '$0 --help' for more information." 1>&2 exit 1 ;; --basedir) basedir=$2 shift 2 ;; -h|--h*) cat <<\EOF Usage: ylwrap [--help|--version] INPUT [OUTPUT DESIRED]... -- PROGRAM [ARGS]... Wrapper for lex/yacc invocations, renaming files as desired. INPUT is the input file OUTPUT is one file PROG generates DESIRED is the file we actually want instead of OUTPUT PROGRAM is program to run ARGS are passed to PROG Any number of OUTPUT,DESIRED pairs may be used. Report bugs to . EOF exit $? ;; -v|--v*) echo "ylwrap $scriptversion" exit $? ;; esac # The input. input=$1 shift # We'll later need for a correct munging of "#line" directives. input_sub_rx=`get_dirname "$input" | quote_for_sed` case $input in [\\/]* | ?:[\\/]*) # Absolute path; do nothing. ;; *) # Relative path. Make it absolute. input=`pwd`/$input ;; esac input_rx=`get_dirname "$input" | quote_for_sed` # Since DOS filename conventions don't allow two dots, # the DOS version of Bison writes out y_tab.c instead of y.tab.c # and y_tab.h instead of y.tab.h. Test to see if this is the case. y_tab_nodot=false if test -f y_tab.c || test -f y_tab.h; then y_tab_nodot=true fi # The parser itself, the first file, is the destination of the .y.c # rule in the Makefile. parser=$1 # A sed program to s/FROM/TO/g for all the FROM/TO so that, for # instance, we rename #include "y.tab.h" into #include "parse.h" # during the conversion from y.tab.c to parse.c. sed_fix_filenames= # Also rename header guards, as Bison 2.7 for instance uses its header # guard in its implementation file. sed_fix_header_guards= while test $# -ne 0; do if test x"$1" = x"--"; then shift break fi from=$1 # Handle y_tab.c and y_tab.h output by DOS if $y_tab_nodot; then case $from in "y.tab.c") from=y_tab.c;; "y.tab.h") from=y_tab.h;; esac fi shift to=$1 shift sed_fix_filenames="${sed_fix_filenames}s|"`quote_for_sed "$from"`"|$to|g;" sed_fix_header_guards="${sed_fix_header_guards}s|"`guard "$from"`"|"`guard "$to"`"|g;" done # The program to run. prog=$1 shift # Make any relative path in $prog absolute. case $prog in [\\/]* | ?:[\\/]*) ;; *[\\/]*) prog=`pwd`/$prog ;; esac dirname=ylwrap$$ do_exit="cd '`pwd`' && rm -rf $dirname > /dev/null 2>&1;"' (exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 mkdir $dirname || exit 1 cd $dirname case $# in 0) "$prog" "$input" ;; *) "$prog" "$@" "$input" ;; esac ret=$? if test $ret -eq 0; then for from in * do to=`printf '%s\n' "$from" | sed "$sed_fix_filenames"` if test -f "$from"; then # If $2 is an absolute path name, then just use that, # otherwise prepend '../'. case $to in [\\/]* | ?:[\\/]*) target=$to;; *) target=../$to;; esac # Do not overwrite unchanged header files to avoid useless # recompilations. Always update the parser itself: it is the # destination of the .y.c rule in the Makefile. Divert the # output of all other files to a temporary file so we can # compare them to existing versions. if test $from != $parser; then realtarget=$target target=tmp-`printf '%s\n' "$target" | sed 's|.*[\\/]||g'` fi # Munge "#line" or "#" directives. Don't let the resulting # debug information point at an absolute srcdir. Use the real # output file name, not yy.lex.c for instance. Adjust the # include guards too. sed -e "/^#/!b" \ -e "s|$input_rx|$input_sub_rx|" \ -e "$sed_fix_filenames" \ -e "$sed_fix_header_guards" \ "$from" >"$target" || ret=$? # Check whether files must be updated. if test "$from" != "$parser"; then if test -f "$realtarget" && cmp -s "$realtarget" "$target"; then echo "$to is unchanged" rm -f "$target" else echo "updating $to" mv -f "$target" "$realtarget" fi fi else # A missing file is only an error for the parser. This is a # blatant hack to let us support using "yacc -d". If -d is not # specified, don't fail when the header file is "missing". if test "$from" = "$parser"; then ret=1 fi fi done fi # Remove the directory. cd .. rm -rf $dirname exit $ret # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: grap-1.46/grap_pic.h0000664000175000017500000001274113163474043011267 00000000000000// -*-c++-*- #ifndef GRAP_PIC_H #define GRAP_PIC_H // This file is (c) 1998-2001 Ted Faber (faber@lunabase.org) see COPYRIGHT // for the full copyright and limitations of liabilities. extern void linenum(); // This is used by Pictick and Picgrid to iterate across their shifts class Picshiftdraw : unary_function { protected: ostream &f; // The output ostream public: Picshiftdraw(ostream& ff) : f(ff) { } int operator()(shiftdesc *sd) { if ( sd->param != 0 ) { f << "move " ; switch (sd->dir) { case left_side: f << "left "; break; case right_side: f << "right "; break; case top_side: f << "up "; break; case bottom_side: f << "down "; break; } f << sd->param << endl; } return 1; } }; class PicDisplayString : public DisplayString, public drawable { public: PicDisplayString(DisplayString& ds) : DisplayString(ds) { } void draw(frame *); ~PicDisplayString() { }; }; class Pictick : public tick, public drawable { public: Pictick(tick& t) : tick(t) { }; void draw(frame *); ~Pictick() { } }; class Picgrid: public grid, public drawable { public: Picgrid(grid &g) : grid(g) { } void draw(frame *); ~Picgrid() { } }; class Picframe: public frame, public drawable { public: void draw(frame *) ; ~Picframe() { } protected: void autoguess(sides, double &, double&, double&, double &, int&, coord *); void addautoticks(sides); void addautogrids(sides); void frame_line(double, double, sides); void label_line(sides); }; class Piclinesegment : public linesegment, public drawable { protected: // Returns true if the coordinate is between 0 and 1 (withing tolerance). inline bool inbox(double a) { return ( a < 1+epsilon && a > 0-epsilon ); } bool clipx( double &, double &, double &, double &); bool clip( double &, double &, double &, double &); public: Piclinesegment(linesegment &ls) : linesegment(ls) { } Piclinesegment(double x, double y, coord* c, line *l, DisplayString *s=0, linedesc *ld=0, bool a=false) : linesegment(x, y, c, l, s, ld, a) { } ~Piclinesegment() { } void draw(frame *); }; // Sequence is defined in grap_data.h class Picplot: public plot, public drawable { public: Picplot(plot& p) : plot(p) { } Picplot(stringlist *s =0, point *p=0) : plot(s, p) { } ~Picplot() { } void draw(frame *); }; class Piccircle: public circle, public drawable { public: Piccircle(circle& c) : circle(c) { } Piccircle(point *p, double r, linedesc *l=0) : circle(p, r, l) { } ~Piccircle() { } void draw(frame *); }; class Picbox: public box, public drawable { protected: void swap(double &a, double &b) { double h = a; a =b ; b =h; } public: Picbox(box& b) : box(b) { } Picbox(point *p1, point *p2, linedesc *l) : box(p1, p2, l) { } ~Picbox() { } void draw(frame *); }; class Picthrustring : public string, public drawable { public: Picthrustring(const string &s) : string(s) { } ~Picthrustring() { } void draw(frame *) { cout << *this << endl; } }; class Picgraph : public graph { string *ps_param; // The params to .G1 string *pos; // the position of the graph (in pic) int graphs; // the number of graphs drawn this block bool frame_queued; // The frame is on the object list Picframe *pframe; // The pic frame for deallocation public: // regular member functions Picgraph() : graph(), ps_param(0), pos(0), graphs(0), pframe(0) { } ~Picgraph() { // pframe should always be a copy of base, so don't delete it. // It will be deallocated by graph::init. delete ps_param; ps_param = 0; delete pos; pos = 0; } // overload the virtual functions in graph void init(string * =0, string* =0); void begin_block(string *param) { graphs = 0; ps_param = param; } void end_block() { if ( graphs ) { cout << ".PE" << endl; linenum(); } } void passthru_string(const string& s) { Picthrustring *t = new Picthrustring(s); if ( t ) objs.push_back(t); } virtual linesegment *new_linesegment(double x, double y, coord* c, line *l, DisplayString *s=0, linedesc *ld=0, bool a=false) { Piclinesegment *pls = new Piclinesegment(x, y, c, l, s, ld, a); queue_frame(); if (pls) objs.push_back(pls); return pls; } virtual plot *new_plot(stringlist *s =0, point *p=0) { Picplot *pl = new Picplot(s, p); queue_frame(); if ( pl ) objs.push_back(pl); return pl; } virtual circle *new_circle(point *p, double r, linedesc *l=0) { Piccircle *c = new Piccircle(p, r, l); queue_frame(); if ( c ) objs.push_back(c); return c; } virtual box *new_box(point *p1, point *p2, linedesc *l) { Picbox *b = new Picbox(p1, p2, l); queue_frame(); if ( b ) objs.push_back(b); return b; } virtual void queue_frame() { if ( !frame_queued ) { objs.push_back(pframe); frame_queued = true; } } void draw(frame *); }; class Piccoord: public coord, public drawable { public: Piccoord(const coord& c) : coord(c) { } ~Piccoord() { } void draw(frame *f) { const string& nm = (name != "") ? name : "gg"; cout << "define x_"<< nm << " { ((( $1 - " << xmin << ") / " << xmax-xmin << ") * " << f->wid << " ) }" << endl; cout << "define y_"<< nm << " { ((( $1 - " << ymin << ") / " << ymax-ymin << ") * " << f->ht << " ) }" << endl; cout << "define xy_" << nm << " { x_" << nm << "($1), " << "y_"<< nm << "($2) }" << endl; } }; #endif grap-1.46/config.h.in0000664000175000017500000000634713670320204011352 00000000000000/* config.h.in. Generated from configure.ac by autoheader. */ /* The pathname of the grap.defines file */ #undef DEFINES /* The directory for documentation */ #undef DOCS_DIR /* The directory for examples */ #undef EXAMPLES_DIR /* True if the grap sprintf command is disabled */ #undef GRAP_SAFER /* C++ namespace where hash_map lives */ #undef HASH_SPACE /* Define to 1 if you have the header file. */ #undef HAVE_ERRNO_H /* Define to 1 if you have the header file. */ #undef HAVE_EXT_HASH_MAP /* Define to 1 if you have the header file. */ #undef HAVE_HASH_MAP /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_LIMITS /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the `rand' function. */ #undef HAVE_RAND /* Define to 1 if you have the `random' function. */ #undef HAVE_RANDOM /* Define to 1 if you have the `snprintf' function. */ #undef HAVE_SNPRINTF /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the `strdup' function. */ #undef HAVE_STRDUP /* Define to 1 if you have the `strerror' function. */ #undef HAVE_STRERROR /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to 1 if you have the header file. */ #undef HAVE_UNORDERED_MAP /* True if optarg is defined by headers */ #undef OPTARG_DEFINED /* OS version */ #undef OS_VERSION /* Name of package */ #undef PACKAGE /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* True if random() is declared */ #undef RANDOM_DECLARED /* True if random() is declared in math.h */ #undef RANDOM_IN_MATH /* True if rand() is declared */ #undef RAND_DECLARED /* True if rand() is declared in math.h */ #undef RAND_IN_MATH /* Is snprintf declared? */ #undef SNPRINTF_DECLARED /* True if sprintf does not return an integer */ #undef SPRINTF_NOT_INT /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* True if strdup is declared */ #undef STRDUP_DECLARED /* True if strerror is declared */ #undef STRERROR_DECLARED /* Version number of package */ #undef VERSION /* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a `char[]'. */ #undef YYTEXT_POINTER /* Define to `unsigned int' if does not define. */ #undef size_t grap-1.46/NEWS0000664000175000017500000000007013163474043010021 00000000000000See CHANGES (automake barfs if this file isn't around) grap-1.46/grap.man0000664000175000017500000012416713670320204010756 00000000000000GRAP(1) BSD General Commands Manual GRAP(1) NNAAMMEE ggrraapp -- Kernighan and Bentley's language for typesetting graphs SSYYNNOOPPSSIISS ggrraapp [--dd _d_e_f_i_n_e_s___f_i_l_e] [--DD] [--ll] [--MM _i_n_c_l_u_d_e _p_a_t_h] [--RR] [--rr] [--vv] [--uu] [--CC] [--cc] [--hh] [_f_i_l_e_n_a_m_e _._._.] DDEESSCCRRIIPPTTIIOONN ggrraapp is an implementation of Kernighan and Bentley's language for type- setting graphs, as described in ``Grap-A Language for Typesetting Graphs, Tutorial and User Manual,'' by Jon L. Bentley and Brian W. Kernighan, revised May 1991, which is the primary source for information on how to use ggrraapp. As of this writing, it is available electronically at http://www.kohala.com/start/troff/cstr114.ps. Additional documentation and examples, packaged with ggrraapp, may have been installed locally as well. If available, paths to them can be displayed using ggrraapp --hh or ggrraapp --vv (or ggrraapp ----hheellpp / ggrraapp ----vveerrssiioonn) This version is a black box implementation of ggrraapp, and some inconsisten- cies are to be expected. The remainder of this manual page will briefly outline the ggrraapp language as implemented here. ggrraapp is a pic(1) pre-processor. It takes commands embedded in a troff(1) source file which are surrounded by ..GG11 and ..GG22 macros, and rewrites them into pic commands to display the graph. Other lines are copied. Output is always to the standard output, which is usually redirected. Input is from the given _f_i_l_e_n_a_m_es, which are read in order. A _f_i_l_e_n_a_m_e of -- is the standard input. If no _f_i_l_e_n_a_m_es are given, input is read from the standard input. Because ggrraapp is a pic preprocessor, and GNU pic will output TeX, it is possible to use ggrraapp with TeX. The --dd option specifies a file of macro definitions to be read at startup, and defaults to /usr/local/share/grap/grap.defines . The --DD option inhibits the reading of any initial macros file (the --ll flag is a synonym for --DD, though I do not remember why). The defines file can also be given using the GRAP_DEFINES environment variable. (See below). --vv prints the version information on the standard output and exits. ----vveerrssiioonn is a synonym for --vv. --uu makes labels unaligned by default. This version of ggrraapp uses new fea- tures of GNU pic to align the left and right labels with the axes, that is that the left and right labels run at right angles to the text of the paper. This may be useful in porting old ggrraapp programs. --cc makes plot strings unclipped by default. Some versions of ggrraapp allow users to place a string anywhere in the coordinate space, rather than only in the frame. By default this version of ggrraapp does not plot any string centered outside the frame. --cc allows strings to be placed anywhere. See also the cclliippppeedd and uunncclliippppeedd string modifiers described in the pplloott statement. --MM is followed by a colon-separated list of directories used to search for relative pathnames included via ccooppyy. The path is also used to locate the defines file, so if the --dd changes the defines file name to a relative name, it will be searched for in the path given by --MM. The search path always includes the current directory, and by default that directory is searched last. All numbers used internally by ggrraapp are double precision floating point values. Sometimes using floating point numbers has unintended conse- quences. To help avoid these problems, ggrraapp can use two thresholds for comparison of floating point numbers, set by --RR or --rr. The --RR flag sets coarse comparison mode, which is suitable for most applications. If you are plotting small values - less than 1e-6 or so - consider using --rr which uses very fine comparisons between numbers. You may also want to rescale your plotted values to be larger in magnitude. The coarse comarisons are used by default. To be precise, the value by which two numbers must differ for ggrraapp to consider them not equal is called the comparison limit and the smallest non-zero number is called the minimum value. The values a given version of ggrraapp uses for these are included in the output of --vv or --hh. All ggrraapp commands are included between ..GG11 and ..GG22 macros, which are con- sumed by ggrraapp. The output contains pic between ..PPSS and ..PPEE macros. Any arguments to the ..GG11 macro in the input are arguments to the ..PPSS macro in the output, so graphs can be scaled just like pic diagrams. If --CC is given, any macro beginning with .G1 or .G2 is treated as a .G1 or .G2 macro, for compatibility with old versions of troff. Using --CC also forces pure troff syntax on embedded font change commands when strings have the ssiizzee attribute, and all strings to be uunncclliippppeedd. The --hh flag prints a brief help message and exits. ----hheellpp is a synonym for --hh. It is possible for someone to cause ggrraapp to fail by passing a bad format string and data to the sspprriinnttff command. If ggrraapp is integrated as part of the printing system, this could conceivably provided a path to breaching security on the machine. If you choose to use ggrraapp as part of a printing system run by the super-user, you should disable sspprriinnttff commands. This can be done by calling ggrraapp with the --SS flag, setting the GRAP_SAFER environment variable, or compiling with the GRAP_SAFER preprocessor sym- bol defined. (The GNU configure script included with ggrraapp will define that preprocessor symbol if the ----wwiitthh--ggrraapp--ssaaffee option is given.) The ggrraapp commands are sketched below. Refer to Kernighan and Bentley's paper for the details. New versions of groff(1) will invoke ggrraapp if --GG is given. CCoommmmaannddss Commands are separated from one another by newlines or semicolons (;). ffrraammee [_l_i_n_e___d_e_s_c_r_i_p_t_i_o_n] [hhtt _h_e_i_g_h_t | wwiidd _w_i_d_t_h] [[(ttoopp|bboottttoomm|lleefftt| rriigghhtt) _l_i_n_e___d_e_s_c_r_i_p_t_i_o_n] ...] ffrraammee [hhtt _h_e_i_g_h_t | wwiidd _w_i_d_t_h] [_l_i_n_e___d_e_s_c_r_i_p_t_i_o_n] [[(ttoopp|bboottttoomm|lleefftt| rriigghhtt) _l_i_n_e___d_e_s_c_r_i_p_t_i_o_n] ...] This describes how the axes for the graph are drawn. A _l_i_n_e___d_e_s_c_r_i_p_t_i_o_n is a pic line description, e.g., dashed 0.5, or the literal solid. It may also include a ccoolloorr keyword followed by the color to draw the string in double quotes. Any color under- stood by the underlying groff system can be used. Color can only be used under GNU pic, and is not available in compatibility mode. Similarly, for pic implementations that understand tthhiicckknneessss, that attribute may be used with a real valued parameter. TThhiicckknneessss is not available in compatibility mode. If the first _l_i_n_e___d_e_s_c_r_i_p_t_i_o_n is given, the frame is drawn with that style. The default is solid. The height and width of the frame can also be specified in inches. The default line style can be over-ridden for sides of the frame by specifying additional parameters to ffrraammee. If no plotting commands have been given before the ffrraammee command is issued, the frame will be output at that point in the plotting stream relative to embedded troff or pic commands. Otherwise the frame is output before the first plotted object (even invisible ones). hhtt and wwiidd are in inches by default, but can be any groff unit. If omitted, the dimensions are 2 inches high by 3 inches wide. ccoooorrdd [_n_a_m_e] [xx _e_x_p_r, _e_x_p_r] [yy _e_x_p_r, _e_x_p_r] [lloogg xx | lloogg yy | lloogg lloogg] The ccoooorrdd command specifies a new coordinate system or sets limits on the default system. It defines the largest and smallest values that can be plotted, and therefore the scale of the data in the frame. The limits for the x and y coordinate systems can be given separately. If a _n_a_m_e is given, that coordinate system is defined, if not the default system is modified. A coordinate system created by one ccoooorrdd command may be modified by subsequent ccoooorrdd commands. A ggrraapp program may declare a coordinate space using ccoooorrdd, ccooppyy a file of data through a macro that plots the data and finds its maxima and minima, and then define the size of the coordinate system with a second ccoooorrdd statement. This command also determines if a scale is plotted logarithmically. lloogg lloogg means the same thing as lloogg xx lloogg yy. ddrraaww [_l_i_n_e___n_a_m_e] [_l_i_n_e___d_e_s_c_r_i_p_t_i_o_n] [_p_l_o_t___s_t_r_i_n_g] The ddrraaww command defines the style with which a given line will be plotted. If _l_i_n_e___n_a_m_e is given, the style is associated with that name, otherwise the default style is set. _l_i_n_e___d_e_s_c_r_i_p_t_i_o_n is a pic line description, and the optional _p_l_o_t___s_t_r_i_n_g is a string to be centered at each point. The default line description is invis, and the default plotting string is a centered bullet, so by default each point is a filled circle, and they are unconnected. If points are being connected, each ddrraaww command ends any current line and begins a new one. When defining a line style, that is the first ddrraaww command for a given line name, specifying no plot string means that there are to be no plot strings. Omitting the plot string on subsequent ddrraaww commands addressing the same named line means not to change the plot string. If a line has been defined with a plot string, and the format is changed by a subsequent ddrraaww statement, the plot string can be removed by specifying "" in the ddrraaww statement. The plot string can have its format changed through several string_modifiers. String_modifiers are described in the descrip- tion of the pplloott command. The standard defines file includes several macros useful as plot strings, including bbuulllleett, ssqquuaarree, and ddeellttaa. nneeww is a synonym for ddrraaww. nneexxtt [_l_i_n_e___n_a_m_e] aatt [_c_o_o_r_d_i_n_a_t_e_s___n_a_m_e] _e_x_p_r, _e_x_p_r [_l_i_n_e___d_e_s_c_r_i_p_t_i_o_n] The nneexxtt command plots the given point using the line style given by _l_i_n_e___n_a_m_e, or the default if none is given. If _l_i_n_e___n_a_m_e is given, it should have been defined by an earlier ddrraaww command, if not a new line style with that name is created, initialized the same way as the default style. The two expressions give the point's x and y values, relative to the optional coordinate system. That system should have been defined by an earlier ccoooorrdd command, if not, grap will exit. If the optional _l_i_n_e___d_e_s_c_r_i_p_t_i_o_n is given, it overrides the style's default line description. You cannot over-ride the plotting string. To use a different plotting string use the pplloott command. The coordinates may optionally be enclosed in parentheses: (_e_x_p_r, _e_x_p_r) _q_u_o_t_e_d___s_t_r_i_n_g [_s_t_r_i_n_g___m_o_d_i_f_i_e_r_s] [, _q_u_o_t_e_d___s_t_r_i_n_g [_s_t_r_i_n_g___m_o_d_i_f_i_e_r_s]] ... aatt [_c_o_o_r_d_i_n_a_t_e_s___n_a_m_e] _e_x_p_r, _e_x_p_r pplloott _e_x_p_r [_f_o_r_m_a_t___s_t_r_i_n_g] aatt [_c_o_o_r_d_i_n_a_t_e_s___n_a_m_e] _e_x_p_r, _e_x_p_r These commands both plot a string at the given point. In the first case the literal strings are stacked above each other. The string_modifiers include the pic justification modifiers (lljjuusstt, rrjjuusstt, aabboovvee, and bbeellooww), and absolute and relative size modifiers. See the pic documentation for the description of the justification modifiers. ggrraapp also supports the aalliiggnneedd and uunnaalliiggnneedd modifiers which are briefly noted in the description of the llaabbeell command. The standard defines file includes several macros useful as plot strings, including bbuulllleett, ssqquuaarree, and ddeellttaa. Strings placed by either format of the pplloott command are restricted to being within the frame. This can be overridden by using the uunncclliippppeedd attribute, which allows a string to be plotted in or out of the frame. The --cc and --CC flags set uunncclliippppeedd on all strings, and to prevent a string from being plotted outside the frame when those flags are active, the cclliippppeedd attribute can be used to retore clipping behavior. Though cclliippppeedd or uunncclliippppeedd can be applied to any string, it only has meaning for pplloott statements. size _e_x_p_r sets the string size to _e_x_p_r points. If _e_x_p_r is preceded by a + or -, the size is increased or decreased by that many points. If ccoolloorr and a color name in double quotes appears, the string will be rendered in that color under a version of GNU troff that sup- ports color. Color is not available in compatibility mode. In the second version, the _e_x_p_r is converted to a string and placed on the graph. _f_o_r_m_a_t___s_t_r_i_n_g is a printf(3) format string. Only formatting escapes for printing floating point numbers make sense. The format string is only respected if the sspprriinnttff command is also active. See the description of sspprriinnttff for the various ways to disable it. PPlloott and sspprriinnttff respond differently when ggrraapp is run- ning safely. SSpprriinnttff ignores any arguments, passing the format string through without substitution. pplloott ignores the format string completely, plotting _e_x_p_r using the "%g" format. Points are specified the same way as for nneexxtt commands, with the same consequences for undefined coordinate systems. The second form of this command is because the first form can be used with a ggrraapp sspprriinnttff expression (See _E_x_p_r_e_s_s_i_o_n_s). ttiicckkss (lleefftt|rriigghhtt|ttoopp|bboottttoomm)[ (iinn|oouutt) [_e_x_p_r]] [oonn||aauuttoo _c_o_o_r_d___n_a_m_e] ttiicckkss (lleefftt|rriigghhtt|ttoopp|bboottttoomm) (iinn|oouutt) [_e_x_p_r] [uupp _e_x_p_r | ddoowwnn _e_x_p_r | lleefftt _e_x_p_r | rriigghhtt _e_x_p_r] aatt [_c_o_o_r_d___n_a_m_e] _e_x_p_r [_f_o_r_m_a_t___s_t_r_i_n_g] [[, _e_x_p_r [_f_o_r_m_a_t___s_t_r_i_n_g]] ...] ttiicckkss (lleefftt|rriigghhtt|ttoopp|bboottttoomm) (iinn|oouutt) [_e_x_p_r] [uupp _e_x_p_r | ddoowwnn _e_x_p_r | lleefftt _e_x_p_r | rriigghhtt _e_x_p_r] ffrroomm [coord_name] _s_t_a_r_t___e_x_p_r ttoo _e_n_d___e_x_p_r [bbyy [+|-|*|/] _b_y___e_x_p_r] [format_string] ttiicckkss [lleefftt|rriigghhtt|ttoopp|bboottttoomm] ooffff This command controls the placement of ticks on the frame. By default, ticks are automatically generated on the left and bottom sides of the frame. The first version of this command turns on the automatic tick gen- eration for a given side. The iinn or oouutt parameter controls the direction and length of the ticks. If a _c_o_o_r_d___n_a_m_e is specified, the ticks are automatically generated using that coordinate system. If no system is specified, the default coordinate system is used. As with nneexxtt and pplloott, the coordinate system must be declared before the ttiicckkss statement that references it. This syntax for requesting automatically generated ticks is an extension, and will not port to older ggrraapp implementations. The second version of the ttiicckkss command overrides the automatic placement of the ticks by specifying a list of coordinates at which to place the ticks. If the ticks are not defined with respect to the default coordinate system, the _c_o_o_r_d___n_a_m_e parameter must be given. For each tick a printf(3) style format string can be given. The _f_o_r_m_a_t___s_t_r_i_n_g defaults to "%g". The format string can also take string modifiers as described in the pplloott command. To place ticks with no labels, specify _f_o_r_m_a_t___s_t_r_i_n_g as "". If sspprriinnttff is disabled, ttiicckkss behaves as pplloott with respect to the format string. The labels on the ticks may be shifted by specifying a direction and the distance in inches to offset the label. That is the optional direction and expression immediately preceding the aatt. The third format of the ttiicckkss command over-rides the default tick generation with a set of ticks ar regular intervals. The syntax is reminiscent of programming language for loops. Ticks are placed starting at _s_t_a_r_t___e_x_p_r ending at _e_n_d___e_x_p_r one unit apart. If the bbyy clause is specified, ticks are _b_y___e_x_p_r units apart. If an oper- ator appears before _b_y___e_x_p_r each tick is operated on by that opera- tor instead of +. For example ticks left out from 2 to 32 by *2 will put ticks at 2, 4, 8, 16, and 32. If _f_o_r_m_a_t___s_t_r_i_n_g is speci- fied, all ticks are formatted using it. The parameters preceding the ffrroomm act as described above. The aatt and ffoorr forms of tick command may both be issued on the same side of a frame. For example: ticks left out from 2 to 32 by *2 ticks left in 3, 5, 7 will put ticks on the left side of the frame pointing out at 2, 4, 8, 16, and 32 and in at 3, 5, and 7. The final form of ttiicckkss turns off ticks on a given side. If no side is given the ticks for all sides are cancelled. ttiicckk is a synonym for ttiicckkss. ggrriidd (lleefftt|rriigghhtt|ttoopp|bboottttoomm) [ticks off] [_l_i_n_e___d_e_s_c_r_i_p_t_i_o_n] [uupp _e_x_p_r | ddoowwnn _e_x_p_r | lleefftt _e_x_p_r | rriigghhtt _e_x_p_r] [oonn||aauuttoo [_c_o_o_r_d___n_a_m_e]] ggrriidd (lleefftt|rriigghhtt|ttoopp|bboottttoomm) [ticks off] [_l_i_n_e___d_e_s_c_r_i_p_t_i_o_n] [uupp _e_x_p_r | ddoowwnn _e_x_p_r | lleefftt _e_x_p_r | rriigghhtt _e_x_p_r] aatt [_c_o_o_r_d___n_a_m_e] _e_x_p_r [_f_o_r_m_a_t___s_t_r_i_n_g] [[, _e_x_p_r [_f_o_r_m_a_t___s_t_r_i_n_g]] ...] ggrriidd (lleefftt|rriigghhtt|ttoopp|bboottttoomm) [ticks off] [_l_i_n_e___d_e_s_c_r_i_p_t_i_o_n] [uupp _e_x_p_r | ddoowwnn _e_x_p_r | lleefftt _e_x_p_r | rriigghhtt _e_x_p_r] ffrroomm [coord_name] _s_t_a_r_t___e_x_p_r ttoo _e_n_d___e_x_p_r [bbyy [+|-|*|/] _b_y___e_x_p_r] [format_string] The ggrriidd command is similar to the ttiicckkss command except that ggrriidd specifies the placement of lines in the frame. The syntax is simi- lar to ttiicckkss as well. By specifying ticks off in the command, no ticks are drawn on that side of the frame. If ticks appear on a side by default, or have been declared by an earlier ttiicckkss command, ggrriidd does not cancel them unless ticks off is specified. Instead of a direction for ticks, ggrriidd allows the user to pick a line description for the grid lines. The usual pic line descrip- tions are allowed. Grids are labelled by default. To omit labels, specify the format string as "". If sspprriinnttff is disabled, ggrriidd behaves as pplloott with respect to the format string. llaabbeell (lleefftt|rriigghhtt|ttoopp|bboottttoomm) _q_u_o_t_e_d___s_t_r_i_n_g [_s_t_r_i_n_g___m_o_d_i_f_i_e_r_s] [, _q_u_o_t_e_d___s_t_r_i_n_g [_s_t_r_i_n_g___m_o_d_i_f_i_e_r_s]] ... [uupp _e_x_p_r | ddoowwnn _e_x_p_r | lleefftt _e_x_p_r | rriigghhtt _e_x_p_r] The llaabbeell command places a label on the given axis. It is possible to specify several labels, which will be stacked over each other as in pic. The final argument, if present, specifies how many inches the label is shifted from the axis. By default the labels on the left and right labels run parallel to the frame. You can cancel this by specifying unaligned as a _s_t_r_i_n_g___m_o_d_i_f_i_e_r. cciirrccllee aatt [_c_o_o_r_d_i_n_a_t_e___n_a_m_e] _e_x_p_r, _e_x_p_r [rraaddiiuuss _e_x_p_r] [_l_i_n_e_d_e_s_c] This draws an circle at the point indicated. By default, the cir- cle is small, 0.025 inches. This can be over-ridden by specifying a radius. The coordinates of the point are relative to the named coordinate system, or the default system if none is specified. This command has been extended to take a line description, e.g., dotted. It also accepts the filling extensions described below in the bbaarr command. It will also accept a ccoolloorr keyword that gives the color of the outline of the circle in double quotes and a ffiillllccoolloorr command that sets the color to fill the circle with simi- larly. Colors are only available when compatibility mode is off, and using a version of GNU pic that supports color. lliinnee [_l_i_n_e___d_e_s_c_r_i_p_t_i_o_n] ffrroomm [_c_o_o_r_d_i_n_a_t_e___n_a_m_e] _e_x_p_r, _e_x_p_r ttoo [_c_o_o_r_d_i_n_a_t_e___n_a_m_e] _e_x_p_r, _e_x_p_r [_l_i_n_e___d_e_s_c_r_i_p_t_i_o_n] aarrrrooww [_l_i_n_e___d_e_s_c_r_i_p_t_i_o_n] ffrroomm [_c_o_o_r_d_i_n_a_t_e___n_a_m_e] _e_x_p_r, _e_x_p_r ttoo [_c_o_o_r_d_i_n_a_t_e___n_a_m_e] _e_x_p_r, _e_x_p_r [_l_i_n_e___d_e_s_c_r_i_p_t_i_o_n] This draws a line or arrow from the first point to the second using the given style. The default line style is solid. The _l_i_n_e___d_e_s_c_r_i_p_t_i_o_n can be given either before the ffrroomm or after the ttoo clause. If both are given the second is used. It is possible to specify one point in one coordinate system and one in another, note that if both points are in a named coordinate system (even if they are in the same named coordinate system), both points must have _c_o_o_r_d_i_n_a_t_e___n_a_m_e given. ccooppyy ["_f_i_l_e_n_a_m_e"] [uunnttiill "_s_t_r_i_n_g"] [tthhrruu _m_a_c_r_o] The ccooppyy command imports data from another file into the current graph. The form with only a filename given is a simple file inclu- sion; the included file is simply read into the input stream and can contain arbitrary ggrraapp commands. The more common case is that it is a number list; see _N_u_m_b_e_r _L_i_s_t_s below. The second form takes lines from the file, splits them into words delimited by one or more spaces, and calls the given macro with those words as parameters. The macro may either be defined here, or be a macro defined earlier. See _M_a_c_r_o_s for more information on macros. The _f_i_l_e_n_a_m_e may be omitted if the uunnttiill clause is present. If so the current file is treated as the input file until _s_t_r_i_n_g is encountered at the beginning of the line. ccooppyy is one of the workhorses of ggrraapp. Check out the paper and _/_u_s_r_/_l_o_c_a_l_/_s_h_a_r_e_/_e_x_a_m_p_l_e_s_/_g_r_a_p for more details. Confirm the loca- tion of the examples directory using the --vv flag. pprriinntt (_e_x_p_r_|_s_t_r_i_n_g) Prints its argument to the standard error. sshh _b_l_o_c_k This passes _b_l_o_c_k to sh(1). Unlike K&B ggrraapp no macro or variable expansion is done. I believe that this is also true for GNU pic version 1.10. See the _M_a_c_r_o_s section for information on defining blocks. ppiicc _p_i_c___s_t_a_t_e_m_e_n_t This issues the given pic statements in the enclosing ..PPSS and ..PPEE at the point where the command is issued. Statements that begin with a period are considered to be troff(statements) and are output in the enclosing ..PPSS and ..PPEE at the point where the command appears. For the purposes of relative placement of pic or troff commands, the frame is output immediately before the first plotted object, or the ffrraammee statement, if any. If the user specifies pic or troff commands and neither any plotable object nor a ffrraammee command, the commands will not be output. ggrraapphh _N_a_m_e _p_i_c___c_o_m_m_a_n_d_s This command is used to position graphs with respect to each other. The current graph is given the pic name _N_a_m_e (names used by pic begin with capital letters). Any pic commands following the graph are used to position the next graph. The frame of the graph is available for use with pic name Frame. The following places a sec- ond graph below the first: graph Linear [ graph description ] graph Exponential with .Frame.n at \ Linear.Frame.s - (0, .05) [ graph description ] _n_a_m_e _= _e_x_p_r This assigns _e_x_p_r to the variable _n_a_m_e. ggrraapp has only numeric (double) variables. Assignment creates a variable if it does not exist. Variables per- sist across graphs. Assignments can cascade; a = b = 35 assigns 35 to a and b. bbaarr (uupp|rriigghhtt) [_c_o_o_r_d_i_n_a_t_e_s___n_a_m_e] _o_f_f_s_e_t hhtt _h_e_i_g_h_t [wwiidd _w_i_d_t_h] [bbaassee _b_a_s_e___o_f_f_s_e_t] [_l_i_n_e___d_e_s_c_r_i_p_t_i_o_n] bbaarr [_c_o_o_r_d_i_n_a_t_e_s___n_a_m_e] _e_x_p_r, _e_x_p_r, [_c_o_o_r_d_i_n_a_t_e_s___n_a_m_e] _e_x_p_r, _e_x_p_r, [_l_i_n_e___d_e_s_c_r_i_p_t_i_o_n] The bbaarr command facilitates drawing bar graphs. The first form of the command describes the bar somewhat generally and has ggrraapp place it. The bar may extend up or to the right, is centered on _o_f_f_s_e_t and extends up or right _h_e_i_g_h_t units (in the given coordinate sys- tem). For example bar up 3 ht 2 draws a 2 unit high bar sitting on the x axis, centered on x=3. By default bars are 1 unit wide, but this can be changed with the wwiidd keyword. By default bars sit on the base axis, i.e., bars directed up will extend from y=0. That may be overridden by the bbaassee key- word. (The bar described above has corners (2.5, 0) and (3.5, 2).) The line description has been extended to include a ffiillll _e_x_p_r key- word that specifies the shading inside the bar. Bars may be drawn in any line style. They support the ccoolloorr and ffiillllccoolloorr keywords described under cciirrccllee. The second form of the command draws a box with the two points as corners. This can be used to draw boxes highlighting certain data as well as bar graphs. Note that filled bars will cover data drawn under them. CCoonnttrrooll FFllooww iiff _e_x_p_r tthheenn _b_l_o_c_k [eellssee _b_l_o_c_k] The iiff statement provides simple conditional execution. If _e_x_p_r is non-zero, the _b_l_o_c_k after the tthheenn statement is executed. If not the _b_l_o_c_k after the eellssee is executed, if present. See _M_a_c_r_o_s for the definition of blocks. Early versions of this implementation of ggrraapp treated the blocks as macros that were defined and expanded in place. This led to unnecessary confusion because explicit separa- tors were sometimes called for. Now, ggrraapp inserts a separator (;) after the last character in _b_l_o_c_k, so constructs like if (x == 3) { y = y + 1 } x = x + 1 behave as expected. A separator is also appended to the end of a ffoorr block. ffoorr _n_a_m_e ffrroomm _f_r_o_m___e_x_p_r ttoo _t_o___e_x_p_r [bbyy [+|-|*|/] _b_y___e_x_p_r] ddoo _b_l_o_c_k This command executes _b_l_o_c_k iteratively. The variable _n_a_m_e is set to _f_r_o_m___e_x_p_r and incremented by _b_y___e_x_p_r until it exceeds _t_o___e_x_p_r. The iteration has the semantics defined in the ttiicckkss command. The definition of _b_l_o_c_k is discussed in _M_a_c_r_o_s. See also the note about implicit separators in the description of the iiff command. An == can be used in place of ffrroomm. EExxpprreessssiioonnss ggrraapp supports most standard arithmetic operators: + - / * ^. The carat (^) is exponentiation. In an iiff statement ggrraapp also supports the C logi- cal operators ==, !=, &&, || and unary !. Also in an iiff, == and != are overloaded for the comparison of quoted strings. Parentheses are used for grouping. Assignment is not allowed in an expression in any context, except for simple cascading of assignments. a = b = 35 works as expected; a = 3.5 * (b = 10) does not execute. ggrraapp supports the following functions that take one argument: lloogg, eexxpp, iinntt, ssiinn, ccooss, ssqqrrtt, rraanndd, fflloooorr, cceeiill. The logarithms are base 10 and the trigonometric functions are in radians. eeeexxpp returns Euler's number to the given power and llnn returns the natural logarithm. The natural log, exponentiation functions and floor and ceil are extensions and are probably not available in other ggrraapp implementations. rraanndd returns a random number uniformly distributed on [0,1). The follow- ing two-argument functions are supported: aattaann22, mmiinn, mmaaxx. aattaann22 works just like atan2(3). The random number generator can be seeded by calling ssrraanndd with a single parameter (converted internally to an integer). Because its return value is of no use, you must use ssrraanndd as a separate statement, it is not part of a valid expression. ssrraanndd is not portable. The ggeettppiidd function takes no arguments and returns the process id. This may be used to seed the random number generator, but do not expect cryp- tographically random values to result. Other than string comparison, no expressions can use strings. One string valued function exists: sspprriinnttff (_f_o_r_m_a_t, [_e_x_p_r [_, _e_x_p_r]] ). It operates like sprintf(3), except returning the value. It can be used anywhere a quoted string is used. If ggrraapp is run with --SS, the environment variable GRAP_SAFER is defined, or ggrraapp has been compiled for safer operation, the sspprriinnttff command will return the format string. This mode of operation is only intended to be used only if ggrraapp is being used as part of a super- user enabled print system. ggrraapp version 1.44 and beyond support two functions for date and time manipulation, ssttrrppttiimmee and ssttrrppttiimmee. ssttrrppttiimmee parses a time using the strptime(3) function. It takes two parameters, both strings, the format and a string to parse using that format and returns a number that can be sorted directly - the number of seconds since the UNIX epoch. ssttrrffttiimmee does the reverse. It takes a string and a number and formats the number into a date. In both functions, the format is the first parameter. The formats are defined in the documentation for strftime(3). MMaaccrrooss ggrraapp has a simple but powerful macro facility. Macros are defined using the ddeeffiinnee command : ddeeffiinnee _n_a_m_e _b_l_o_c_k uunnddeeffiinnee _n_a_m_e Every occurrence of _n_a_m_e in the program text is replaced by the contents of _b_l_o_c_k. _b_l_o_c_k is defined by a series of statements in nested { }'s, or a series of statements surrounded by the same let- ter. An example of the latter is define foo X coord x 1,3 X Each time foo appears in the text, it will be replaced by coord x 1,3. Macros are literal, and can contain newlines. If a macro does not span multiple lines, it should end in a semicolon to avoid parsing errors. Macros can take parameters, too. If a macro call is followed by a parenthesized, comma-separated list the values starting with $1 will be replaced in the macro with the elements of the list. A $ not followed by a digit is left unchanged. This parsing is very rudimentary; no nesting or parentheses or escaping of commas is allowed. Also, there is no way to say argument 1 followed by a digit (${1}0 in sh(1)). The following will draw a line with slope 1. define foo { next at $1, $2 } for i from 1 to 5 { foo(i,i) } Macros persist across graphs. The file _/_u_s_r_/_l_o_c_a_l_/_s_h_a_r_e_/_g_r_a_p_/_g_r_a_p_._d_e_f_i_n_e_s contains simple macros for plot- ting common characters. The uunnddeeffiinnee command deletes a macro. See the directory _/_u_s_r_/_l_o_c_a_l_/_s_h_a_r_e_/_e_x_a_m_p_l_e_s_/_g_r_a_p for more examples of macros. Confirm the location of the examples directory using the --vv flag. NNuummbbeerr LLiissttss A whitespace-separated list of numbers is treated specially. The list is taken to be points to be plotted using the default line style on the default coordinate system. If more than two numbers are given, the extra numbers are taken to be additional y values to plot at the first x value. Number lists in DWB ggrraapp can be comma-separated, and this ggrraapp supports that as well. More precisely, numbers in number lists can be separated by either whitespace, commas, or both. 1 2 3 4 5 6 Will plot points using the default line style at (1,2), (1,3),(4,5) and (4,6). A simple way to plot a set of numbers in a file named _._/_d_a_t_a is: .G1 copy "./data" .G2 PPiicc MMaaccrrooss ggrraapp defines pic macros that can be used in embedded pic code to place elements in the graph. The macros are xx__gggg, yy__gggg, and xxyy__gggg. These macros define pic distances that correspond to the given argument. They can be used to size boxes or to plot pic constructs on the graph. To place a given construct on the graph, you should add Frame.Origin to it. Other coordinate spaces can be used by replacing gggg with the name of the coordinate space. A coordinate space named gggg cannot be reliably accessed by these macros. The macros are emitted immediately before the frame is drawn. DWB ggrraapp may use these as part of its implementation. This ggrraapp provides them only for compatibility. Note that these are very simple macros, and may not do what you expect under complex conditions. EENNVVIIRROONNMMEENNTT VVAARRIIAABBLLEESS If the environment variable GRAP_DEFINES is defined, ggrraapp will look for its defines file there. If that value is a relative path name the path specified in the --MM option will be searched for it. GRAP_DEFINES over- rides the compiled in location of the defines file, but may be overridden by the --dd or --DD flags. If GRAP_SAFER is set, sspprriinnttff is disabled to prevent forcing ggrraapp to core dump or smash the stack. FFIILLEESS _/_u_s_r_/_l_o_c_a_l_/_s_h_a_r_e_/_g_r_a_p_/_g_r_a_p_._d_e_f_i_n_e_s SSEEEE AALLSSOO atan2(3), groff(1), pic(1), printf(3), sh(1), sprintf(3), troff(1) If documentation and examples have been installed, ggrraapp ----vveerrssiioonn or ggrraapp ----hheellpp will display the locations. BBUUGGSS There are several small incompatibilities with K&R ggrraapp. They include the sshh command not expanding variables and macros, and a more strict adherence to parameter order in the internal commands. Although much improved, the error reporting code can still be confused. Notably, an error in a macro is not detected until the macro is used, and it produces unusual output in the error message. Iterating many times over a macro with no newlines can run ggrraapp out of memory. AAUUTTHHOORR This implementation was done by Ted Faber . Bruce Lilly contributed many bug fixes, including a considerable revamp of the error reporting code. If you can actually find an error in your ggrraapp code, you can probably thank him. ggrraapp was designed and specified by Brian Kernighan and Jon Bentley. BSD March 11, 2006 BSD grap-1.46/ChangeLog0000664000175000017500000000006713163474043011102 00000000000000See CHANGES (automake barfs if this file isn't around) grap-1.46/CHANGES0000664000175000017500000006135413670047055010333 00000000000000Change log 1.46 Handle multiple label lines correctly (thanks to Bruce Lilly for pointing that out). Be more careful about scaling rand() returns. 1.45 Eric Raymond caught a typo in the grap man page. Various small code changes to remove clang and recent g++ warnings. 1.44 Modern g++ seems to dislike *printf without a constant format string if there are no other aguuments and was causing compiles to fail. Fixed warning and patch from Tobias Quathamer. Manpage spelling fix from Tobias Quathamer. John Heidemann pointed out that plot doesn't accept modifiers to strings (though he didn't phrase it that way). The short form is that plot bullet at x,y wasn't working. I've adjusted plot to make the string modifiers into active keywords, which fixes the problem. Someone named Y T pointed out that there was no mod operator (%). There is now. This marks the transition from my home brewed Makefiles to automake-generated makefiles. A couple largely unused options went away, but with any luck we still build everywhere. Robert Daasch submitted a patch to include floor and ceil fuctions. That's been incorporated. (His patch also included adding a mod operator, but I'd already done that.) Added minimal support for dates, by adding versions of strftime and strptime that return and accept seconds since the unix epoch. 1.43 Bruce Lilly pointed out that g++ 4.3.1 was emitting all sorts of dire warnings about the hash_map data structure and associated support being pulled from g++ in the future. SuSe seems to ship with this and there's no point scaring people (or letting a time bomb tick). Grap now detects and uses unordered_map if it's present on your system, which stops the wailing and gnashing of teeth from g++ 4.3.1 . That g++ version also requires a compiler option to support that include file, which we also autodetect and use. (This is essentially autodetecting the flags described in the changes to grap 1.41 below, along with some code changes to make that actually function correctly.) A fellow named Fergus had a Cygwin compilation problem as well. His system apparently had rand but not random (a very rare configuration these days). This led me to find a corner of the autoconf code that I apparently hadn't checked sufficiently. If rand was found and a declaration made in the system files, the grap config stuff failed to note the declaration and made its own incompatible one. This should be gone now. Fergus's system also seemed to be lacking snprintf - which again is very odd. I hadn't reflected the change to grap sprintf in version 1.23 into the code that emulates snprintf on systems without it. That code has been added. Changed the examples to include a brief tutorial on string matching in grap. Suggested by John Heidemann. 1.42 There's been a long standing bug with how different versions of pic interpret the "line from (x,y) then down 5" construct. There was once a bug report at http://lists.gnu.org/archive/html/groff/2008-03/msg00003.html about this. As of version 1.42 grap no longer outputs this pic construct. Dan Lasley pointed out that the key was incomplete for the bar graph example. His fix to restore the key is included. John Heidemann points out that bars in coordinate systems other than the default just didn't work. This was a bug in my yacc grammer - for heaven's sake. It's corrected to match the manual page. For loops were strange in that .G1 for xx from 15 to 13 do { print "YYY" } print "ZZZZ" .G2 would loop infinitely. xx never passes 13. Added a test to make that a null loop as well as making .G1 for xx from 13 to 13 do { print "YYY" } print "ZZZZ" .G2 print one "YYY". You can still confuse loops, using strange by clauses - for example "by 0" or "by * -1" but common cases should be covered. Spotted by a fellow named Yuval. Found a lurking initializer bug while fixing the for loop thing. I added references to standard plot strings in a couple places to make them somewhat easier to find. 1.41 Small changes to compile without warnings under g++ 4.2.0 and to find and use ext/hash_map under g++ versions that include it. Incorporated Tobias Toedter's patch to the grap.spec. I'd found another place to misspell "Kernighan" and Tobias fixed it. Got rid of an ambiguous else construct in grap_pic.cc Support g++4.3.0 by either compiling under compatibility headers (with a warning) or using the c++0x standard header if you set CXXFLAGS=-std=c++0x CPPFLAGS=-std=c++0x in the environment (during configure and compile). Using unordered_set avoids the warnings, but is experimental. 1.40 Man, here's a weird one, care of Bruce Lilly: in previous versions doing something like this: coord temp x -2,2 y 3,4 ticks left out from temp -1 to 1 would interpret the ticks as starting from the value of the uninitialized variable temp with one subtracted from it to 1 in the default coordinate space rather than (correctly) interpreting that as ticks from -1 to 1 in the temp coordinate space. This is a two character fix to a regular expression, but a weird bug. I believe it's fixed. Bruce also discovered that the changes I put into version 1.38 to address issues raised by Hartmut Henkel affected large number comparisions in unpleasently non-intuitive ways. Specifically doing this: coord pressure x -2.400000, 27.000000 y 1035.124000, 1039.000000 ticks right in left 0.6 from pressure 1035.200 to 1039.000000 by 0.200 Results in the top tick - the one at 1039 - being clipped because the 19 additions in the tick loop introduce enough floating point error that the limit (1039) and the index (1039+epsilon) differ by a large enough value that the loop terminates one iteration early. Essentially the <= at the top of the tick loop fails because the error induced by the 19 additions accumulates to be detectable. I've reverted the default comparison thresholds back to their pre-1.38 levels; numbers must differ by more than 1e-6 to be considered different by grap. For people who explicitly want to work with very small quantities directly - a decision I still disagree with - the -r flag has been added to make grap use the system's idea of what the smallest comparable numbers are (the 1.38 and 1.39 behavior). The output of -v or -h lists these two values and the manual page documents the flags. I've updated the grap.spec to one donated by John Heidemann. Linux guys should have it easier. 1.39 Martin Michlmayr noticed a typo that upsets gcc 4.1, though earlier versions don't even generate a warning (Grrrr). (Original report at .) This is fixed. I didn't issue a new FreeBSD port, because it doesn't change anything functionally. I also cleaned up the man page a bit, and Tobias Toedter fixed a couple typos in the man page and the README file. Always troubling to misspell the inventor's name. 1.38 Michail Vidiassov suggests that a DESTDIR variable be added to the Makefile to allow staged installs or temporary installs or other stuff. Setting DESTDIR when making install or deinstall will create a tree under DESTDIR that contains the full grap install. E.g., make DESTDIR=/usr/tmp install Does something like: /usr/bin/install -c -d /usr/tmp/usr/local/share/doc/grap || true /usr/bin/install -c -m 644 README CHANGES COPYRIGHT grap.man /usr/tmp/usr/local/share/doc/grap strip grap || true /usr/bin/install -c -d /usr/tmp/usr/local/bin || true /usr/bin/install -c -d /usr/tmp/usr/local/man/man1 || true /usr/bin/install -c -d /usr/tmp/usr/local/share/grap || true /usr/bin/install -c -d /usr/tmp/usr/local/share/examples/grap || true /usr/bin/install -c grap /usr/tmp/usr/local/bin /usr/bin/install -c -m 644 grap.1 /usr/tmp/usr/local/man/man1 /usr/bin/install -c -m 644 grap*.defines /usr/tmp/usr/local/share/grap /usr/bin/install -c -m 644 examples/*.d examples/example.ms \ examples/*.result examples/Makefile \ /usr/tmp/usr/local/share/examples/grap There is a possibility of munging the manpage by doing this, but that's actually pretty difficult, and the modifications below to print install locations will still print the original (that is DESTDIR-free) install locations. Warner Lemberg found a bunch of bad typesetting in the examples, and I hope much of that is fixed. He also pointed out that configure should allow installers to place documentation and examples where their system likes them. I've altered the configuration script to accept these locations as --with arguments (--help lists them). grap -v or grap -h (or the long versions: grap --version/grap --help) prints out the examples/documentation locations and that new behavior is documented in the manual page. (The locations aren't directly given in the man page, because the ASCII and postscript versions of the manual are created before the source tar file is so that grap man pages can be installed places that don't have doc manual pages). Fixed a bug where lines acquired the lindescription of the last drawn line. This was a typo level error that just never got exercised. Thanks to Steve Blinkhorn for finding it. Steve also points out that thickness attributes on frames were being ignored. They're not anymore, but they're of limited usefulness and they don't thicken the ticks. The easiest way to draw a thick frame with thick ticks is: .G1 pic linethick=5 frame .\" ticks statement here pic linethick=1 draw solid bullet next at 1,2 next at 3,4 .G2 That draws a thick frame and thin line. I integrated some changes suggested by Hartmut Henkel to better handle graphing small numbers. I didn't include his patch exactly, but I think that most of the functionality has been added. His test cases look the same. If you're graphing things in the 1e-30 range, you should see autoscaling and not have your graph stop at 1e-6, assuming that your compiler has . I really think it's a bad idea to graph in that domain, as the math with numbers that small can be really hairy, and grap isn't exactly tuned for numerical analysis. But I think we do better now. 1.37 Fixed an error handling bug where an error at end of file/line could cause a core dump. Yuk. 1.36 Joel M. Cook pointed out that plot "\(bu" at 0, -306 didn't work. grap was requiring a numeric expression before the format string. I think I've had that discussion before, but I decided to support the behavior this time. Now both the expression and the format string are optional. plot at x,y will plot a 0 at x,y. plot "x" at x,y is exactly equivalent to "x" at x,y in output, but slightly slower. plot 3 at x,y works as before as does plot 2 "%g of clubs" at x,y I also modified the grammar to accept the base and wid paramaters to bar in any order. 1.35 Changes to lex code to compiler under newer versions of lex and configure code to activate them. Several people pointed out the problem and I like Bruce Lilly's solution best. Configure bugs are all mine. Bruce Lilly also noticed that copy statements with a macro and neither an until nor a filename didn't work as they should. He provided the fix for that. Bill Ward pointed out that grap should support gpic's "thickness" just like the color attributes. So now it does. And an apology to R. Clayton who sent patches for this very thing that I lost until after I'd implemented. 1.32: Whoops. Color modifiers were mis parsed in implicit plot statements. Now things like : bullet color "blue" at 1, 3 work. Minor code tweaks to make grap compile under g++ 3.4.2 1.31: In compatibility mode grap will no longer add whitespace around graphs. I like it, but Yuval Tamir rightly complained. 1.30: Made the undocumented color commands support GNU pic color commands. In other words added color to grap. Probably the easiest place to see the syntax is the new example added to the examples file. The changes are on the manual page, too, but the example sets basically everything that can be set, so it's a good example. 1.27: A couple compilation bugs reported under later g++ versions by a couple people have been fixed. Brian Mays caught a clipping bug, and Bruce Lilly also caught a couple compiler dependencies. 1.26: .lf was appearing outside the PS/PE pairs, so I disabled generation of those lines. 1.25: Fixed a bug parsing draw/new with no line descriptions. Thanks to Robert W. Numrich for spotting it. Cygwin seems to need errno.h to declare errno in grap_lex.l. I added the machinery to look for it and use it if it's there. I also added a couple missing semi-colons to grap.y to shut bison up. Added the clipped and unclipped attributes to allow plot statements to place strings outside the frame. Tuned the makefile so you can use pmake in parallel. 1.23: made it possible to disable sprintf and other calls to sprintf(3) with a user given format string, which is a potential security hole. Fixed a plot bug I found while disabling that. 1.22: John Heidemann caught a bug with respect to large sizes and size changes in titles. Those large size changes are now supported. Generally the groff [] syntax is now used for the embedded \s commans that size generates. This can be turned off by using -C. John also wanted to be able to specify string modifiers like size, etc. on ticks. Now ticks, grids, and plot strings (e.g. in a new or draw statement) all take string modifiers. grap.defines has been changed to support and encourage this usage. A bug where a null graph was output when only a draw statement was given has been corrected. sprintf processing has been revamped to more directly follow sprintf syntax. As a result, a limitation on the number of parameters (10) has been introduced. As a result of using string attributes on plotting strings, the name of the default line has become user-visible. Changing grap_internal_default via new will change the default lines for the rest of the graph. It's not encouraged. 1.21: Allow redefinition of keywords as macros. In the process, I added an undefine keyword to do the obvious: remove a macro. Added xy_gg macros, too. Fixed a bug where giving a coordinate name before a parenthesized point caused a syntax error. Thanks to Kees Zeelenberg for spotting this. Added an srand function to seed the random number generator, though there's none documented in Kernighan and Bentley's grap, and a getpid function to get a (sort of) random number. Don't use this for key generation. W. Robert Daasc caught this omission. While I was in there, I discovered that rand was not returning its full range from [0,1). It does now. Some keywords that accept strings weren't accepting sprintf, some of them have been fixed. Lee Ji Hwan found a bug with large files being read thru macros causing a core dump. That has been fixed. It was a really embarrassing coding style error, too... John Aycock discovered a bug where a line style was ignored on the first line command executed. It's not ignored anymore. I also found a bug in the execution order of copy through macros, although I'm uncertain if a version was ever released with the bug intact. I think this may have been related to Lee Ji Hwan's bug, which means it probably hasn't seen the light of day. -h prints a usage summary. --help is a synonym for -h and --version is a synonym for -v. 1.20: The big jump reflects both internal changes and visible feature changes. The class structure in the code has been substantially revamped, and the code brought into better conformance with the current state of the C++ world. As of version 1.20, grap no longer attempts to compile under g++ 2.7.2. grap 1.11 source will remain available from http://www.lunabase.org/~faber/Vault/software/grap for those who need it. One feature change is that troff and pic commands are now placed correctly in their relative order rather than being collected before and after the graph. This required specifying more carefully where the frame generation is placed. Frames are output either immediately before the first plotted object or after the frame statement, if any. This change motivated much of the class changes and actually cleaned them up somewhat. grap is now *much* more tolerant of variables with the keword names. Things like from=1; to = 10 for i from from to to do { ... } now work. This is due to a sizable rewrite of the tokenizer. In fact, variables and coordinate spaces can share names. Things like: for next = 0 to 10 do { next at next next, next } now work (you have to add a couple ticks statements to really see that example). I'd say we're to the point where obfuscated grap programs are a possibility. The only change this necessitated was that if you specify a coordinate system in an automatic ticks statement, you have to use the on or auto keyword. See the examples document for an example. I recoded macros to remove an antiquated construct that was confusing some non-g++ compilers. A static array was recoded as an STL vector, with the result that an artificial constraint on the number of arguments in a macro went away. Part of the recoding of the tokenizer encoded a large data structure in a file called grap_tokenizer.cc. The code is striaght-ahead initialization, but it drives the g++ optimizer stone crazy. (Optimizing this function is very memory intensive.) By default, optimization is specifically disabled under g++. You can override that behavior by specifying --enable-optimize-grap_tokenizer to ./configure. On the machines I use, optimizing this module has absolutely no effect on performance, and I suggest you don't bother spending the time optimizing it. The autoconf and make stuff has been revamped to use GNU make's automatic makefile generation or BSD pmake's automatic .depend inclusion, as well as simplifying the distribution creation and caching all configuration values. Added some GNU standard Makefile targets to the Makefile. Fixed some bugs in the manual page. Ran spell again on the examples. Misspelling Brian Kernighan's name is bad. Many additional compatibility changes suggested by Bruce Lilly. 1.11: Strings are now clipped, thanks to John Heidemann for finding the error. 1.10: Cleaned up the automatic tick generation and fixed a bug in there, too. Allow reassignment of coordinate system parameters, e.g., .G1 coord test copy "examples/cy_fatal.d" coord test x 1980,2000 .G2 Default line format now uses the bullet macro if it's defined. The coord statement now will accept multiple log scale modifiers. The statement coord x 1,1000 log x log y is now legal. x and y are now legal variable names. They used to be language tokens, and in fact still are, although their scope as tokens is now limited to coord statements. Tried to streamline the use of for_each and functors by removing trivial calls to for_each. Still trying to move code out of grap.y to make it shorter to compile. Simplified expression grammar by disallowing logical expressions outside if statements. I also caught another memory leak here. Signifying a line break by using new (or draw) now works. So code like .G1 draw solid next at 2,4 next at 3,5 new next at 4,6 next at 5,7 .G2 produces 2 solid line segments. This forced a little rethinking of the syntax for changing the properties of a line using new/draw. The implementation is on the man page. If it breaks existing grap scripts, I'd love to hear about it. Grids support similar syntax to that of ticks for explicitly requesting automatic grid generation. Automatic tock or grid generation can now be requested relative to a named coordinate system, formerly automatic ticks/grid lines were only generated for the default coordinate system. Added the ln function. Why did that take me so long? Revised and (finally) spell-checked the man page. I also stopped including the auto-generated manual page in an macros. A text version of the man page is now installed, but the manual uses the doc macros exclusively. Line clipping was added in here, too. 1.06: Added an anonymous donor's TeX defines. Also added the -C compatibility option for groff and fixed some manpage formatting bugs. 1.05: kromJx@crosswinds.net noticed that numbers like 1. weren't accepted. They are now. While I was fixing that I noticed that copy until commands without a macro weren't supported. They are now. Made a minor change to the examples to test the fixes. 1.03: Added the -M path option to make groff handle grap better. I also added the GRAP_DEFINES environment variable to change the defines file. I also added a new source file, grap_parse.cc in an attempt to break up the monolithic and gigantic grap.y. I had some small success. In the course of creating grap_parse.cc I think I caught some memory leaks, too. 1.02: Bruce's error handling code produced a few inconsistencies (eating the last newline of a file, and adding one befor ethe file. I think it no longer does that. In addition I took care of a error placement bug when the error was in a line containing a macro expansion, and changed the error handling from using char * to using Strings, like the rest of grap. Got rid of an error on SunOS (and presumably other architectures) where -0 labels were printed on auto-generated labels. Fixed bugs in sprintf when compiled using standard strings. Fixed a memory leak and general bug with the undocumented color commands. (There, that'll tell me if anyone reads this!) 1.01: Fixed a compilation bug under RedHat 6.1. Cleaned up autoconf and tweaked the makefile. 1.0: Incorporated Bruce Lilly's error reporting code. Cleaned up the documents (including a menton for Bruce in the man page) for v1.0 release. Cleared up a file reading bug. 0.98b: Bruce Lilly reported some bugs and DWP incompatibilities, mainly with negative numbers in number lists and comma separations in them. He also compiles in UWIN under NT, which broke autoconf in some weird ways. The most important of these necessitated adding a check to ensure that install supports -d. His test case is in the example file now. He also found some spelling errors. The README file now reflects the real state of the world, too. More kudos to Bruce. While tinkering with those autoconf changes I found that grap didn't compile under g++ 2.7.2.1 any more. Good thing that 0.97b wasn't really released. All is well again. More fun from Bruce: he's given me patches to make cascding assignments work and to remove a bug with comments not acting as separators. I've also make the order of copy commands more flexible (the until can go before or after an inline macro, for example) and fixed a bug in the grammar that made it difficult to put general expressions in places like the frame size. Expressions can go anywhere now, at the expense that string comparisons can only appear in if statements. Those bugs were also spotted by Bruce. 0.97b: Finally have a copy of egcs, so grap will now compile under it using both the stl and the standard string class. What do you know, compiling under egcs halves the run time. This is roughly half due to better egcs compilation and half due to the better performance of the standard string class. Moved to a config.h-style grap.h. Smoothed out the header files to confine as much conditional compilation as possible to grap.h. The code now uses hash_maps if they're available. 0.95b: bug fix: deleting grap_buffer_state contents twice on error, allow more than one shift description on ticks, grids, and labels. Thanks to Anindo Banerjea at ISI for spotting my misimplementation. Another couple of Bannerjea catches: through is now recognized as a synonym for thru. "For," "then" and "else" clauses were previously treated as macros but now have a terminating separator added to them. The result is that things like if (x == 3) { y = y + 1 } x = x + 1 work now. (If the { } is treated as a macro defined and expanded on the spot, the grap parser sees y = y + 1x = x + 1 and cannot parse the expression y+1x). The new behavior is both more intuitive and more in line with previous grap implementations. More from Anindo: expansion of macro arguments assumed that the only possible character following a dollar sign was a single digit. This caused problems both when a non-digit followed and the $ was literal, and when the intent was to access an argument with an index greater than 9. Argument expansion now only expands when a $ is followed by 1 or more digits, and includes all the digits in the index. The frame statement will now accept the default line style before or after the frame size. I still don't accept things like frame ht 3 solid wid 3 - the specifications of the size must be contiguous. 0.92a: bug fix - string equality check. Small change to Makefile.in to support default Solaris behavior. Added -v for version info. Some general internals fiddling (I'd like to call it cleanup, but I think that's generous). 0.91a: small changes for the RPM 0.9a: Added commands for making bars. Error reporting is much closer to the correct line now. Generalized line descriptions for fillable objects. Circles now take a line description. Added new examples of fillable objects. Now using the BSD copyright notice instead of my own half-baked one. 0.8a: alpha release grap-1.46/COPYING0000664000175000017500000000001313163474043010352 00000000000000See README grap-1.46/AUTHORS0000664000175000017500000000002313163474043010370 00000000000000faber@lunabase.org grap-1.46/grap_tokenizer.cc0000664000175000017500000002372213163474043012665 00000000000000/* This code is (c) 1998-2001 Ted Faber see COPYRIGHT for the full copyright and limitations of liabilities. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef STDC_HEADERS #include #include #include #endif #if defined(STDC_HEADERS) | defined(HAVE_STDLIB_H) #include #endif #include #include #include #include "grap.h" #include "grap_data.h" #include "grap_draw.h" #include "y.tab.h" // Keywords recognized in the initial GRAP state (AT, SPRINTF and all // the string modifiers are there for implicit PLOT statements). string gk[] = { "copy", "next", "draw", "new", "line", "define", "arrow", "circle", "plot", "at", "frame", "graph", "coord", "for", "if", "print", "sprintf", "ticks", "tick", "label", "grid", "pic", "sh", "bar", "ljust", "rjust", "above", "below", "aligned", "unaligned", "size", "undefine", "clipped", "unclipped", "color", "strftime" }; // These are the keywords recognized by any keyword that takes a line // descriptor: string lk[] = { "invis", "solid", "dotted", "dashed", "fill", "fillcolor", "color", "thickness" }; // Keywords recognized for sting modifiers string sk[] = { "ljust", "rjust", "above", "below", "aligned", "unaligned", "size", "clipped", "unclipped", "color" }; // Keywords recognized by ticks and graph string tk[] = { "left", "right", "up", "down", "bottom", "bot", "top", "in", "out", "from", "to", "by", "at", "off", "on", "auto", "sprintf", "color", "strftime" }; // Vector versions of these vector grap_keys(gk, gk+sizeof(gk)/sizeof(string)); vector linedesc_keys(lk, lk+sizeof(lk)/sizeof(string)); vector strmod_keys(sk, sk+sizeof(sk)/sizeof(string)); vector tick_keys(tk, tk+sizeof(tk)/sizeof(string)); // The data structure encapsulating the keyword handling algorithms keywordDictionary keywords; // This builds a large hash table encapsulating the actions to take // when a keyword is parsed. This is one big static data structure, // and should just be statically initialized, but is complex enough // that building it is easier to maintain. It's split into // subfunctions primarily because the gcc optimizer has a terrible // time with the one big function, and partially to make it easier to // maintain. // All these can appear multiple times in a command void init_multiples() { vector empty; keywords["above"] = keyword(empty, empty, false, ABOVE); keywords["top"] = keyword(empty, empty, false, TOP); keywords["bot"] = keywords["bottom"] = keyword(empty, empty, false, BOTTOM); keywords["left"] = keyword(empty, empty, false, LEFT); keywords["right"] = keyword(empty, empty, false, RIGHT); keywords["up"] = keyword(empty, empty, false, UP); keywords["down"] = keyword(empty, empty, false, DOWN); keywords["ljust"] = keyword(empty, empty, false, LJUST); keywords["rjust"] = keyword(empty, empty, false, RJUST); keywords["below"] = keyword(empty, empty, false, BELOW); keywords["aligned"] = keyword(empty, empty, false, ALIGNED); keywords["unaligned"] = keyword(empty, empty, false, UNALIGNED); keywords["clipped"] = keyword(empty, empty, false, CLIPPED); keywords["unclipped"] = keyword(empty, empty, false, UNCLIPPED); keywords["size"] = keyword(empty, empty, false, SIZE); keywords["in"] = keyword(empty, empty, false, IN); keywords["out"] = keyword(empty, empty, false, OUT); keywords["off"] = keyword(empty, empty, false, OFF); keywords["on"] = keywords["auto"] = keyword(empty, empty, false, ON); keywords["fill"] = keyword(empty, empty, false, FILL); keywords["invis"] = keyword(empty, empty, false, INVIS); keywords["solid"] = keyword(empty, empty, false, SOLID); keywords["dotted"] = keyword(empty, empty, false, DOTTED); keywords["dashed"] = keyword(empty, empty, false, DASHED); keywords["fillcolor"] = keyword(empty, empty, false, FILLCOLOR); keywords["color"] = keyword(empty, empty, false, COLOR); keywords["thickness"] = keyword(empty, empty, false, THICKNESS); keywords["sprintf"] = keyword(empty, empty, false, SPRINTF); keywords["strftime"] = keyword(empty, empty, false, STRFTIME); } // These are all one time command modifiers void init_only_once() { vector empty; vector temp; // temp.clear(); temp.push_back("radius"); temp.push_back("rad"); keywords["radius"] = keywords["rad"] = keyword(empty, temp, false, RADIUS); temp.clear(); temp.push_back("from"); keywords["from"] = keyword(empty, temp, false, FROM); temp.clear(); temp.push_back("thru"); temp.push_back("through"); keywords["thru"] = keywords["through"] = keyword(empty, temp, false, THRU); temp.clear(); temp.push_back("to"); keywords["to"] = keyword(empty, temp, false, TO); temp.clear(); temp.push_back("by"); keywords["by"] = keyword(empty, temp, false, BY); temp.clear(); temp.push_back("until"); keywords["until"] = keyword(empty, temp, false, UNTIL); temp.clear(); temp.push_back("do"); keywords["do"] = keyword(empty, temp, false, DO); temp.clear(); temp.push_back("x"); keywords["x"] = keyword(empty, temp, false, XDIM); temp.clear(); temp.push_back("y"); keywords["y"] = keyword(empty, temp, false, YDIM); temp.clear(); temp.push_back("base"); keywords["base"] = keyword(empty, temp, false, BASE); temp.clear(); temp.push_back("ht"); keywords["ht"] = keyword(empty, temp, false, HT); temp.clear(); temp.push_back("wid"); keywords["wid"] = keyword(empty, temp, false, WID); temp.clear(); temp.push_back("at"); temp.insert(temp.end(), strmod_keys.begin(), strmod_keys.end()); keywords["plot"] = keyword(temp, empty, true, PLOT); } // These all signal the start of a command void init_line_starters() { vector empty; vector temp; temp.clear(); temp.push_back("thru"); temp.push_back("through"); temp.push_back("until"); keywords["copy"] = keyword(temp, empty, true, COPY); temp = linedesc_keys; temp.push_back("at"); temp.push_back("sprintf"); temp.push_back("strftime"); keywords["next"] = keyword(temp, empty, true, NEXT); temp = linedesc_keys; temp.insert(temp.end(), strmod_keys.begin(), strmod_keys.end()); temp.push_back("sprintf"); temp.push_back("strftime"); keywords["draw"] = keywords["new"] = keyword(temp, empty, true, DRAW); temp = linedesc_keys; temp.push_back("from"); temp.push_back("to"); keywords["line"] = keyword(temp, empty, true, LINE); temp = linedesc_keys; temp.push_back("from"); temp.push_back("to"); keywords["arrow"] = keyword(temp, empty, true, ARROW); temp = linedesc_keys; temp.push_back("at"); temp.push_back("radius"); temp.push_back("rad"); keywords["circle"] = keyword(temp, empty, true, CIRCLE); temp = linedesc_keys; temp.push_back("top"); temp.push_back("bottom"); temp.push_back("bot"); temp.push_back("left"); temp.push_back("right"); temp.push_back("ht"); temp.push_back("wid"); keywords["frame"] = keyword(temp, empty, true, FRAME); temp.clear(); temp.push_back("x"); temp.push_back("y"); temp.push_back("log"); keywords["coord"] = keyword(temp, empty, true, COORD); temp.clear(); temp.push_back("from"); temp.push_back("to"); temp.push_back("by"); temp.push_back("do"); keywords["for"] = keyword(temp, empty, true, FOR); temp.clear(); temp.push_back("then"); keywords["if"] = keyword(temp, empty, true, IF); temp.clear(); temp.push_back("else"); keywords["then"] = keyword(temp, empty, true, THEN); temp = tick_keys; temp.insert(temp.end(), strmod_keys.begin(), strmod_keys.end()); keywords["tick"] = keywords["ticks"] = keyword(temp, empty, true, TICKS); temp = strmod_keys; temp.push_back("left"); temp.push_back("right"); temp.push_back("up"); temp.push_back("down"); temp.push_back("bottom"); temp.push_back("bot"); temp.push_back("top"); temp.push_back("sprintf"); temp.push_back("strftime"); keywords["label"] = keyword(temp, empty, true, LABEL); temp = linedesc_keys; temp.insert(temp.end(), tick_keys.begin(), tick_keys.end()); temp.insert(temp.end(), strmod_keys.begin(), strmod_keys.end()); temp.push_back("ticks"); temp.push_back("tick"); keywords["grid"] = keyword(temp, empty, true, GRID); temp = linedesc_keys; temp.push_back("ht"); temp.push_back("wid"); temp.push_back("up"); temp.push_back("right"); temp.push_back("base"); keywords["bar"] = keyword(temp, empty, true, BAR); } // These have special parsing rules. They clear the active commands. void init_wipers() { vector empty; keywords["define"] = keyword(empty, empty, true, DEFINE); keywords["undefine"] = keyword(empty, empty, true, UNDEFINE); keywords["graph"] = keyword(empty, empty, true, GRAPH); keywords["else"] = keyword(empty, empty, true, ELSE); keywords["print"] = keyword(empty, empty, true, PRINT); keywords["pic"] = keyword(empty, empty, true, PIC); keywords["sh"] = keyword(empty, empty, true, SH); } // This are used in parsing multi-element matches for macros. bool id_letter[256]; // set up the table to scan for embedded macros void init_id() { int i; // Scratch for (i = 0; i < 256; i++ ) id_letter[i] = false; // assumes letters are contiugous. Is there still any character set // for this which doesn't hold? for ( i = 'a'; i <= 'z' ; i++ ) id_letter[i] = true; for ( i = 'A'; i <= 'Z' ; i++ ) id_letter[i] = true; for ( i = '0'; i <= '9' ; i++ ) id_letter[i] = true; id_letter[static_cast('_')] = true; } // Initialize the table of keywords. void init_keywords() { vector empty; init_multiples(); init_only_once(); init_line_starters(); init_wipers(); // init the table init_id(); } grap-1.46/strdup.cc0000664000175000017500000000045313163474043011157 00000000000000#ifdef STDC_HEADERS #include #endif extern "C" { void * malloc(size_t size); }; char *strdup(const char *s) { int len = strlen(s)+1; char *t; int i; if ( !(t = (char *) malloc(len)) ) return 0; else for ( i = 0; i < len; i++ ) t[i] = s[i]; return t; } grap-1.46/grap_string.h0000664000175000017500000001054513163474043012022 00000000000000#ifndef GRAP_STRING_H #define GRAP_STRING_H // These should be replaced by the standard string library, but under // g++ 2.7.2.1 that library is incompatible with the STL static const int strchunk = 256; class String { public: typedef size_t size_type; static const size_type npos = ~0; String() : str(0), len(0) { } String(const char *c) : str(0), len(0) { resize(::strlen(c)+1); strcpy(str,c); }; String(const int i) : str(0), len(0) { resize(strchunk); snprintf(str,len,"%d",i); }; String(const double d, const String *fmt = 0) : str(0), len(0) { resize(strchunk); if ( fmt ) snprintf(str,len,fmt->str,d); else snprintf(str,len,"%g",d); }; String(const String* x) : str(0), len(0) { resize(x->len); if ( len ) strcpy(str,x->str); }; String(const String& x) : str(0), len(0) { resize(x.len); if ( len) strcpy(str,x.str); }; ~String() { if ( str) { delete str; str = 0; } len = 0; }; char& operator[](const int i) { if ( i < len ) return str[i]; else { resize(i+1); return str[i]; } }; String& operator=(const String &s) { if ( len < s.len) resize(s.len); if ( len )strcpy(str,s.str); return *this; }; String& operator+=(const String& s) { int nlen = s.strlen() + strlen()+ 1; if ( len < nlen ) resize(nlen); if ( len ) strcat(str,s.str); return *this; } String& operator+=(const char *s) { int nlen = ::strlen(s) + strlen() + 1; if ( len < nlen ) resize(nlen); if ( len ) strcat(str,s); return *this; } String& operator+=(const char c) { int last = strlen(); if ( len < last +2 ) resize(last+2); last=strlen(); str[last] = c; str[last+1] = '\0'; return *this; } String operator+(const String& s) { String rc = *this; rc+= s; return rc; } String operator+(const char *c) { String rc = *this; rc+= c; return rc; } size_type find(char c) const { size_type len = length(); for ( size_type i = 0; i < len; i++ ) if ( str[i] == c ) return i; return npos; } void erase(size_type start, size_type end) { size_type lim = length(); if ( end == npos ) end = lim-1; if ( len ) { strcpy(str+start,str+end); str[(lim-1)-end-start] = '\0'; } } int operator==(const String &s) const { return !strcmp(str,s.str); } int operator<(const String &s) const { return ( strcmp(str,s.str) < 0) ; } int operator==(const char *s) const { return !strcmp(str,s); } int operator!=(const String &s) const { return strcmp(str,s.str); } int operator!=(const char *s) const { return strcmp(str,s); } int operator<(String& s) { return strcmp(str,s.str) < 0; } void quote() { int l; if ( len < strlen()+3 ) resize(len+3); for ( int i = len-1; i >=1; i-- ) str[i] = str[i-1]; l = strlen(); if ( l == 0 ) l = 1; str[0] = '"'; str[l] = '"'; str[l+1] = '\0'; } void unquote() { int i; if ( str[0] == '"' ) { for ( i = 0; i < len-2; i++ ) str[i] = str[i+1]; str[strlen()-1] = '\0'; } i = strlen(); if ( str[i-1] == '"' ) str[i-1] = '\0'; } void strncpy(char *s, int l) { ::strncpy(s,str,l); } int strlen() const { return ( (str) ? ::strlen(str) : 0 ); } const char *c_str() const { return str;} int length() const { return strlen();} ostream& print(ostream& f) const { return f << str; } String substr(int i, int n=0) { String s; s.resize(strlen()); if ( n == 0 || n > strlen()-i ) n = strlen() - i; for ( int j = 0; j < n; j++ ) s.str[j] = str[i+j]; s.str[n] = '\0'; return s; } protected: char *str; int len; void resize(int ns) { char *c; int s; s =( ns/strchunk + (( ns % strchunk ) ? 1 : 0 )) * strchunk; c = new char[s]; if ( len ) for ( int j = 0; j < len; j++) c[j] = str[j]; else c[0] = '\0'; if ( str ) delete str; str = c; len = s; } }; inline ostream& operator<<(ostream& f, const String& s) { return s.print(f); } // These functions and classes are all duplicated for standard strings // in grap_data.h. The choice is to either support 2 versions of // these functions or to make the emulation of standard strings better // and support that. Because this code was already written, I chose // this. inline void unquote(String *s) { s->unquote(); } inline void quote(String *s) { s->quote(); } #endif grap-1.46/INSTALL0000664000175000017500000000001313163474043010350 00000000000000See README grap-1.46/missing0000755000175000017500000001533013256032133010715 00000000000000#! /bin/sh # Common wrapper for a few potentially missing GNU programs. scriptversion=2013-10-28.13; # UTC # Copyright (C) 1996-2014 Free Software Foundation, Inc. # Originally written by Fran,cois Pinard , 1996. # This program 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 2, or (at your option) # any later version. # This program 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 . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try '$0 --help' for more information" exit 1 fi case $1 in --is-lightweight) # Used by our autoconf macros to check whether the available missing # script is modern enough. exit 0 ;; --run) # Back-compat with the calling convention used by older automake. shift ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due to PROGRAM being missing or too old. Options: -h, --help display this help and exit -v, --version output version information and exit Supported PROGRAM values: aclocal autoconf autoheader autom4te automake makeinfo bison yacc flex lex help2man Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and 'g' are ignored when checking the name. Send bug reports to ." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit $? ;; -*) echo 1>&2 "$0: unknown '$1' option" echo 1>&2 "Try '$0 --help' for more information" exit 1 ;; esac # Run the given program, remember its exit status. "$@"; st=$? # If it succeeded, we are done. test $st -eq 0 && exit 0 # Also exit now if we it failed (or wasn't found), and '--version' was # passed; such an option is passed most likely to detect whether the # program is present and works. case $2 in --version|--help) exit $st;; esac # Exit code 63 means version mismatch. This often happens when the user # tries to use an ancient version of a tool on a file that requires a # minimum version. if test $st -eq 63; then msg="probably too old" elif test $st -eq 127; then # Program was missing. msg="missing on your system" else # Program was found and executed, but failed. Give up. exit $st fi perl_URL=http://www.perl.org/ flex_URL=http://flex.sourceforge.net/ gnu_software_URL=http://www.gnu.org/software program_details () { case $1 in aclocal|automake) echo "The '$1' program is part of the GNU Automake package:" echo "<$gnu_software_URL/automake>" echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/autoconf>" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; autoconf|autom4te|autoheader) echo "The '$1' program is part of the GNU Autoconf package:" echo "<$gnu_software_URL/autoconf/>" echo "It also requires GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; esac } give_advice () { # Normalize program name to check for. normalized_program=`echo "$1" | sed ' s/^gnu-//; t s/^gnu//; t s/^g//; t'` printf '%s\n' "'$1' is $msg." configure_deps="'configure.ac' or m4 files included by 'configure.ac'" case $normalized_program in autoconf*) echo "You should only need it if you modified 'configure.ac'," echo "or m4 files included by it." program_details 'autoconf' ;; autoheader*) echo "You should only need it if you modified 'acconfig.h' or" echo "$configure_deps." program_details 'autoheader' ;; automake*) echo "You should only need it if you modified 'Makefile.am' or" echo "$configure_deps." program_details 'automake' ;; aclocal*) echo "You should only need it if you modified 'acinclude.m4' or" echo "$configure_deps." program_details 'aclocal' ;; autom4te*) echo "You might have modified some maintainer files that require" echo "the 'autom4te' program to be rebuilt." program_details 'autom4te' ;; bison*|yacc*) echo "You should only need it if you modified a '.y' file." echo "You may want to install the GNU Bison package:" echo "<$gnu_software_URL/bison/>" ;; lex*|flex*) echo "You should only need it if you modified a '.l' file." echo "You may want to install the Fast Lexical Analyzer package:" echo "<$flex_URL>" ;; help2man*) echo "You should only need it if you modified a dependency" \ "of a man page." echo "You may want to install the GNU Help2man package:" echo "<$gnu_software_URL/help2man/>" ;; makeinfo*) echo "You should only need it if you modified a '.texi' file, or" echo "any other file indirectly affecting the aspect of the manual." echo "You might want to install the Texinfo package:" echo "<$gnu_software_URL/texinfo/>" echo "The spurious makeinfo call might also be the consequence of" echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" echo "want to install GNU make:" echo "<$gnu_software_URL/make/>" ;; *) echo "You might have modified some files without having the proper" echo "tools for further handling them. Check the 'README' file, it" echo "often tells you about the needed prerequisites for installing" echo "this package. You may also peek at any GNU archive site, in" echo "case some other package contains this missing '$1' program." ;; esac } give_advice "$1" | sed -e '1s/^/WARNING: /' \ -e '2,$s/^/ /' >&2 # Propagate the correct exit status (expected to be 127 for a program # not found, 63 for a program that failed due to version mismatch). exit $st # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: grap-1.46/grap_draw.h0000664000175000017500000005072313670046006011450 00000000000000// -*-c++-*- #ifndef GRAP_DRAW_H #define GRAP_DRAW_H // This file is (c) 1998-2001 Ted Faber (faber@lunabase.org) see COPYRIGHT // for the full copyright and limitations of liabilities. // Names for the sides of graphs (_side because of globals left(), right()) typedef enum { top_side=0, bottom_side ,left_side, right_side} sides; // Styles of drawing lines typedef enum { solid, dotted, dashed, invis, def } linetype; // The axes of graphs typedef enum { none = 0, x_axis = 1, y_axis = 2, both=3} axis; // Justifications for strings, powers of two so we con combine them typedef enum { ljust = 1, rjust = 2, above = 4, below = 8, aligned = 16, unaligned=32} just; typedef struct { axis which; double min; double max; } axisdesc; typedef struct { double size; int rel; int just; bool clip; string *color; } strmod; class linedesc { // Basic class features for line descriptions: constructors, // destructor, and assignment public: linetype ld; // The basic style double param; // Some styles have parameters e.g., dotted 0.3 double fill; // Used for drawing solids, e.g. box string *color; // The name of a color for the line string *fillcolor ; // The color to fill a solid double thick; // Linethickness linedesc(linetype l=def, double p=0, string *c=0, double f=0, string *fc=0, double ft=0) : ld(l), param(p), fill(f), color(0), fillcolor(0), thick(ft) { if ( c ) color = new string(*c); if ( fc ) fillcolor = new string(*fc); } linedesc(const linedesc *l) { if ( l) { ld = l->ld; param = l->param; fill = l->fill; thick = l->thick; if ( l->color ) color = new string(*l->color); else color = 0; if ( l->fillcolor ) fillcolor = new string(*l->fillcolor); else fillcolor = 0; } else { ld = def; param = 0; color = 0; fillcolor = 0; fill = 0; thick = 0; } } linedesc(const linedesc& ldc) : ld(ldc.ld), param(ldc.param), fill(ldc.fill), color(0), fillcolor(0), thick(ldc.thick) { if ( ldc.color ) color = new string(*ldc.color); if ( ldc.fillcolor ) fillcolor = new string(*ldc.fillcolor); } // Make a new linedescriptor that combines the properites in ld1 and // ld2. linedesc(const linedesc* ld1, const linedesc* ld2) : ld(def), param(0), fill(0), color(0), fillcolor(0), thick(0) { if ( ld1 ) *this = *ld1; if ( ld2 && ld2->ld != def ) { ld = ld2->ld; param = ld2->param; } if ( (thick == 0) && ld2 && ld2->thick ) thick = ld2->thick; if ( ld2 && ld2->color ) color = new string(*ld2->color); } ~linedesc() { if ( color ) { delete color; color = 0; } if ( fillcolor ) { delete fillcolor; fillcolor = 0; } } linedesc& operator=(const linedesc &l) { ld = l.ld; param= l.param; fill = l.fill; thick = l.thick; if ( color ) { delete color; color = 0;} if ( l.color ) color = new string(*l.color); if ( fillcolor ) { delete fillcolor; fillcolor = 0;} if ( l.fillcolor ) fillcolor = new string(*l.fillcolor); return *this; } } ; class shiftdesc { // Basic class features for shift descriptions: constructors, // destructor, and assignment public: sides dir; // Direction to shift this label double param; // Amount to shift shiftdesc(sides s=top_side, double p=0) : dir(s), param(p) { } shiftdesc(const shiftdesc *sh ) { if ( sh ) { dir = sh->dir; param = sh->param; } else { dir = top_side; param = 0; } } }; // This functor copies one shiftlist into another, making copies of // each shiftdesc on the list. It's used by various objects that have // shiftlists in them. Each element is inserted at the back class shiftcpy : public unary_function { protected: shiftlist *s; // The new shiftlist public: shiftcpy(shiftlist *ss) : s(ss) { } int operator() (shiftdesc *sd) { shiftdesc *sd2 = new shiftdesc(sd); s->push_back(sd2); return 1; } }; class frame; // An abstract class that means that an object is drawable, and // priovides a method with which to draw itself. Drawing is always // relative to a frame. Because drawable classes are managed by the // graph structure, drawable also supplies a smart allocation system. class drawable { public: virtual void draw(frame *) = 0; // So we get the right size to delete (ick) virtual ~drawable() { } }; typedef list objlist; class DisplayString : public string { // These are primarily used to keep track of the extended string // info. A drawable class is derived to display them. public: int j; // justification modifiers (should be just, // but int supports | and & double size; // Fontsize int relsz; // True if the fontsize is relative bool clip; // True if the string can only appear in the frame string *color; // color of the string DisplayString() : string(), j(none), size(0), relsz(0), clip(true), color(0) { } DisplayString(const char *s, int ju=0, double sz=0, int rsz=0, bool c=true, string *col=0) : string(s), j(ju), size(sz), relsz(rsz), clip(c), color(col) { } DisplayString(string s, int ju=0, double sz=0, int rsz=0, bool c=true, string *col=0) : string(s), j(ju), size(sz), relsz(rsz), clip(c), color(col) { } DisplayString(const DisplayString& ds) : string(ds), j(ds.j), size(ds.size), relsz(ds.relsz), clip(ds.clip), color(ds.color) { if ( color ) color = new string(*color); } DisplayString(double e, const DisplayString *fmt=0) : j(0), size(0), relsz(0), clip(true), color(0) { char *c = new char[64]; bool delf = false; if ( !fmt) { fmt = new DisplayString("%g"); delf = true; } snprintf(c,64,fmt->c_str(),e); // *this = c; assign(c); delete[] c; if ( delf ) delete fmt; else { j = fmt->j; size = fmt->size; relsz = fmt->relsz; clip = fmt->clip; if ( fmt->color ) color = new string(*fmt->color); else color = 0; } } ~DisplayString() { delete color; } }; // A grap coordinate system class coord { public: coord() : xmin(0), xmax(0),ymin(0), ymax(0), logscale(none), xautoscale(1), yautoscale(1), name() { } coord(const string& s) : xmin(0), xmax(0),ymin(0), ymax(0), logscale(none), xautoscale(1), yautoscale(1), name(s) { } coord(axis ls) : xmin(0), xmax(0),ymin(0), ymax(0), logscale(ls), xautoscale(1), yautoscale(1), name() { } coord(axis ls, const string& s) : xmin(0), xmax(0),ymin(0), ymax(0), logscale(ls), xautoscale(1), yautoscale(1), name(s) { } coord(double xi, double xa, double yi, double ya, axis ls) : xmin(xi), xmax(xa),ymin(yi), ymax(ya),logscale(ls), xautoscale(0), yautoscale(0), name() { } coord(double xi, double xa, double yi, double ya, axis ls, const string& s) : xmin(xi), xmax(xa),ymin(yi), ymax(ya),logscale(ls), xautoscale(0), yautoscale(0), name(s) { } coord(const coord& c) : xmin(c.xmin), xmax(c.xmax), ymin(c.ymin), ymax(c.ymax), logscale(c.logscale), xautoscale(c.xautoscale), yautoscale(c.yautoscale), name(c.name) { } double xmin, xmax; // x range double ymin, ymax; // y range axis logscale; // The axes that are logarithmic int xautoscale; // True if the user has not given an explicit x range int yautoscale; // True if the user has not given an explicit y range string name; // Name of the coordinate system, if any void newpt(double x, double y) { newx(x); newy(y); } void newx(double); void newy(double); // Add a margin to the system (0.07 is 7%) handles log scales void addmargin(double); // Convert to [0,1] double map(double, axis); }; class tick { public: double where; // x or y value of the tick double size; // how large a tick mark to make sides side; // Which side of the graph the mark is on DisplayString *prt; // The string to print next to the mark shiftlist shift; // Shift information, to fine tune position of prt coord *c; // The coordinate scale that the tick is in tick() : where(0), size(0), side(top_side), prt(0), shift(), c(0) { } tick(const tick& t) : where(t.where), size(t.size), side(t.side), shift(), c(t.c) { shiftcpy sc(&shift); if ( t.prt ) prt = new DisplayString(*t.prt); else prt =0; for_each(t.shift.begin(), t.shift.end(), sc); } tick(double w, double s, sides sd, DisplayString *p, shiftlist *sh, coord *co) : where(w), size(s), side(sd), shift(), c(co) { shiftcpy sc(&shift); if ( p ) prt = new DisplayString(*p); else prt =0; if ( sh ) for_each(sh->begin(), sh->end(), sc); } ~tick() { shiftdesc *s; if ( prt) { delete prt; prt = 0; } while ( !shift.empty() ) { s = shift.front(); shift.pop_front(); delete s; } } // Important safety tip: Don't byte-copy string pointers. tick& operator=(const tick& t) { shiftcpy sc(&shift); where = t.where; size = t.size; side = t.side; shift = t.shift; c = t.c; if ( prt ) { delete prt; } if ( t.prt ) prt = new DisplayString(*t.prt); else prt = 0; for_each(t.shift.begin(), t.shift.end(), sc); return *this; } }; class grid { public: double where; // x or y value of the grid line linedesc desc; // style of the grid line sides side; // Side of the graph where line labels are printed DisplayString *prt; // The label for this line shiftlist shift; // Shift info for the label coord *c; // Coordinate system for this line grid() : where(0), desc(dotted,0,0), side(top_side), prt(0), shift(), c(0) { } grid(double w, linedesc *l, sides sd, DisplayString *p, shiftlist *sh, coord *co) : where(w), desc(l), side(sd), prt(0), shift(), c(co) { shiftcpy sc(&shift); if ( p ) prt = new DisplayString(*p); if ( sh ) for_each(sh->begin(), sh->end(), sc); } // To allow ticks and grids to share parse rules grid(const tick *t) : where(t->where), desc(dotted,0,0), side(t->side), prt(0), shift(), c(t->c) { shiftcpy sc(&shift); if ( t->prt ) prt = new DisplayString(*t->prt); for_each(t->shift.begin(), t->shift.end(), sc); } grid(const grid& g) : where(g.where), desc(g.desc), side(g.side), prt(0), shift(), c(g.c) { shiftcpy sc(&shift); if ( g.prt ) prt = new DisplayString(*g.prt); for_each(g.shift.begin(), g.shift.end(), sc); } ~grid() { shiftdesc *s; if ( prt ) { delete prt; prt = 0; } while ( !shift.empty() ) { s = shift.front(); shift.pop_front(); delete s; } } // Important safety tip: Don't byte-copy string pointers. grid& operator=(const grid& g) { shiftcpy sc(&shift); where = g.where; desc = g.desc; side = g.side; shift = g.shift; c = g.c; if ( prt ) delete prt; if ( g.prt ) prt = new DisplayString(*g.prt); else prt = 0; for_each(g.shift.begin(), g.shift.end(), sc); return *this; } }; class point { public: double x,y; // Point coordinates coord *c; // system the coordinates are in point() : x(0), y(0), c(0) {} point(double xx, double yy, coord* cc) : x(xx), y(yy), c(cc) { if ( c ) c->newpt(x, y); } point(const point *p) : x(p->x), y(p->y), c(p->c) { if ( c ) c->newpt(x, y); } point(const point& p) : x(p.x), y(p.x), c(p.c) { } point& operator=(point &p) { x = p.x; y = p.y; c = p.c; return *this; } }; class label { public: stringlist *strs; shiftlist *shifts; label(): strs(new stringlist), shifts(new shiftlist) { } label(stringlist *st, shiftlist *sl) : strs(st), shifts(sl) { } ~label() { if ( strs ) { stringlist::iterator s; for (s = strs->begin(); s != strs->end(); s++) delete (*s); strs->erase(strs->begin(), strs->end()); delete strs; strs=0; } if ( shifts ) { shiftlist::iterator s; for (s = shifts->begin(); s != shifts->end(); s++) delete (*s); shifts->erase(shifts->begin(), shifts->end()); delete shifts; shifts=0; } } }; typedef list