graph.c 55 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718
  1. /* This file is part of the GNU plotutils package. Copyright (C) 1989,
  2. 1990, 1991, 1995, 1996, 1997, 1998, 1999, 2000, 2005, 2008, 2009, Free
  3. Software Foundation, Inc.
  4. The GNU plotutils package is free software. You may redistribute it
  5. and/or modify it under the terms of the GNU General Public License as
  6. published by the Free Software foundation; either version 2, or (at your
  7. option) any later version.
  8. The GNU plotutils package is distributed in the hope that it will be
  9. useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License along
  13. with the GNU plotutils package; see the file COPYING. If not, write to
  14. the Free Software Foundation, Inc., 51 Franklin St., Fifth Floor,
  15. Boston, MA 02110-1301, USA. */
  16. /* This file contains the main routine, and a few support subroutines, for
  17. GNU graph. */
  18. #include "sys-defines.h"
  19. #include "extern.h"
  20. #include "libcommon.h"
  21. #include "getopt.h"
  22. #include "fontlist.h"
  23. /* options */
  24. #define ARG_NONE 0
  25. #define ARG_REQUIRED 1
  26. #define ARG_OPTIONAL 2
  27. const char *optstring = "-BCHOQVstE:F:f:g:h:k:K:I:l:L:m:N:q:R:r:T:u:w:W:c:X:Y:a::x::y::S::"; /* initial hyphen requests no reordering */
  28. struct option long_options[] =
  29. {
  30. /* The most important option ("--display-type" is an obsolete variant) */
  31. { "output-format", ARG_REQUIRED, NULL, 'T'},
  32. { "display-type", ARG_REQUIRED, NULL, 'T' << 8 }, /* hidden */
  33. /* Other frequently used options */
  34. {"auto-abscissa", ARG_OPTIONAL, NULL, 'a'}, /* 0 or 1 or 2 */
  35. {"clip-mode", ARG_REQUIRED, NULL, 'K'},
  36. {"fill-fraction", ARG_REQUIRED, NULL, 'q'},
  37. {"font-name", ARG_REQUIRED, NULL, 'F'},
  38. {"font-size", ARG_REQUIRED, NULL, 'f'},
  39. {"grid-style", ARG_REQUIRED, NULL, 'g'},
  40. {"height-of-plot", ARG_REQUIRED, NULL, 'h'},
  41. {"input-format", ARG_REQUIRED, NULL, 'I'},
  42. {"line-mode", ARG_REQUIRED, NULL, 'm'},
  43. {"line-width", ARG_REQUIRED, NULL, 'W'},
  44. {"line-color", ARG_REQUIRED, NULL, 'c'},
  45. {"right-shift", ARG_REQUIRED, NULL, 'r'},
  46. {"save-screen", ARG_NONE, NULL, 's'},
  47. {"symbol", ARG_OPTIONAL, NULL, 'S'}, /* 0 or 1 or 2 */
  48. {"tick-size", ARG_REQUIRED, NULL, 'k'},
  49. {"toggle-auto-bump", ARG_NONE, NULL, 'B'},
  50. {"toggle-axis-end", ARG_REQUIRED, NULL, 'E'},
  51. {"toggle-frame-on-top", ARG_NONE, NULL, 'H'},
  52. {"toggle-log-axis", ARG_REQUIRED, NULL, 'l'},
  53. {"toggle-no-ticks", ARG_REQUIRED, NULL, 'N'},
  54. {"toggle-rotate-y-label", ARG_NONE, NULL, 'Q'},
  55. {"toggle-round-to-next-tick", ARG_REQUIRED, NULL, 'R'},
  56. {"toggle-transpose-axes", ARG_NONE, NULL, 't'},
  57. {"toggle-use-color", ARG_NONE, NULL, 'C'},
  58. {"top-label", ARG_REQUIRED, NULL, 'L'},
  59. {"upward-shift", ARG_REQUIRED, NULL, 'u'},
  60. {"width-of-plot", ARG_REQUIRED, NULL, 'w'},
  61. {"x-label", ARG_REQUIRED, NULL, 'X'},
  62. {"x-limits", ARG_OPTIONAL, NULL, 'x'}, /* 0, 1, 2, or 3 */
  63. {"y-label", ARG_REQUIRED, NULL, 'Y'},
  64. {"y-limits", ARG_OPTIONAL, NULL, 'y'}, /* 0, 1, 2, or 3 */
  65. /* Long options with no equivalent short option alias */
  66. {"bg-color", ARG_REQUIRED, NULL, 'q' << 8},
  67. {"bitmap-size", ARG_REQUIRED, NULL, 'B' << 8},
  68. {"blankout", ARG_REQUIRED, NULL, 'b' << 8},
  69. {"emulate-color", ARG_REQUIRED, NULL, 'e' << 8},
  70. {"frame-line-width", ARG_REQUIRED, NULL, 'W' << 8},
  71. {"frame-color", ARG_REQUIRED, NULL, 'C' << 8},
  72. {"max-line-length", ARG_REQUIRED, NULL, 'M' << 8},
  73. {"pen-colors", ARG_REQUIRED, NULL, 'p' << 8},
  74. {"reposition", ARG_REQUIRED, NULL, 'R' << 8}, /* 3 */
  75. {"rotation", ARG_REQUIRED, NULL, 'r' << 8},
  76. {"symbol-font-name", ARG_REQUIRED, NULL, 'G' << 8},
  77. {"title-font-name", ARG_REQUIRED, NULL, 'Z' << 8},
  78. {"title-font-size", ARG_REQUIRED, NULL, 'F' << 8},
  79. {"legend", ARG_REQUIRED, NULL, 'L' << 8},
  80. {"place-legend", ARG_REQUIRED, NULL, 'O' << 8},
  81. {"legend-font-size", ARG_REQUIRED, NULL, 'Q' << 8},
  82. {"page-size", ARG_REQUIRED, NULL, 'P' << 8},
  83. /* Options relevant only to raw graph (refers to plot(5) output) */
  84. {"portable-output", ARG_NONE, NULL, 'O'},
  85. /* Documentation options */
  86. {"help-fonts", ARG_NONE, NULL, 'f' << 8},
  87. {"list-fonts", ARG_NONE, NULL, 'l' << 8},
  88. {"version", ARG_NONE, NULL, 'V' << 8},
  89. {"help", ARG_NONE, NULL, 'h' << 8},
  90. {NULL, 0, 0, 0}
  91. };
  92. /* null-terminated list of options, such as obsolete-but-still-maintained
  93. options or undocumented options, which we don't show to the user */
  94. const int hidden_options[] = { (int)('T' << 8), 0 };
  95. const char *progname = "graph"; /* name of this program */
  96. const char *written = "Written by Robert S. Maier.";
  97. const char *copyright = "Copyright (C) 2009 Free Software Foundation, Inc.";
  98. const char *usage_appendage = " [FILE]...\n\
  99. With no FILE, or when FILE is -, read standard input.\n";
  100. /* forward references */
  101. static void close_file (char *filename, FILE *stream);
  102. static void open_file_for_reading (char *filename, FILE **input);
  103. static bool parse_pen_string (const char *pen_s);
  104. void
  105. add_legend (Legend **legends, int *length, const Point *point, char const *label)
  106. {
  107. ++(*length);
  108. *legends = (Legend *)xrealloc (*legends, *length * sizeof (Legend));
  109. memcpy(&((*legends)[*length-1].point), point, sizeof (Point));
  110. (*legends)[*length-1].label = xstrdup(label);
  111. }
  112. int
  113. main (int argc, char *argv[])
  114. {
  115. /* Variables related to getopt parsing */
  116. int option;
  117. int opt_index;
  118. int errcnt = 0; /* errors encountered in getopt parsing */
  119. int matched;
  120. bool using_getopt = true; /* true until end of command-line options */
  121. bool continue_parse = true; /* reset e.g. when --help or --version seen */
  122. bool show_version = false; /* show version message? */
  123. bool show_usage = false; /* show usage message? */
  124. bool show_fonts = false; /* supply help on fonts? */
  125. bool do_list_fonts = false; /* show a list of fonts? */
  126. bool filter = false; /* will we act as a filter? */
  127. bool new_symbol = false;
  128. bool new_symbol_size = false;
  129. bool new_symbol_font_name = false;
  130. bool new_line_color = false;
  131. bool new_linemode = false;
  132. bool new_plot_line_width = false;
  133. bool new_fill_fraction = false;
  134. bool new_use_color = false;
  135. bool first_file_of_graph = true;
  136. bool first_graph_of_multigraph = true;
  137. FILE *data_file = NULL;
  138. /* Variables related to the point reader */
  139. Reader *reader = NULL;
  140. data_type input_type = T_ASCII; /* by default we read ascii data */
  141. bool auto_bump = true; /* auto-bump linemode between polylines? */
  142. bool auto_abscissa = false; /* generate abscissa values automatically? */
  143. double x_start = 0.; /* start and increment, for auto-abscissa */
  144. double delta_x = 1.;
  145. /* polyline attributes */
  146. int linemode_index = 1; /* linemode for polylines, 1=solid, etc. */
  147. double plot_line_width = -0.001; /* polyline width (as frac. of display width), negative means default provided by libplot) */
  148. int symbol_index = 0; /* 0=none, 1=dot, 2=plus, 3=asterisk, etc. */
  149. double symbol_size = .03; /* symbol size (frac. of plotting box size) */
  150. double fill_fraction = -1.0; /* negative means regions aren't filled */
  151. bool use_color = false; /* color / monochrome */
  152. bool new_legend_label = false;
  153. const char *legend_label = NULL;
  154. /* points used for legend */
  155. Legend *legends = (Legend *)xmalloc (0);
  156. int no_of_legends = 0;
  157. double place_legend_x = 1.;
  158. double place_legend_y = 1.;
  159. /* Variables related to both the point reader and the point plotter */
  160. bool transpose_axes = false; /* true means -x applies to y axis, etc. */
  161. /* Variables related to the multigrapher, i.e. point plotter */
  162. Multigrapher *multigrapher = NULL;
  163. /* command-line parameters (constant over multigrapher operation) */
  164. const char *output_format = "meta";/* libplot output format */
  165. const char *bg_color = NULL; /* color of background, if non-NULL */
  166. const char *bitmap_size = NULL;
  167. const char *emulate_color = NULL;
  168. const char *max_line_length = NULL;
  169. const char *meta_portable = NULL;
  170. const char *page_size = NULL;
  171. const char *rotation_angle = NULL;
  172. bool save_screen = false; /* save screen, i.e. no erase before plot? */
  173. /* graph-specific parameters (may change from graph to graph) */
  174. grid_type grid_spec = AXES_AND_BOX; /* frame type for current graph */
  175. bool no_rotate_y_label = false; /* used for pre-X11R6 servers */
  176. const char *frame_color = "black"; /* color of frame (and graph, if no -C)*/
  177. int clip_mode = 1; /* clipping mode (cf. gnuplot) */
  178. /* following variables are portmanteau: x and y are included as bitfields*/
  179. int log_axis = 0; /* log axes or linear axes? */
  180. int round_to_next_tick = 0; /* round axis limits to nearest tick? */
  181. int switch_axis_end = 0; /* axis at top/right instead of bottom/left? */
  182. int omit_ticks = 0; /* omit ticks and tick labels from an axis? */
  183. /* graph dimensions, expressed as fractions of the width of the libplot
  184. graphics display [by convention square]; <0.0 means use libplot default */
  185. double frame_line_width = -0.001; /* width of lines in the graph frame */
  186. /* dimensions of graphing area, expressed as fractions of the width of
  187. the libplot graphics display [by convention square] */
  188. double margin_below = .2; /* margin below the plot */
  189. double margin_left = .2; /* margin left of the plot */
  190. double plot_height = .6; /* height of the plot */
  191. double plot_width = .6; /* width of the plot */
  192. /* dimensions, expressed as fractions of the size of the plotting area */
  193. double tick_size = .02; /* size of tick marks (< 0.0 allowed) */
  194. double font_size = 0.0525; /* fontsize */
  195. double title_font_size = 0.07; /* title fontsize */
  196. double legend_font_size = 0.035; /* title fontsize */
  197. double blankout_fraction = 1.3; /* this fraction of size of plotting box
  198. is erased before the plot is drawn */
  199. /* text-related */
  200. const char *font_name = NULL; /* font name, NULL -> device default */
  201. const char *title_font_name = NULL; /* title font name, NULL -> default */
  202. const char *symbol_font_name = "ZapfDingbats"; /* symbol font name, NULL -> default */
  203. const char *line_color = ""; /* line color, default */
  204. const char *x_label = NULL; /* label for the x axis, NULL -> no label */
  205. const char *y_label = NULL; /* label for the y axis, NULL -> no label */
  206. const char *top_label = NULL; /* title above the plot, NULL -> no title */
  207. /* user-specified limits on the axes */
  208. double min_x = 0.0, min_y = 0.0, max_x = 0.0, max_y = 0.0;
  209. double spacing_x = 0.0, spacing_y = 0.0;
  210. /* flags indicating which axis limits the user has specified */
  211. bool spec_min_x = false, spec_min_y = false;
  212. bool spec_max_x = false, spec_max_y = false;
  213. bool spec_spacing_x = false, spec_spacing_y = false;
  214. /* misc. local variables used in getopt parsing, counterparts to the above */
  215. double local_x_start, local_delta_x;
  216. int local_grid_style;
  217. int local_symbol_index;
  218. int local_clip_mode;
  219. double local_symbol_size, local_font_size, local_title_font_size, local_legend_font_size;
  220. double local_frame_line_width, local_plot_line_width;
  221. double local_min_x, local_min_y;
  222. double local_max_x, local_max_y;
  223. double local_spacing_x, local_spacing_y;
  224. double local_fill_fraction;
  225. double local_place_legend;
  226. /* `finalized' arguments to set_graph_parameters() (computed at the time
  227. the first file of a graph is seen, and continuing in effect over the
  228. duration of the graph) */
  229. int final_log_axis = 0;
  230. int final_round_to_next_tick = 0;
  231. double final_min_x = 0.0, final_max_x = 0.0, final_spacing_x = 0.0;
  232. double final_min_y = 0.0, final_max_y = 0.0, final_spacing_y = 0.0;
  233. bool final_spec_min_x = false, final_spec_min_y = false;
  234. bool final_spec_max_x = false, final_spec_max_y = false;
  235. bool final_spec_spacing_x = false, final_spec_spacing_y = false;
  236. bool final_transpose_axes = false;
  237. /* for storage of data points (if we're not acting as a filter) */
  238. Point *p; /* points array */
  239. int points_length = 1024; /* length of the points array, in points */
  240. int no_of_points = 0; /* number of points stored in it */
  241. /* support for multigraphing */
  242. double reposition_trans_x = 0.0, reposition_trans_y = 0.0;
  243. double reposition_scale = 1.0;
  244. double old_reposition_trans_x, old_reposition_trans_y;
  245. double old_reposition_scale;
  246. /* sui generis */
  247. bool frame_on_top = false;
  248. /* The main command-line parsing loop, which uses getopt to scan argv[]
  249. without reordering, i.e. to process command-line arguments (options
  250. and filenames) sequentially.
  251. From a logical point of view, a multigraph consists of a sequence of
  252. graphs, with a `--reposition' flag serving as a separator between
  253. graphs. A graph is drawn from one or more files.
  254. So this parsing loop invokes Multigrapher methods (1) when a file name
  255. is seen, (2) when a `--reposition' directive is seen, and (3) at the
  256. end of the scan over argv[].
  257. If at the end of the scan no file names have been seen, stdin is used
  258. instead as an input stream. (As a file name, `-' means stdin.) */
  259. while (continue_parse)
  260. {
  261. if (using_getopt)
  262. /* end of options not reached yet */
  263. {
  264. option = getopt_long (argc, argv,
  265. /* initial hyphen requests no reordering */
  266. optstring,
  267. long_options, &opt_index);
  268. if (option == EOF) /* end of options */
  269. {
  270. using_getopt = false;
  271. continue; /* back to top of while loop */
  272. }
  273. if (option == 1) /* filename embedded among options */
  274. {
  275. if (strcmp (optarg, "-") == 0)
  276. data_file = stdin; /* interpret "-" as stdin */
  277. else
  278. open_file_for_reading (optarg, &data_file);
  279. }
  280. }
  281. else
  282. /* end of options reached, processing filenames manually */
  283. {
  284. if (optind >= argc) /* all files processed */
  285. {
  286. if (first_graph_of_multigraph && first_file_of_graph)
  287. /* no file appeared on command line, read stdin instead */
  288. {
  289. data_file = stdin;
  290. option = 1; /* code for pseudo-option */
  291. }
  292. else
  293. break; /* all files done, break out of while loop */
  294. }
  295. else /* have files yet to process */
  296. {
  297. if (strcmp (argv[optind], "-") == 0)
  298. data_file = stdin;
  299. else
  300. open_file_for_reading (argv[optind], &data_file);
  301. optarg = argv[optind]; /* keep track of name of opened file */
  302. optind++;
  303. option = 1; /* code for pseudo-option */
  304. }
  305. }
  306. /* Parse an option flag, which may be a genuine option flag obtained
  307. from getopt, or a fake (a `1', indicating that a filename has been
  308. seen by getopt, or that filename has been seen on the command line
  309. after all genuine options have been processed, or that stdin
  310. must be read because no filenames have been seen). */
  311. switch (option)
  312. {
  313. /* ----------- options with no argument --------------*/
  314. case 's': /* Don't erase display before plot, ARG NONE */
  315. save_screen = true;
  316. break;
  317. case 't': /* Toggle transposition of axes, ARG NONE */
  318. transpose_axes = (transpose_axes == true ? false : true);
  319. break;
  320. case 'B': /* Toggle linemode auto-bumping, ARG NONE */
  321. auto_bump = (auto_bump == true ? false : true);
  322. break;
  323. case 'C': /* Toggle color/monochrome, ARG NONE */
  324. new_use_color = true;
  325. use_color = (use_color == true ? false : true);
  326. break;
  327. case 'L' << 8:
  328. new_legend_label = true;
  329. legend_label = xstrdup (optarg);
  330. break;
  331. case 'H': /* Toggle frame-on-top, ARG NONE */
  332. frame_on_top = (frame_on_top == true ? false : true);
  333. break;
  334. case 'O': /* portable format, ARG NONE */
  335. meta_portable = "yes";
  336. break;
  337. case 'e' << 8: /* emulate color, ARG NONE */
  338. emulate_color = xstrdup (optarg);
  339. break;
  340. case 'V' << 8: /* Version, ARG NONE */
  341. show_version = true;
  342. continue_parse = false;
  343. break;
  344. case 'h' << 8: /* Help, ARG NONE */
  345. show_usage = true;
  346. continue_parse = false;
  347. break;
  348. case 'f' << 8: /* Help on fonts, ARG NONE */
  349. show_fonts = true;
  350. continue_parse = false;
  351. break;
  352. case 'l' << 8: /* List fonts, ARG NONE */
  353. do_list_fonts = true;
  354. continue_parse = false;
  355. break;
  356. case 'Q': /* Toggle rotation of y-label, ARG NONE */
  357. no_rotate_y_label = (no_rotate_y_label == true ? false : true);
  358. break;
  359. /*----------- options with a single argument --------------*/
  360. case 'I': /* Input format, ARG REQUIRED */
  361. switch (*optarg)
  362. {
  363. case 'a':
  364. case 'A':
  365. /* ASCII format, records and fields within records are
  366. separated by whitespace, and datasets are separated by a
  367. pair of newlines. Record length = 2. */
  368. input_type = T_ASCII;
  369. break;
  370. case 'f':
  371. case 'F':
  372. /* Binary single precision, records and fields within records
  373. are contiguous, and datasets are separated by a FLT_MAX.
  374. Record length = 2. */
  375. input_type = T_SINGLE;
  376. break;
  377. case 'd':
  378. case 'D':
  379. /* Binary double precision, records and fields within records
  380. are contiguous, and datasets are separated by a DBL_MAX.
  381. Record length = 2. */
  382. input_type = T_DOUBLE;
  383. break;
  384. case 'i':
  385. case 'I':
  386. /* Binary integer, records and fields within records are
  387. contiguous, and datasets are separated by an occurrence of
  388. INT_MAX. Record length = 2. */
  389. input_type = T_INTEGER;
  390. break;
  391. case 'e':
  392. case 'E':
  393. /* Same as T_ASCII, but record length = 3. */
  394. input_type = T_ASCII_ERRORBAR;
  395. break;
  396. case 'g':
  397. case 'G':
  398. /* Sui generis. */
  399. input_type = T_GNUPLOT; /* gnuplot `table' format */
  400. break;
  401. default:
  402. fprintf (stderr,
  403. "%s: error: `%s' is an unrecognized data option\n",
  404. progname, optarg);
  405. errcnt++;
  406. }
  407. break;
  408. case 'f': /* Font size, ARG REQUIRED */
  409. if (sscanf (optarg, "%lf", &local_font_size) <= 0)
  410. {
  411. fprintf (stderr,
  412. "%s: error: the font size should be a number, but it was `%s'\n",
  413. progname, optarg);
  414. errcnt++;
  415. }
  416. else
  417. {
  418. if (local_font_size >= 1.0)
  419. fprintf (stderr, "%s: the too-large font size `%f' is disregarded (it should be less than 1.0)\n",
  420. progname, local_font_size);
  421. else if (local_font_size < 0.0)
  422. fprintf (stderr, "%s: the negative font size `%f' is disregarded\n",
  423. progname, local_font_size);
  424. else
  425. font_size = local_font_size;
  426. }
  427. break;
  428. case 'g': /* Grid style, ARG REQUIRED */
  429. if (sscanf (optarg, "%d", &local_grid_style) <= 0)
  430. {
  431. fprintf (stderr,
  432. "%s: error: the grid style should be a (small) integer, but it was `%s'\n",
  433. progname, optarg);
  434. errcnt++;
  435. break;
  436. }
  437. switch (local_grid_style)
  438. /* the subset ordering is: 0 < 1 < 2 < 3; 4 is different */
  439. {
  440. case 0:
  441. /* no frame at all; just the plot */
  442. grid_spec = NO_AXES;
  443. break;
  444. case 1:
  445. /* box, ticks, gridlines, labels */
  446. grid_spec = AXES;
  447. break;
  448. case 2:
  449. /* box, ticks, no gridlines, labels */
  450. grid_spec = AXES_AND_BOX;
  451. break;
  452. case 3:
  453. /* `half-box', partial ticks, no gridlines, labels */
  454. grid_spec = AXES_AND_BOX_AND_GRID;
  455. break;
  456. case 4:
  457. /* no box, no gridlines; specially positioned axes, labels */
  458. grid_spec = AXES_AT_ORIGIN;
  459. break;
  460. case 5:
  461. /* like AXES_AND_BOX, but no axes */
  462. grid_spec = BOX;
  463. break;
  464. default:
  465. fprintf (stderr,
  466. "%s: error: the grid style number `%s' is out of bounds\n",
  467. progname, optarg);
  468. errcnt++;
  469. }
  470. break;
  471. case 'h': /* Height of plot, ARG REQUIRED */
  472. if (sscanf (optarg, "%lf", &plot_height) <= 0)
  473. {
  474. fprintf (stderr,
  475. "%s: error: the plot height should be a number, but it was `%s'\n",
  476. progname, optarg);
  477. errcnt++;
  478. }
  479. break;
  480. case 'K': /* Clip mode, ARG REQUIRED */
  481. if ((sscanf (optarg, "%d", &local_clip_mode) <= 0)
  482. || local_clip_mode < 0 || local_clip_mode > 2)
  483. fprintf (stderr,
  484. "%s: the bad clip mode `%s' is disregarded (it should be 0, 1, or 2)\n",
  485. progname, optarg);
  486. else
  487. clip_mode = local_clip_mode;
  488. break;
  489. case 'l': /* Toggle log/linear axis, ARG REQUIRED */
  490. switch (*optarg)
  491. {
  492. case 'x':
  493. case 'X':
  494. log_axis ^= X_AXIS;
  495. break;
  496. case 'y':
  497. case 'Y':
  498. log_axis ^= Y_AXIS;
  499. break;
  500. default:
  501. fprintf (stderr,
  502. "%s: the unrecognized axis specification `%s' is disregarded\n",
  503. progname, optarg);
  504. break;
  505. }
  506. break;
  507. case 'N': /* Toggle omission of labels, ARG REQUIRED */
  508. switch (*optarg)
  509. {
  510. case 'x':
  511. case 'X':
  512. omit_ticks ^= X_AXIS;
  513. break;
  514. case 'y':
  515. case 'Y':
  516. omit_ticks ^= Y_AXIS;
  517. break;
  518. default:
  519. fprintf (stderr,
  520. "%s: the unrecognized axis specification `%s' is disregarded\n",
  521. progname, optarg);
  522. break;
  523. }
  524. break;
  525. case 'm': /* Linemode, ARG REQUIRED */
  526. new_linemode = true;
  527. if (sscanf (optarg, "%d", &linemode_index) <= 0)
  528. {
  529. fprintf (stderr,
  530. "%s: error: the linemode should be a (small) integer, but it was `%s'\n",
  531. progname, optarg);
  532. errcnt++;
  533. }
  534. break;
  535. case 'c': /* Color, ARG REQUIRED */
  536. new_line_color = true;
  537. line_color = xstrdup (optarg);
  538. break;
  539. case 'q': /* Fill fraction, ARG REQUIRED */
  540. if (sscanf (optarg, "%lf", &local_fill_fraction) <= 0)
  541. {
  542. fprintf (stderr,
  543. "%s: error: the fill fraction should be a number, but it was `%s'\n",
  544. progname, optarg);
  545. errcnt++;
  546. }
  547. else
  548. {
  549. if (local_fill_fraction > 1.0)
  550. fprintf (stderr,
  551. "%s: the region fill fraction `%f' was disregarded (it should be less than or equal to 1.0)\n",
  552. progname, local_fill_fraction);
  553. else
  554. {
  555. fill_fraction = local_fill_fraction;
  556. new_fill_fraction = true;
  557. }
  558. }
  559. break;
  560. case 'r': /* Right shift, ARG REQUIRED */
  561. if (sscanf (optarg, "%lf", &margin_left) <= 0)
  562. {
  563. fprintf (stderr,
  564. "%s: error: the rightward displacement for the plot should be a number, but it was `%s'\n",
  565. progname, optarg);
  566. errcnt++;
  567. }
  568. break;
  569. case 'u': /* Upward shift, ARG REQUIRED */
  570. if (sscanf (optarg, "%lf", &margin_below) <= 0)
  571. {
  572. fprintf (stderr,
  573. "%s: error: the upward displacement for the plot should be a number, but it was `%s'\n",
  574. progname, optarg);
  575. errcnt++;
  576. }
  577. break;
  578. case 'w': /* Width of plot, ARG REQUIRED */
  579. if (sscanf (optarg, "%lf", &plot_width) <= 0)
  580. {
  581. fprintf (stderr,
  582. "%s: error: the plot width should be a number, but it was `%s'\n",
  583. progname, optarg);
  584. errcnt++;
  585. }
  586. break;
  587. case 'T': /* Output format, ARG REQUIRED */
  588. case 'T' << 8:
  589. output_format = xstrdup (optarg);
  590. break;
  591. case 'F': /* Font name, ARG REQUIRED */
  592. font_name = xstrdup (optarg);
  593. break;
  594. case 'r' << 8: /* Rotation angle, ARG REQUIRED */
  595. rotation_angle = xstrdup (optarg);
  596. break;
  597. case 'Z' << 8: /* Title Font name, ARG REQUIRED */
  598. title_font_name = xstrdup (optarg);
  599. break;
  600. case 'G' << 8: /* Symbol Font name, ARG REQUIRED */
  601. symbol_font_name = xstrdup (optarg);
  602. new_symbol_font_name = true;
  603. break;
  604. case 'R': /* Toggle rounding to next tick, ARG REQUIRED*/
  605. switch (*optarg)
  606. {
  607. case 'x':
  608. case 'X':
  609. round_to_next_tick ^= X_AXIS;
  610. break;
  611. case 'y':
  612. case 'Y':
  613. round_to_next_tick ^= Y_AXIS;
  614. break;
  615. default:
  616. fprintf (stderr,
  617. "%s: the unrecognized axis specification `%s' is disregarded\n",
  618. progname, optarg);
  619. break;
  620. }
  621. break;
  622. case 'L': /* Top title, ARG REQUIRED */
  623. top_label = xstrdup (optarg);
  624. break;
  625. case 'k': /* Tick size, ARG REQUIRED */
  626. if (sscanf (optarg, "%lf", &tick_size) <= 0)
  627. {
  628. fprintf (stderr,
  629. "%s: error: the tick size should be a number, but it was `%s'\n",
  630. progname, optarg);
  631. errcnt++;
  632. }
  633. break;
  634. case 'W': /* Line width, ARG REQUIRED */
  635. if (sscanf (optarg, "%lf", &local_plot_line_width) <= 0)
  636. {
  637. fprintf (stderr,
  638. "%s: error: the line thickness for the plot should be a number, but it was `%s'\n",
  639. progname, optarg);
  640. errcnt++;
  641. }
  642. if (local_plot_line_width < 0.0)
  643. fprintf (stderr, "%s: the negative plot line thickness `%f' is disregarded\n",
  644. progname, local_plot_line_width);
  645. else
  646. {
  647. plot_line_width = local_plot_line_width;
  648. new_plot_line_width = true;
  649. }
  650. break;
  651. case 'X': /* X axis title, ARG REQUIRED */
  652. x_label = xstrdup (optarg);
  653. break;
  654. case 'Y': /* Y axis title, ARG REQUIRED */
  655. y_label = xstrdup (optarg);
  656. break;
  657. case 'E': /* Toggle switching of axis to other end,
  658. ARG REQUIRED */
  659. switch (*optarg)
  660. {
  661. case 'x':
  662. case 'X':
  663. switch_axis_end ^= Y_AXIS;
  664. break;
  665. case 'y':
  666. case 'Y':
  667. switch_axis_end ^= X_AXIS;
  668. break;
  669. default:
  670. fprintf (stderr,
  671. "%s: the unrecognized axis specification `%s' is disregarded\n",
  672. progname, optarg);
  673. break;
  674. }
  675. break;
  676. case 'b' << 8: /* Blankout fraction, ARG REQUIRED */
  677. if (sscanf (optarg, "%lf", &blankout_fraction) <= 0)
  678. {
  679. fprintf (stderr,
  680. "%s: error: the fractional blankout should be a number, but it was `%s'\n",
  681. progname, optarg);
  682. errcnt++;
  683. }
  684. break;
  685. case 'B' << 8: /* Bitmap size, ARG REQUIRED */
  686. bitmap_size = xstrdup (optarg);
  687. break;
  688. case 'F' << 8: /* Title font size, ARG REQUIRED */
  689. if (sscanf (optarg, "%lf", &local_title_font_size) <= 0)
  690. {
  691. fprintf (stderr,
  692. "%s: error: the font size for the title should be a number, but it was `%s'\n",
  693. progname, optarg);
  694. errcnt++;
  695. }
  696. else if (local_title_font_size >= 1.0)
  697. fprintf (stderr, "%s: the too-large title font size `%f' is disregarded (it should be less than 1.0)\n",
  698. progname, local_title_font_size);
  699. else if (local_title_font_size < 0.0)
  700. fprintf (stderr, "%s: the negative title font size `%f' is disregarded\n",
  701. progname, local_title_font_size);
  702. if (local_title_font_size == 0.0)
  703. fprintf (stderr, "%s: the request for a zero title font size is disregarded\n",
  704. progname);
  705. else
  706. title_font_size = local_title_font_size;
  707. break;
  708. case 'Q' << 8: /* Legend font size, ARG REQUIRED */
  709. if (sscanf (optarg, "%lf", &local_legend_font_size) <= 0)
  710. {
  711. fprintf (stderr,
  712. "%s: error: the font size for the legend should be a number, but it was `%s'\n",
  713. progname, optarg);
  714. errcnt++;
  715. }
  716. else if (local_legend_font_size >= 1.0)
  717. fprintf (stderr, "%s: the too-large legend font size `%f' is disregarded (it should be less than 1.0)\n",
  718. progname, local_legend_font_size);
  719. else if (local_legend_font_size < 0.0)
  720. fprintf (stderr, "%s: the negative legend font size `%f' is disregarded\n",
  721. progname, local_legend_font_size);
  722. if (local_legend_font_size == 0.0)
  723. fprintf (stderr, "%s: the request for a zero legend font size is disregarded\n",
  724. progname);
  725. else
  726. legend_font_size = local_legend_font_size;
  727. break;
  728. case 'W' << 8: /* Frame line width, ARG REQUIRED */
  729. if (sscanf (optarg, "%lf", &local_frame_line_width) <= 0)
  730. {
  731. fprintf (stderr,
  732. "%s: error: the line thickness for the frame should be a number, but it was `%s'\n",
  733. progname, optarg);
  734. errcnt++;
  735. }
  736. if (local_frame_line_width < 0.0)
  737. fprintf (stderr, "%s: the negative frame line thickness `%f' is disregarded\n",
  738. progname, local_frame_line_width);
  739. else
  740. frame_line_width = local_frame_line_width;
  741. break;
  742. case 'M' << 8: /* Max line length, ARG REQUIRED */
  743. max_line_length = xstrdup (optarg);
  744. break;
  745. case 'P' << 8: /* Page size, ARG REQUIRED */
  746. page_size = xstrdup (optarg);
  747. break;
  748. case 'p' << 8: /* Pen color string, ARG REQUIRED */
  749. if (parse_pen_string (optarg) == false)
  750. {
  751. fprintf (stderr, "%s: the unparseable pen string `%s' is disregarded\n",
  752. progname, optarg);
  753. }
  754. break;
  755. case 'q' << 8: /* Background color, ARG REQUIRED */
  756. bg_color = xstrdup (optarg);
  757. break;
  758. case 'C' << 8: /* Frame color, ARG REQUIRED */
  759. frame_color = xstrdup (optarg);
  760. break;
  761. /*------ options with zero or more arguments ---------*/
  762. case 'O' << 8:
  763. optind--; /* ?? */
  764. if (optind >= argc)
  765. break;
  766. if (sscanf (argv[optind], "%lf", &local_place_legend) <= 0)
  767. break;
  768. place_legend_x = local_place_legend;
  769. if (place_legend_x<0. || place_legend_x>1.)
  770. {
  771. fprintf (stderr, "%s: error: place_legend x out of [0 1]: %s\n", progname, argv[optind]);
  772. return EXIT_FAILURE;
  773. }
  774. optind++; /* tell getopt we recognized place_legend_x */
  775. if (optind >= argc)
  776. break;
  777. if (sscanf (argv[optind], "%lf", &local_place_legend) <= 0)
  778. break;
  779. place_legend_y = local_place_legend;
  780. if (place_legend_y<0. || place_legend_y>1.)
  781. {
  782. fprintf (stderr, "%s: error: place_legend y out of [0 1]: %s\n", progname, argv[optind]);
  783. return EXIT_FAILURE;
  784. }
  785. optind++; /* tell getopt we recognized place_legend_y */
  786. break;
  787. case 'a': /* Auto-abscissa, ARG OPTIONAL [0,1,2] */
  788. auto_abscissa = true;
  789. if (optind >= argc)
  790. break;
  791. if (sscanf (argv[optind], "%lf", &local_delta_x) <= 0)
  792. break;
  793. optind++; /* tell getopt we recognized delta_x */
  794. if (local_delta_x == 0.0)
  795. /* "-a 0" turns off auto-abscissa for next file */
  796. {
  797. auto_abscissa = false;
  798. break;
  799. }
  800. delta_x = local_delta_x;
  801. if (optind >= argc)
  802. break;
  803. if (sscanf (argv[optind], "%lf", &local_x_start) <= 0)
  804. break;
  805. x_start = local_x_start;
  806. optind++; /* tell getopt we recognized x_start */
  807. break;
  808. case 'x': /* X limits, ARG OPTIONAL [0,1,2,3] */
  809. matched = 0;
  810. if (optind >= argc
  811. || ((strcmp (argv[optind], "-") != 0)
  812. && (matched
  813. = sscanf (argv[optind], "%lf", &local_min_x)) <= 0))
  814. {
  815. spec_min_x = spec_max_x = spec_spacing_x = false;
  816. break;
  817. }
  818. if (matched > 0)
  819. {
  820. spec_min_x = true;
  821. min_x = local_min_x;
  822. }
  823. else
  824. spec_min_x = false;
  825. optind++; /* tell getopt we recognized min_x */
  826. matched = 0;
  827. if (optind >= argc
  828. || ((strcmp (argv[optind], "-") != 0)
  829. && (matched
  830. = sscanf (argv[optind], "%lf", &local_max_x)) <= 0))
  831. {
  832. spec_max_x = spec_spacing_x = false;
  833. break;
  834. }
  835. if (matched > 0)
  836. {
  837. spec_max_x = true;
  838. max_x = local_max_x;
  839. }
  840. else
  841. spec_max_x = false;
  842. optind++; /* tell getopt we recognized max_x */
  843. matched = 0;
  844. if (optind >= argc
  845. || ((strcmp (argv[optind], "-") != 0)
  846. && (matched
  847. = sscanf (argv[optind], "%lf", &local_spacing_x)) <= 0))
  848. {
  849. spec_spacing_x = false;
  850. break;
  851. }
  852. if (matched > 0)
  853. {
  854. spec_spacing_x = true;
  855. spacing_x = local_spacing_x;
  856. }
  857. else
  858. spec_spacing_x = false;
  859. optind++; /* tell getopt we recognized spacing_x */
  860. break;
  861. case 'y': /* Y limits, ARG OPTIONAL [0,1,2,3] */
  862. matched = 0;
  863. if (optind >= argc
  864. || ((strcmp (argv[optind], "-") != 0)
  865. && (matched
  866. = sscanf (argv[optind], "%lf", &local_min_y)) <= 0))
  867. {
  868. spec_min_y = spec_max_y = spec_spacing_y = false;
  869. break;
  870. }
  871. if (matched > 0)
  872. {
  873. spec_min_y = true;
  874. min_y = local_min_y;
  875. }
  876. else
  877. spec_min_y = false;
  878. optind++; /* tell getopt we recognized min_y */
  879. matched = 0;
  880. if (optind >= argc
  881. || ((strcmp (argv[optind], "-") != 0)
  882. && (matched
  883. = sscanf (argv[optind], "%lf", &local_max_y)) <= 0))
  884. {
  885. spec_max_y = spec_spacing_y = false;
  886. break;
  887. }
  888. if (matched > 0)
  889. {
  890. spec_max_y = true;
  891. max_y = local_max_y;
  892. }
  893. else
  894. spec_max_y = false;
  895. optind++; /* tell getopt we recognized max_y */
  896. matched = 0;
  897. if (optind >= argc
  898. || ((strcmp (argv[optind], "-") != 0)
  899. && (matched
  900. = sscanf (argv[optind], "%lf", &local_spacing_y)) <= 0))
  901. {
  902. spec_spacing_y = false;
  903. break;
  904. }
  905. if (matched > 0)
  906. {
  907. spec_spacing_y = true;
  908. spacing_y = local_spacing_y;
  909. }
  910. else
  911. spec_spacing_y = false;
  912. optind++; /* tell getopt we recognized spacing_y */
  913. break;
  914. case 'S': /* Symbol, ARG OPTIONAL [0,1,2] */
  915. new_symbol = true;
  916. symbol_index = 1; /* symbol # 1 is switched to by -S alone */
  917. if (optind >= argc)
  918. break;
  919. if (sscanf (argv[optind], "%d", &local_symbol_index) <= 0)
  920. break;
  921. if (local_symbol_index < 0 || local_symbol_index > 255)
  922. fprintf (stderr, "%s: the symbol type `%d' is disregarded (it should be in the range 0..255)\n",
  923. progname, local_symbol_index);
  924. else
  925. symbol_index = local_symbol_index;
  926. optind++; /* tell getopt we recognized symbol_index */
  927. if (optind >= argc)
  928. break;
  929. if (sscanf (argv[optind], "%lf", &local_symbol_size) <= 0)
  930. break;
  931. if (local_symbol_size < 0.0)
  932. fprintf (stderr, "%s: the negative symbol size `%f' is disregarded\n",
  933. progname, local_symbol_size);
  934. else if (local_symbol_size == 0.0)
  935. fprintf (stderr, "%s: the request for a zero symbol size is disregarded\n",
  936. progname);
  937. else
  938. {
  939. symbol_size = local_symbol_size;
  940. new_symbol_size = true;
  941. }
  942. optind++; /* tell getopt we recognized symbol_size */
  943. break;
  944. /* ---------- options with one or more arguments ---------- */
  945. case 'R' << 8: /* End graph and reposition, ARG REQUIRED [3]*/
  946. old_reposition_trans_x = reposition_trans_x;
  947. old_reposition_trans_y = reposition_trans_y;
  948. old_reposition_scale = reposition_scale;
  949. if (sscanf (optarg, "%lf", &reposition_trans_x) <= 0)
  950. {
  951. fprintf (stderr,
  952. "%s: error: the x repositioning should be a number, but it was `%s'\n",
  953. progname, optarg);
  954. return EXIT_FAILURE;
  955. }
  956. if (optind >= argc)
  957. {
  958. fprintf (stderr,
  959. "%s: error: one or more arguments to the --reposition option were missing\n",
  960. progname);
  961. return EXIT_FAILURE;
  962. }
  963. if (sscanf (argv[optind], "%lf", &reposition_trans_y) <= 0)
  964. {
  965. fprintf (stderr,
  966. "%s: error: the y repositioning should be a number, but it was `%s'\n",
  967. progname, argv[optind]);
  968. return EXIT_FAILURE;
  969. }
  970. optind++; /* tell getopt we recognized trans_y */
  971. if (optind >= argc)
  972. {
  973. fprintf (stderr,
  974. "%s: error: one or more arguments to the --reposition option were missing\n",
  975. progname);
  976. return EXIT_FAILURE;
  977. }
  978. if (sscanf (argv[optind], "%lf", &reposition_scale) <= 0)
  979. {
  980. fprintf (stderr,
  981. "%s: error: the reposition scale factor should be a number, but it was `%s'\n",
  982. progname, optarg);
  983. return EXIT_FAILURE;
  984. }
  985. if (reposition_scale == 0.0)
  986. {
  987. fprintf (stderr,
  988. "%s: error: the reposition scale factor should not be zero\n", progname);
  989. return EXIT_FAILURE;
  990. }
  991. optind++; /* tell getopt we recognized trans_x */
  992. if (!first_file_of_graph)
  993. /* a graph is in progress (at least one file has been read), so
  994. it must be ended before we begin the next one */
  995. {
  996. if (!filter)
  997. /* We haven't been acting as a real-time filter for the
  998. duration of this graph, so the graph isn't already drawn
  999. on the display. Instead, we have a points array and we
  1000. need to plot it, after computing bounds. */
  1001. {
  1002. /* fill in any of min_? and max_? that user didn't
  1003. specify (the prefix "final_" means these arguments
  1004. were finalized at the time the first file of the plot
  1005. was processed) */
  1006. array_bounds (p, no_of_points,
  1007. final_transpose_axes, clip_mode,
  1008. &final_min_x, &final_min_y,
  1009. &final_max_x, &final_max_y,
  1010. final_spec_min_x, final_spec_min_y,
  1011. final_spec_max_x, final_spec_max_y);
  1012. if (first_graph_of_multigraph)
  1013. /* haven't created multigrapher yet, do so now */
  1014. {
  1015. if ((multigrapher = new_multigrapher (output_format, bg_color, bitmap_size, emulate_color, max_line_length, meta_portable, page_size, rotation_angle, save_screen)) == NULL)
  1016. {
  1017. fprintf (stderr,
  1018. "%s: error: the graphing device could not be opened\n", progname);
  1019. return EXIT_FAILURE;
  1020. }
  1021. }
  1022. /* begin graph: push new libplot drawing state onto stack
  1023. of states; also concatenate the current transformation
  1024. matrix with a matrix formed from the repositioning
  1025. parameters (this will be in effect for duration of the
  1026. graph) */
  1027. begin_graph (multigrapher,
  1028. old_reposition_scale,
  1029. old_reposition_trans_x, old_reposition_trans_y);
  1030. /* font selection, saves typing */
  1031. if ((title_font_name == NULL) && (font_name != NULL))
  1032. title_font_name = font_name;
  1033. /* initialize, using (in part) finalized arguments */
  1034. set_graph_parameters (multigrapher,
  1035. frame_line_width,
  1036. frame_color,
  1037. top_label,
  1038. title_font_name, title_font_size, /* for title */
  1039. tick_size, grid_spec,
  1040. final_min_x, final_max_x, final_spacing_x,
  1041. final_min_y, final_max_y, final_spacing_y,
  1042. final_spec_spacing_x,
  1043. final_spec_spacing_y,
  1044. plot_width, plot_height,
  1045. margin_below, margin_left,
  1046. font_name, font_size, /* for abs. label */
  1047. x_label,
  1048. font_name, font_size, /* for ord. label */
  1049. y_label,
  1050. no_rotate_y_label,
  1051. /* these args are portmanteaux */
  1052. final_log_axis,
  1053. final_round_to_next_tick,
  1054. switch_axis_end, omit_ticks,
  1055. /* more args */
  1056. clip_mode,
  1057. blankout_fraction,
  1058. final_transpose_axes);
  1059. /* draw the graph frame (grid, ticks, etc.); draw a
  1060. `canvas' (a background opaque white rectangle) only if
  1061. this isn't the first graph */
  1062. draw_frame_of_graph (multigrapher,
  1063. (first_graph_of_multigraph ? false : true));
  1064. /* plot the laboriously read-in array */
  1065. plot_point_array (multigrapher, p, no_of_points);
  1066. plot_legend (multigrapher, legends, no_of_legends, place_legend_x, place_legend_y, legend_font_size);
  1067. /* free points array */
  1068. free (p);
  1069. no_of_points = 0;
  1070. first_file_of_graph = false;
  1071. } /* end of not-filter case */
  1072. /* draw graph frame on top of graph, if user requested it */
  1073. if (frame_on_top)
  1074. {
  1075. end_polyline_and_flush (multigrapher);
  1076. draw_frame_of_graph (multigrapher, false);
  1077. }
  1078. /* end graph: pop the graph-specific libplot drawing state off
  1079. the stack of drawing states */
  1080. end_graph (multigrapher);
  1081. /* on to next graph */
  1082. first_graph_of_multigraph = false;
  1083. first_file_of_graph = true;
  1084. } /* end of not first-file-of-plot case */
  1085. break; /* end of `--reposition' option */
  1086. /* ---------------- pseudo-options -------------- */
  1087. /* File specified on command line, returned in order (along with
  1088. command-line options). The first time we reach this point in
  1089. any plot, we perform special initializations and in particular
  1090. determine whether or not, for the duration of this plot, we'll
  1091. be acting as a filter. We can do so if xmin, xmax, ymin, ymax
  1092. have all been specified, by this point, on the command line.
  1093. A plot may consist of many files. A plot in progress is
  1094. terminated if a --reposition option (which moves us to the
  1095. next plot of a multiplot) is seen, or when the last
  1096. command-line option is processed. */
  1097. case 1:
  1098. if (first_file_of_graph)
  1099. {
  1100. /* For plots with a logarithmic axis, compute logs of axis
  1101. limits, since coordinates along the axis, as obtained from
  1102. the reader, are stored in logarithmic form. */
  1103. if (log_axis & X_AXIS)
  1104. {
  1105. if (spec_min_x)
  1106. {
  1107. if (min_x > 0.0)
  1108. min_x = log10(min_x);
  1109. else
  1110. {
  1111. fprintf(stderr,
  1112. "%s: error: the limit %g on a logarithmic axis is nonpositive\n",
  1113. progname, min_x);
  1114. return EXIT_FAILURE;
  1115. }
  1116. }
  1117. if (spec_max_x)
  1118. {
  1119. if (max_x > 0.0)
  1120. max_x = log10(max_x);
  1121. else
  1122. {
  1123. fprintf(stderr,
  1124. "%s: error: the limit %g on a logarithmic axis is nonpositive\n",
  1125. progname, max_x);
  1126. return EXIT_FAILURE;
  1127. }
  1128. }
  1129. }
  1130. if (log_axis & Y_AXIS)
  1131. {
  1132. if (spec_min_y)
  1133. {
  1134. if (min_y > 0.0)
  1135. min_y = log10(min_y);
  1136. else
  1137. {
  1138. fprintf(stderr,
  1139. "%s: error: the limit %g on a logarithmic axis is nonpositive\n",
  1140. progname, min_y);
  1141. return EXIT_FAILURE;
  1142. }
  1143. }
  1144. if (spec_max_y)
  1145. {
  1146. if (max_y > 0.0)
  1147. max_y = log10(max_y);
  1148. else
  1149. {
  1150. fprintf(stderr,
  1151. "%s: error: the limit %g on a logarithmic axis is nonpositive\n",
  1152. progname, max_y);
  1153. return EXIT_FAILURE;
  1154. }
  1155. }
  1156. }
  1157. /* We now finalize the following parameters (arguments to
  1158. set_graph_parameters()), even though we won't call
  1159. set_graph_parameters() for a while yet, if it turns out we
  1160. need to act as a real-time filter. */
  1161. /* portmanteaux */
  1162. final_log_axis = log_axis;
  1163. final_round_to_next_tick = round_to_next_tick;
  1164. /* bool */
  1165. final_transpose_axes = transpose_axes;
  1166. /* x-axis specific */
  1167. final_min_x = min_x;
  1168. final_max_x = max_x;
  1169. final_spacing_x = spacing_x;
  1170. final_spec_min_x = spec_min_x;
  1171. final_spec_max_x = spec_max_x;
  1172. final_spec_spacing_x = spec_spacing_x;
  1173. /* y-axis specific */
  1174. final_min_y = min_y;
  1175. final_max_y = max_y;
  1176. final_spec_min_y = spec_min_y;
  1177. final_spec_max_y = spec_max_y;
  1178. final_spacing_y = spacing_y;
  1179. final_spec_spacing_y = spec_spacing_y;
  1180. /* If user didn't specify either the lower limit or the upper
  1181. limit for an axis, by default we'll round the axis limits
  1182. to the nearest tick, after computing them. (If either
  1183. limit was specified by the user, to request rounding the
  1184. user must specify the -R option as well.) */
  1185. if (!final_spec_min_x && !final_spec_max_x)
  1186. final_round_to_next_tick |= X_AXIS;
  1187. if (!final_spec_min_y && !final_spec_max_y)
  1188. final_round_to_next_tick |= Y_AXIS;
  1189. /* The case when x_min, x_max, y_min, y_max are all specified
  1190. by the luser is special: we set the `filter' flag for the
  1191. duration of this plot, to indicate that we can function as
  1192. a real-time filter, calling read_and_plot_file() on each
  1193. file, rather than calling read_file() on each one
  1194. separately to create an array of points, and then calling
  1195. plot_point_array(). */
  1196. filter = ((final_spec_min_x && final_spec_max_x
  1197. && final_spec_min_y && final_spec_max_y)
  1198. ? true : false);
  1199. } /* end of first-file-of-plot case */
  1200. if (filter)
  1201. /* filter flag is set, will call read_and_plot() on this file */
  1202. {
  1203. if (first_file_of_graph)
  1204. {
  1205. if (first_graph_of_multigraph)
  1206. /* need to create the multigrapher */
  1207. {
  1208. if ((multigrapher = new_multigrapher (output_format, bg_color, bitmap_size, emulate_color, max_line_length, meta_portable, page_size, rotation_angle, save_screen)) == NULL)
  1209. {
  1210. fprintf (stderr,
  1211. "%s: error: the graphing device could not be opened\n",
  1212. progname);
  1213. return EXIT_FAILURE;
  1214. }
  1215. }
  1216. /* begin graph: push a graph-specific drawing state onto
  1217. libplot's stack of drawing states; also concatenate
  1218. the current transformation matrix with a matrix formed
  1219. from the repositioning parameters (this will take
  1220. effect for the duration of the graph) */
  1221. begin_graph (multigrapher,
  1222. reposition_scale,
  1223. reposition_trans_x, reposition_trans_y);
  1224. /* font selection, saves typing */
  1225. if ((title_font_name == NULL) && (font_name != NULL))
  1226. title_font_name = font_name;
  1227. /* following will be in effect for the entire plot */
  1228. set_graph_parameters (multigrapher,
  1229. frame_line_width,
  1230. frame_color,
  1231. top_label,
  1232. title_font_name, title_font_size, /* for title */
  1233. tick_size, grid_spec,
  1234. final_min_x, final_max_x, final_spacing_x,
  1235. final_min_y, final_max_y, final_spacing_y,
  1236. final_spec_spacing_x,
  1237. final_spec_spacing_y,
  1238. plot_width, plot_height,
  1239. margin_below, margin_left,
  1240. font_name, font_size, /* on abscissa */
  1241. x_label,
  1242. font_name, font_size, /* on ordinate */
  1243. y_label,
  1244. no_rotate_y_label,
  1245. /* these args are portmanteaux */
  1246. final_log_axis,
  1247. final_round_to_next_tick,
  1248. switch_axis_end,
  1249. omit_ticks,
  1250. /* more args */
  1251. clip_mode,
  1252. blankout_fraction,
  1253. final_transpose_axes);
  1254. /* draw the graph frame (grid, ticks, etc.); draw a
  1255. `canvas' (a background opaque white rectangle) only if
  1256. this isn't the first graph */
  1257. draw_frame_of_graph (multigrapher,
  1258. first_graph_of_multigraph ? false : true);
  1259. reader = new_reader (data_file, input_type,
  1260. auto_abscissa, delta_x, x_start,
  1261. /* following three are graph-specific */
  1262. final_transpose_axes,
  1263. final_log_axis, auto_bump,
  1264. /* following args are file-specific
  1265. (they set dataset attributes) */
  1266. symbol_index, symbol_size,
  1267. symbol_font_name,
  1268. line_color,
  1269. linemode_index, plot_line_width,
  1270. fill_fraction, use_color);
  1271. new_symbol = new_symbol_size = new_symbol_font_name = false;
  1272. new_line_color = new_linemode = new_plot_line_width = false;
  1273. new_fill_fraction = new_use_color = false;
  1274. }
  1275. else
  1276. /* not first file of plot; do some things anyway */
  1277. {
  1278. /* set reader parameters that may change when we move
  1279. from file to file within a plot */
  1280. alter_reader_parameters (reader,
  1281. data_file, input_type,
  1282. auto_abscissa, delta_x, x_start,
  1283. /* following args set dataset
  1284. attributes */
  1285. symbol_index, symbol_size,
  1286. symbol_font_name,
  1287. line_color,
  1288. linemode_index, plot_line_width,
  1289. fill_fraction, use_color,
  1290. /* following bools make up a mask*/
  1291. new_symbol, new_symbol_size,
  1292. new_symbol_font_name,
  1293. new_line_color,
  1294. new_linemode, new_plot_line_width,
  1295. new_fill_fraction, new_use_color);
  1296. new_symbol = new_symbol_size = new_symbol_font_name = false;
  1297. new_line_color = new_linemode = new_plot_line_width = false;
  1298. new_fill_fraction = new_use_color = false;
  1299. }
  1300. /* call read_and_plot_file() on the file; each dataset in the
  1301. file yields a polyline */
  1302. read_and_plot_file (reader, multigrapher, &no_of_points, &new_legend_label, &legends, &no_of_legends, legend_label);
  1303. } /* end of filter case */
  1304. else
  1305. /* filter flag is set, will read and plot this file separately */
  1306. /* Luser didn't specify enough information for us to act as a
  1307. filter, so we do things the hard way: we call read_file() on
  1308. each file to create a points array, and at the end of the
  1309. plot we'll call plot_point_array() on the array. For now,
  1310. we don't even call set_graph_parameters(). */
  1311. {
  1312. if (first_file_of_graph) /* some additional initializations */
  1313. {
  1314. p = (Point *)xmalloc (points_length * sizeof (Point));
  1315. reader = new_reader (data_file, input_type,
  1316. auto_abscissa, delta_x, x_start,
  1317. /* following are graph-specific */
  1318. final_transpose_axes,
  1319. final_log_axis, auto_bump,
  1320. /* following args are file-specific
  1321. (they set dataset attributes) */
  1322. symbol_index, symbol_size,
  1323. symbol_font_name,
  1324. line_color,
  1325. linemode_index, plot_line_width,
  1326. fill_fraction, use_color);
  1327. new_symbol = new_symbol_size = new_symbol_font_name = false;
  1328. new_line_color = new_linemode = new_plot_line_width = false;
  1329. new_fill_fraction = new_use_color = false;
  1330. }
  1331. else /* not first file of plot, but do some things anyway */
  1332. {
  1333. /* set reader parameters that may change when we move
  1334. from file to file within a plot */
  1335. alter_reader_parameters (reader,
  1336. data_file, input_type,
  1337. auto_abscissa, delta_x, x_start,
  1338. /* following args set dataset
  1339. attributes */
  1340. symbol_index, symbol_size,
  1341. symbol_font_name,
  1342. line_color,
  1343. linemode_index, plot_line_width,
  1344. fill_fraction, use_color,
  1345. /* following bools make up a mask*/
  1346. new_symbol, new_symbol_size,
  1347. new_symbol_font_name,
  1348. new_line_color,
  1349. new_linemode, new_plot_line_width,
  1350. new_fill_fraction, new_use_color);
  1351. new_symbol = new_symbol_size = new_symbol_font_name = false;
  1352. new_line_color = new_linemode = new_plot_line_width = false;
  1353. new_fill_fraction = new_use_color = false;
  1354. }
  1355. /* add points to points array by calling read_file() on file */
  1356. int old_no_of_points = no_of_points;
  1357. read_file (reader, &p, &points_length, &no_of_points);
  1358. if (new_legend_label && no_of_points>old_no_of_points)
  1359. add_legend (&legends, &no_of_legends, &p[no_of_points-1], legend_label);
  1360. new_legend_label = false;
  1361. } /* end of not-filter case */
  1362. /* close file */
  1363. if (data_file != stdin)
  1364. close_file (optarg, data_file);
  1365. first_file_of_graph = false;
  1366. break; /* end of `case 1' in switch() [i.e., filename seen] */
  1367. /*---------------- End of options ----------------*/
  1368. default: /* Default, unknown option */
  1369. errcnt++;
  1370. continue_parse = false;
  1371. break;
  1372. } /* end of switch() */
  1373. if (errcnt > 0)
  1374. continue_parse = false;
  1375. } /* end of while loop */
  1376. if (errcnt > 0)
  1377. {
  1378. fprintf (stderr, "Try `%s --help' for more information\n", progname);
  1379. return EXIT_FAILURE;
  1380. }
  1381. if (show_version)
  1382. {
  1383. display_version (progname, written, copyright);
  1384. return EXIT_SUCCESS;
  1385. }
  1386. if (do_list_fonts)
  1387. {
  1388. int success;
  1389. success = list_fonts (output_format, progname);
  1390. if (success)
  1391. return EXIT_SUCCESS;
  1392. else
  1393. return EXIT_FAILURE;
  1394. }
  1395. if (show_fonts)
  1396. {
  1397. int success;
  1398. success = display_fonts (output_format, progname);
  1399. if (success)
  1400. return EXIT_SUCCESS;
  1401. else
  1402. return EXIT_FAILURE;
  1403. }
  1404. if (show_usage)
  1405. {
  1406. display_usage (progname, hidden_options, usage_appendage, 2);
  1407. return EXIT_SUCCESS;
  1408. }
  1409. /* End of command-line parse. At this point, we need to terminate the
  1410. graph currently in progress, if it's nonempty (i.e. if one or more
  1411. files have been read). */
  1412. if (!first_file_of_graph)
  1413. {
  1414. /* At least one file was read. If we're acting as a real-time
  1415. filter, then the graph is already drawn on the display and there's
  1416. nothing for us to do. Instead, we have a points array and we need
  1417. to plot it, after computing bounds. */
  1418. if (!filter)
  1419. {
  1420. /* fill in any of min_? and max_? that user didn't specify (the
  1421. prefix "final_" means these arguments were finalized at the
  1422. time the first file of the plot was processed) */
  1423. array_bounds (p, no_of_points,
  1424. final_transpose_axes, clip_mode,
  1425. &final_min_x, &final_min_y,
  1426. &final_max_x, &final_max_y,
  1427. final_spec_min_x, final_spec_min_y,
  1428. final_spec_max_x, final_spec_max_y);
  1429. if (first_graph_of_multigraph)
  1430. /* still haven't created multigrapher, do so now */
  1431. {
  1432. if ((multigrapher = new_multigrapher (output_format, bg_color, bitmap_size, emulate_color, max_line_length, meta_portable, page_size, rotation_angle, save_screen)) == NULL)
  1433. {
  1434. fprintf (stderr,
  1435. "%s: error: the graphing device could not be opened\n", progname);
  1436. return EXIT_FAILURE;
  1437. }
  1438. }
  1439. /* begin graph: push new libplot drawing state onto stack of
  1440. states; also concatenate the current transformation matrix
  1441. with a matrix formed from the repositioning parameters (this
  1442. will take effect for the duration of the graph) */
  1443. begin_graph (multigrapher,
  1444. reposition_scale,
  1445. reposition_trans_x, reposition_trans_y);
  1446. /* font selection, saves typing */
  1447. if ((title_font_name == NULL) && (font_name != NULL))
  1448. title_font_name = font_name;
  1449. set_graph_parameters (multigrapher,
  1450. frame_line_width,
  1451. frame_color,
  1452. top_label,
  1453. title_font_name, title_font_size, /*for title*/
  1454. tick_size, grid_spec,
  1455. final_min_x, final_max_x, final_spacing_x,
  1456. final_min_y, final_max_y, final_spacing_y,
  1457. final_spec_spacing_x,
  1458. final_spec_spacing_y,
  1459. plot_width, plot_height,
  1460. margin_below, margin_left,
  1461. font_name, font_size, /* for abscissa label */
  1462. x_label,
  1463. font_name, font_size, /* for ordinate label */
  1464. y_label,
  1465. no_rotate_y_label,
  1466. /* these args are portmanteaux */
  1467. final_log_axis,
  1468. final_round_to_next_tick,
  1469. switch_axis_end, omit_ticks,
  1470. /* more args */
  1471. clip_mode,
  1472. blankout_fraction,
  1473. final_transpose_axes);
  1474. /* draw the graph frame (grid, ticks, etc.); draw a `canvas' (a
  1475. background opaque white rectangle) only if this isn't the
  1476. first graph */
  1477. draw_frame_of_graph (multigrapher,
  1478. first_graph_of_multigraph ? false : true);
  1479. /* plot the laboriously read-in array */
  1480. plot_point_array (multigrapher, p, no_of_points);
  1481. /* free points array */
  1482. free (p);
  1483. no_of_points = 0;
  1484. } /* end of not-filter case */
  1485. /* plot accumulated legend */
  1486. plot_legend (multigrapher, legends, no_of_legends, place_legend_x, place_legend_y, legend_font_size);
  1487. /* draw graph frame on top of graph, if user requested it */
  1488. if (frame_on_top)
  1489. {
  1490. end_polyline_and_flush (multigrapher);
  1491. draw_frame_of_graph (multigrapher, false);
  1492. }
  1493. /* end graph: pop drawing state off the stack of drawing states */
  1494. end_graph (multigrapher);
  1495. } /* end of nonempty-graph case */
  1496. /* finish up by deleting our multigrapher (one must have been created,
  1497. since we always read at least stdin) */
  1498. if (delete_multigrapher (multigrapher) < 0)
  1499. {
  1500. fprintf (stderr, "%s: error: the graphing device could not be closed\n",
  1501. progname);
  1502. return EXIT_FAILURE;
  1503. }
  1504. return EXIT_SUCCESS;
  1505. }
  1506. static void
  1507. open_file_for_reading (char *filename, FILE **input)
  1508. {
  1509. FILE *data_file;
  1510. data_file = fopen (filename, "r");
  1511. if (data_file == NULL)
  1512. {
  1513. fprintf (stderr, "%s: %s: %s\n", progname, filename, strerror(errno));
  1514. exit (EXIT_FAILURE);
  1515. }
  1516. else
  1517. *input = data_file;
  1518. }
  1519. static void
  1520. close_file (char *filename, FILE *stream)
  1521. {
  1522. if (fclose (stream) < 0)
  1523. fprintf (stderr,
  1524. "%s: the input file `%s' could not be closed\n",
  1525. progname, filename);
  1526. }
  1527. static bool
  1528. parse_pen_string (const char *pen_s)
  1529. {
  1530. const char *charp;
  1531. char name[MAX_COLOR_NAME_LEN];
  1532. int i;
  1533. charp = pen_s;
  1534. while (*charp)
  1535. {
  1536. int pen_num;
  1537. bool got_digit;
  1538. const char *tmp;
  1539. if (*charp == ':') /* skip any ':' */
  1540. {
  1541. charp++;
  1542. continue; /* back to top of while loop */
  1543. }
  1544. pen_num = 0;
  1545. got_digit = false;
  1546. while (*charp >= '0' && *charp <= '9')
  1547. {
  1548. pen_num = 10 * pen_num + (int)*charp - (int)'0';
  1549. got_digit = true;
  1550. charp++;
  1551. }
  1552. if (!got_digit || pen_num < 1 || pen_num > NO_OF_LINEMODES)
  1553. return false;
  1554. if (*charp != '=')
  1555. return false;
  1556. charp++;
  1557. for (tmp = charp, i = 0; i < MAX_COLOR_NAME_LEN; tmp++, i++)
  1558. {
  1559. if (*tmp == ':') /* end of color name string */
  1560. {
  1561. name[i] = '\0';
  1562. charp = tmp + 1;
  1563. break;
  1564. }
  1565. else if (*tmp == '\0') /* end of name string */
  1566. {
  1567. name[i] = '\0';
  1568. charp = tmp;
  1569. break;
  1570. }
  1571. else
  1572. name[i] = *tmp;
  1573. }
  1574. /* replace pen color name by user-specified color name */
  1575. colorstyle[pen_num - 1] = xstrdup (name);
  1576. }
  1577. return true;
  1578. }
  1579. /*
  1580. Local Variables:
  1581. c-file-style: "gnu"
  1582. tab-width: 8
  1583. End:
  1584. */