1 /*
2 * Copyright (c) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
3 * 2002, 2003, 2004
4 * Ohio University.
5 *
6 * ---
7 *
8 * Starting with the release of tcptrace version 6 in 2001, tcptrace
9 * is licensed under the GNU General Public License (GPL). We believe
10 * that, among the available licenses, the GPL will do the best job of
11 * allowing tcptrace to continue to be a valuable, freely-available
12 * and well-maintained tool for the networking community.
13 *
14 * Previous versions of tcptrace were released under a license that
15 * was much less restrictive with respect to how tcptrace could be
16 * used in commercial products. Because of this, I am willing to
17 * consider alternate license arrangements as allowed in Section 10 of
18 * the GNU GPL. Before I would consider licensing tcptrace under an
19 * alternate agreement with a particular individual or company,
20 * however, I would have to be convinced that such an alternative
21 * would be to the greater benefit of the networking community.
22 *
23 * ---
24 *
25 * This file is part of Tcptrace.
26 *
27 * Tcptrace was originally written and continues to be maintained by
28 * Shawn Ostermann with the help of a group of devoted students and
29 * users (see the file 'THANKS'). The work on tcptrace has been made
30 * possible over the years through the generous support of NASA GRC,
31 * the National Science Foundation, and Sun Microsystems.
32 *
33 * Tcptrace is free software; you can redistribute it and/or modify it
34 * under the terms of the GNU General Public License as published by
35 * the Free Software Foundation; either version 2 of the License, or
36 * (at your option) any later version.
37 *
38 * Tcptrace is distributed in the hope that it will be useful, but
39 * WITHOUT ANY WARRANTY; without even the implied warranty of
40 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41 * General Public License for more details.
42 *
43 * You should have received a copy of the GNU General Public License
44 * along with Tcptrace (in the file 'COPYING'); if not, write to the
45 * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
46 * MA 02111-1307 USA
47 *
48 * Author: Shawn Ostermann
49 * School of Electrical Engineering and Computer Science
50 * Ohio University
51 * Athens, OH
52 * ostermann@cs.ohiou.edu
53 * http://www.tcptrace.org/
54 */
55 #include "tcptrace.h"
56 static char const GCC_UNUSED copyright[] =
57 "@(#)Copyright (c) 2004 -- Ohio University.\n";
58 static char const GCC_UNUSED rcsid[] =
59 "@(#)$Header$";
60
61
62
63 /* info that I keep about each plotter */
64 struct plotter_info {
65 MFILE *fplot; /* the file that hold the plot */
66 tcb *p2plast; /* the TCB that this goes with (if any) */
67 timeval zerotime; /* first time stamp in this plot (see -z) */
68 char *filename; /* redundant copy of name for debugging */
69 Bool header_done; /* Flag indicating plotter header written to file */
70 Bool axis_switched; /* Switch x & y axis types.
71 * (Needed for Time Line Charts,
72 * Default = FALSE)
73 */
74 char *title; /* Plotter title */
75 char *xlabel; /* Plotter x-axis label */
76 char *ylabel; /* Plotter y-axis label */
77 };
78
79
80
81 /* locally global parameters */
82 static int max_plotters;
83 static PLOTTER plotter_ix = NO_PLOTTER;
84 static char *temp_color = NULL;
85 static struct plotter_info *pplotters;
86
87
88 /* local routine declarations */
89 static char *xp_timestamp(PLOTTER pl, struct timeval time);
90 static char *TSGPlotName(tcb *plast, PLOTTER, char *suffix);
91 static void DoPlot(PLOTTER pl, char *fmt, ...);
92 static void WritePlotHeader(PLOTTER pl);
93 static void CallDoPlot(PLOTTER pl, char *plot_cmd, int plot_argc, ...);
94
95
96 /*
97 * Return a string suitable for use as a timestamp in the xplot output.
98 * sdo fix: originally, we were just plotting to the accuracy of 1/10 ms
99 * this was mostly to help keep the .xpl files from being too large. However,
100 * on faster networks this just isn't enough, so we'll now use all 6 digits
101 * of the microsecond counter. Note that there's no guarantee that the
102 * timestamps are really all that accurate!
103 */
104 static char *
xp_timestamp(PLOTTER pl,struct timeval time)105 xp_timestamp(
106 PLOTTER pl,
107 struct timeval time)
108 {
109 #define NUM_BUFS 4
110 static char bufs[NUM_BUFS][20]; /* several of them for multiple calls in one printf */
111 static int bufix = 0;
112 unsigned secs;
113 unsigned usecs;
114 unsigned decimal;
115 char *pbuf;
116 struct plotter_info *ppi;
117
118 ppi = &pplotters[pl];
119
120 /* see if we're graphing from "0" OR if the axis type is switched */
121 if (graph_time_zero || ppi->axis_switched) {
122
123
124 if (ZERO_TIME(&ppi->zerotime)) {
125 /* set "zero point" */
126 ppi->zerotime = time;
127 }
128
129 /* (in)sanity check */
130 if (tv_lt(time,ppi->zerotime)) {
131 fprintf(stderr,"Internal error in plotting (plot file '%s')...\n\
132 ZERO-based X-axis plotting requested and elements are not plotted in\n\
133 increasing time order. Try without the '-z' flag\n",
134 ppi->filename);
135 /* exit(-5); */
136 time.tv_sec = time.tv_usec = 0;
137 } else {
138 /* computer offset from first plotter point */
139 tv_sub(&time, ppi->zerotime);
140 }
141 }
142
143 /* calculate time components */
144 secs = time.tv_sec;
145 usecs = time.tv_usec;
146 decimal = usecs;
147
148 /* use one of 4 rotating static buffers (for multiple calls per printf) */
149 bufix = (bufix+1)%NUM_BUFS;
150 pbuf = bufs[bufix];
151
152 snprintf(pbuf,sizeof(bufs[bufix]),"%u.%06u",secs,decimal);
153
154 return(pbuf);
155 }
156
157
158
159 void
plot_init(void)160 plot_init(void)
161 {
162 max_plotters = 256; /* just a default, make more on the fly */
163
164 pplotters = MallocZ(max_plotters * sizeof(struct plotter_info));
165 }
166
167
168 static void
plotter_makemore(void)169 plotter_makemore(void)
170 {
171 int new_max_plotters = max_plotters * 4;
172
173 if (debug)
174 fprintf(stderr,"plotter: making more space for %d total plotters\n",
175 new_max_plotters);
176
177 /* reallocate the memory to make more space */
178 pplotters = ReallocZ(pplotters,
179 max_plotters * sizeof(struct plotter_info),
180 new_max_plotters * sizeof(struct plotter_info));
181
182 max_plotters = new_max_plotters;
183 }
184
185
186
187
188 /* max number of letters in endpoint name */
189 /* (8 allows 26**8 different endpoints (209,000,000,000)
190 probably plenty for now!!!!!) */
191
192 /* #define MAX_HOSTLETTER_LEN 8
193 Moving this definition to tcptrace.h so other modules can use it. */
194
195 char *
HostLetter(llong ix)196 HostLetter(
197 llong ix)
198 {
199 static char name[MAX_HOSTLETTER_LEN+1];
200 static char *pname;
201
202 /* basically, just convert to base 26 */
203 pname = &name[sizeof(name)-1];
204 *pname-- = '\00';
205 while (pname >= name) {
206 unsigned digit = ix % 26;
207 *pname-- = 'a'+digit;
208 ix = (ix / 26) - 1;
209 if (ix == -1)
210 return(pname+1);
211 }
212 fprintf(stderr,"Fatal, too many hosts to name (max length %d)\n\nNOTE:\nIf you are using gcc version 2.95.3, then this may be a compiler bug. This particular version\nis known to generate incorrect assembly code when used with CCOPT=-O2.\nSuggested fixes are:\n 1. Update gcc to the latest version and recompile tcptrace.\n 2. Use the same version of gcc, but edit the tcptrace Makefile, setting CCOPT=-O instead of\n CCOPT=-O2, and then recompile tcptrace.\nEither of these steps should hopefully fix the problem.\n\n", MAX_HOSTLETTER_LEN);
213 exit(-1);
214 return(NULL); /* NOTREACHED */
215 }
216
217
218 char *
NextHostLetter(void)219 NextHostLetter(void)
220 {
221 static llong count = 0;
222 return(HostLetter(count++));
223 }
224
225
226
227 static char *
TSGPlotName(tcb * plast,PLOTTER pl,char * suffix)228 TSGPlotName(
229 tcb *plast,
230 PLOTTER pl,
231 char *suffix)
232 {
233 static char filename[25];
234
235
236 snprintf(filename,sizeof(filename),"%s2%s%s",
237 plast->host_letter, plast->ptwin->host_letter, suffix);
238
239 return(filename);
240 }
241
242
243
244 static void
DoPlot(PLOTTER pl,char * fmt,...)245 DoPlot(
246 PLOTTER pl,
247 char *fmt,
248 ...)
249 {
250 va_list ap;
251 MFILE *f = NULL;
252 struct plotter_info *ppi;
253
254 va_start(ap,fmt);
255
256 /* if (!graph_tsg) */
257 /* return; */
258
259 if (pl == NO_PLOTTER) {
260 va_end(ap);
261 return;
262 }
263
264 if (pl > plotter_ix) {
265 fprintf(stderr,"Illegal plotter: %d\n", pl);
266 exit(-1);
267 }
268
269 ppi = &pplotters[pl];
270
271 if ((f = ppi->fplot) == NULL) {
272 va_end(ap);
273 return;
274 }
275
276 /* Write the plotter header if not already written */
277 if(!ppi->header_done)
278 WritePlotHeader(pl);
279
280 Mvfprintf(f,fmt,ap);
281 if (temp_color) {
282 Mfprintf(f," %s",temp_color);
283 temp_color = NULL;
284 }
285 Mfprintf (f,"\n");
286
287 va_end(ap);
288
289 return;
290 }
291
292
293 PLOTTER
new_plotter(tcb * plast,char * filename,char * title,char * xlabel,char * ylabel,char * suffix)294 new_plotter(
295 tcb *plast,
296 char *filename, /* if NULL, use default name from plast */
297 char *title,
298 char *xlabel,
299 char *ylabel,
300 char *suffix)
301 {
302 PLOTTER pl;
303 MFILE *f;
304 struct plotter_info *ppi;
305
306 ++plotter_ix;
307 if (plotter_ix >= max_plotters) {
308 plotter_makemore();
309 }
310
311 pl = plotter_ix;
312 ppi = &pplotters[pl];
313
314 if (filename == NULL)
315 filename = TSGPlotName(plast,pl,suffix);
316 else if (suffix != NULL) {
317 char buf[100];
318 snprintf(buf,sizeof(buf),"%s%s", filename, suffix);
319 filename = buf;
320 }
321
322 if (debug)
323 fprintf(stderr,"Plotter %d file is '%s'\n", pl, filename);
324
325 if ((f = Mfopen(filename,"w")) == NULL) {
326 perror(filename);
327 return(NO_PLOTTER);
328 }
329
330 ppi->fplot = f;
331 ppi->p2plast = plast;
332 ppi->filename = strdup(filename);
333 ppi->axis_switched = FALSE;
334 ppi->header_done = FALSE;
335
336 /* Save these fields to be writtn to the plotter header later in DoPlot() */
337 ppi->title = strdup(title);
338 ppi->xlabel = strdup(xlabel);
339 ppi->ylabel = strdup(ylabel);
340
341 return(pl);
342 }
343
344
345 void
plotter_done(void)346 plotter_done(void)
347 {
348 PLOTTER pl;
349 MFILE *f;
350 char *fname;
351 static struct dstring *xplot_cmd_buff=NULL;
352
353 if(plotter_ix>0) {
354 if(xplot_all_files) {
355 xplot_cmd_buff=DSNew();
356 DSAppendString(xplot_cmd_buff,"xplot");
357 DSAppendString(xplot_cmd_buff," ");
358 if(xplot_args!=NULL) {
359 DSAppendString(xplot_cmd_buff,xplot_args);
360 DSAppendString(xplot_cmd_buff," ");
361 }
362 }
363 }
364
365 for (pl = 0; pl <= plotter_ix; ++pl) {
366 struct plotter_info *ppi = &pplotters[pl];
367
368
369 if ((f = ppi->fplot) == NULL)
370 continue;
371
372 /* Write the plotter header if not already written */
373 if(!ppi->header_done)
374 WritePlotHeader(pl);
375
376 if (!ignore_non_comp ||
377 ((ppi->p2plast != NULL) && (ConnComplete(ppi->p2plast->ptp)))) {
378 Mfprintf(f,"go\n");
379 Mfclose(f);
380 } else {
381 fname = ppi->p2plast->tsg_plotfile;
382 if (debug)
383 fprintf(stderr,"Removing incomplete plot file '%s'\n",
384 fname);
385 Mfclose(f);
386 if (unlink(fname) != 0)
387 perror(fname);
388 }
389
390 if(xplot_all_files){
391 if(output_file_dir!=NULL) {
392 DSAppendString(xplot_cmd_buff,output_file_dir);
393 DSAppendString(xplot_cmd_buff,"/");
394 }
395 DSAppendString(xplot_cmd_buff,ppi->filename);
396 DSAppendString(xplot_cmd_buff," ");
397 }
398 }
399
400 if(plotter_ix>0) {
401 if(xplot_all_files) {
402 fprintf(stdout,"%s\n",DSVal(xplot_cmd_buff));
403 system(DSVal(xplot_cmd_buff));
404 DSDestroy(&xplot_cmd_buff);
405 }
406 }
407 }
408
409
410
411 void
plotter_temp_color(PLOTTER pl,char * color)412 plotter_temp_color(
413 PLOTTER pl,
414 char *color)
415 {
416 if (colorplot)
417 temp_color = color;
418 }
419
420
421 void
plotter_perm_color(PLOTTER pl,char * color)422 plotter_perm_color(
423 PLOTTER pl,
424 char *color)
425 {
426 if (colorplot)
427 CallDoPlot(pl, color, 0);
428 }
429
430
431 void
plotter_line(PLOTTER pl,struct timeval t1,u_long x1,struct timeval t2,u_long x2)432 plotter_line(
433 PLOTTER pl,
434 struct timeval t1,
435 u_long x1,
436 struct timeval t2,
437 u_long x2)
438 {
439 CallDoPlot(pl,"line", 4, t1, x1, t2, x2);
440 }
441
442
443 void
plotter_dline(PLOTTER pl,struct timeval t1,u_long x1,struct timeval t2,u_long x2)444 plotter_dline(
445 PLOTTER pl,
446 struct timeval t1,
447 u_long x1,
448 struct timeval t2,
449 u_long x2)
450 {
451 CallDoPlot(pl,"dline", 4, t1, x1, t2, x2);
452 }
453
454
455 void
plotter_diamond(PLOTTER pl,struct timeval t,u_long x)456 plotter_diamond(
457 PLOTTER pl,
458 struct timeval t,
459 u_long x)
460 {
461 CallDoPlot(pl,"diamond", 2, t, x);
462 }
463
464
465 void
plotter_dot(PLOTTER pl,struct timeval t,u_long x)466 plotter_dot(
467 PLOTTER pl,
468 struct timeval t,
469 u_long x)
470 {
471 CallDoPlot(pl,"dot", 2, t, x);
472 }
473
474
475 void
plotter_plus(PLOTTER pl,struct timeval t,u_long x)476 plotter_plus(
477 PLOTTER pl,
478 struct timeval t,
479 u_long x)
480 {
481 CallDoPlot(pl,"plus", 2, t, x);
482 }
483
484
485 void
plotter_box(PLOTTER pl,struct timeval t,u_long x)486 plotter_box(
487 PLOTTER pl,
488 struct timeval t,
489 u_long x)
490 {
491 CallDoPlot(pl,"box", 2, t, x);
492 }
493
494
495
496 void
plotter_arrow(PLOTTER pl,struct timeval t,u_long x,char dir)497 plotter_arrow(
498 PLOTTER pl,
499 struct timeval t,
500 u_long x,
501 char dir)
502 {
503 char arrow_type[7];
504 snprintf(arrow_type, sizeof(arrow_type), "%carrow", dir);
505 CallDoPlot(pl, arrow_type, 2, t, x);
506 }
507
508
509 void
plotter_uarrow(PLOTTER pl,struct timeval t,u_long x)510 plotter_uarrow(
511 PLOTTER pl,
512 struct timeval t,
513 u_long x)
514 {
515 plotter_arrow(pl,t,x,'u');
516 }
517
518
519 void
plotter_darrow(PLOTTER pl,struct timeval t,u_long x)520 plotter_darrow(
521 PLOTTER pl,
522 struct timeval t,
523 u_long x)
524 {
525 plotter_arrow(pl,t,x,'d');
526 }
527
528
529 void
plotter_rarrow(PLOTTER pl,struct timeval t,u_long x)530 plotter_rarrow(
531 PLOTTER pl,
532 struct timeval t,
533 u_long x)
534 {
535 plotter_arrow(pl,t,x,'r');
536 }
537
538
539 void
plotter_larrow(PLOTTER pl,struct timeval t,u_long x)540 plotter_larrow(
541 PLOTTER pl,
542 struct timeval t,
543 u_long x)
544 {
545 plotter_arrow(pl,t,x,'l');
546 }
547
548
549 void
plotter_tick(PLOTTER pl,struct timeval t,u_long x,char dir)550 plotter_tick(
551 PLOTTER pl,
552 struct timeval t,
553 u_long x,
554 char dir)
555 {
556 char tick_type[6];
557 snprintf(tick_type, sizeof(tick_type), "%ctick", dir);
558 CallDoPlot(pl, tick_type, 2, t, x);
559 }
560
561
562 void
plotter_dtick(PLOTTER pl,struct timeval t,u_long x)563 plotter_dtick(
564 PLOTTER pl,
565 struct timeval t,
566 u_long x)
567 {
568 plotter_tick(pl,t,x,'d');
569 }
570
571
572 void
plotter_utick(PLOTTER pl,struct timeval t,u_long x)573 plotter_utick(
574 PLOTTER pl,
575 struct timeval t,
576 u_long x)
577 {
578 plotter_tick(pl,t,x,'u');
579 }
580
581
582 void
plotter_ltick(PLOTTER pl,struct timeval t,u_long x)583 plotter_ltick(
584 PLOTTER pl,
585 struct timeval t,
586 u_long x)
587 {
588 plotter_tick(pl,t,x,'l');
589 }
590
591
592 void
plotter_rtick(PLOTTER pl,struct timeval t,u_long x)593 plotter_rtick(
594 PLOTTER pl,
595 struct timeval t,
596 u_long x)
597 {
598 plotter_tick(pl,t,x,'r');
599 }
600
601
602 void
plotter_htick(PLOTTER pl,struct timeval t,u_long x)603 plotter_htick(
604 PLOTTER pl,
605 struct timeval t,
606 u_long x)
607 {
608 plotter_tick(pl,t,x,'h');
609 }
610
611
612 void
plotter_vtick(PLOTTER pl,struct timeval t,u_long x)613 plotter_vtick(
614 PLOTTER pl,
615 struct timeval t,
616 u_long x)
617 {
618 plotter_tick(pl,t,x,'v');
619 }
620
621
622
623 /* don't plot ANYTHING, just make sure ZERO point is set! */
624 void
plotter_nothing(PLOTTER pl,struct timeval t)625 plotter_nothing(
626 PLOTTER pl,
627 struct timeval t)
628 {
629 char *ret;
630 ret = xp_timestamp(pl,t);
631 if (debug > 10)
632 printf("plotter_nothing(%s) gets '%s'\n", ts2ascii(&t), ret);
633 }
634
635
636
637 void
plotter_text(PLOTTER pl,struct timeval t,u_long x,char * where,char * str)638 plotter_text(
639 PLOTTER pl,
640 struct timeval t,
641 u_long x,
642 char *where,
643 char *str)
644 {
645 char text_type[6];
646 snprintf(text_type, sizeof(text_type), "%stext", where);
647
648 CallDoPlot(pl, text_type, 2, t, x);
649 /* fix by Bill Fenner - Wed Feb 5, 1997, thanks */
650 /* This is a little ugly. Text commands take 2 lines. */
651 /* A temporary color could have been */
652 /* inserted after that line, but would NOT be inserted after */
653 /* the next line, so we'll be OK. I can't think of a better */
654 /* way right now, and this works fine (famous last words) */
655 CallDoPlot(pl, str, 0);
656 }
657
658 void
plotter_invisible(PLOTTER pl,struct timeval t,u_long x)659 plotter_invisible(
660 PLOTTER pl,
661 struct timeval t,
662 u_long x)
663 {
664 CallDoPlot(pl,"invisible", 2, t, x);
665 }
666
667
668 /* high-level line-drawing package */
669 struct pl_line {
670 char *color;
671 char *label;
672 int last_y;
673 timeval last_time;
674 PLOTTER plotter;
675 Bool labelled;
676 };
677
678
679 PLINE
new_line(PLOTTER plotter,char * label,char * color)680 new_line(
681 PLOTTER plotter,
682 char *label,
683 char *color)
684 {
685 struct pl_line *pl;
686
687 pl = MallocZ(sizeof(struct pl_line));
688 pl->plotter = plotter;
689 pl->label = label;
690 pl->color = color;
691
692 return(pl);
693 }
694
695
696 void
extend_line(PLINE pline,timeval xval,int yval)697 extend_line(
698 PLINE pline,
699 timeval xval,
700 int yval)
701 {
702 PLOTTER p;
703
704 if (!pline)
705 return;
706
707 p = pline->plotter;
708
709 #ifdef OLD
710 /* attach a label to the first non-zero point */
711 if (!pline->labelled) {
712 if (yval != 0) {
713 plotter_temp_color(p, pline->color);
714 plotter_text(p, xval, yval, "l", pline->label);
715 pline->labelled = 1;
716 }
717 }
718 #endif
719
720 /* attach a label midway on the first line segment above 0 */
721 /* for whom the second point is NOT 0 */
722 if (!pline->labelled) {
723 if ((yval != 0) && (!ZERO_TIME(&pline->last_time))) {
724 timeval tv_elapsed;
725 timeval tv_avg;
726 int avg_yval;
727
728 /* computer elapsed time for these 2 points */
729 tv_elapsed = xval;
730 tv_sub(&tv_elapsed,pline->last_time);
731
732 /* divide elapsed time by 2 */
733 tv_elapsed.tv_sec /= 2;
734 tv_elapsed.tv_usec /= 2;
735
736 /* add 1/2 of the elapsed time to the oldest point */
737 /* (giving us the average time) */
738 tv_avg = pline->last_time;
739 tv_add(&tv_avg, tv_elapsed);
740
741 /* average the Y values */
742 avg_yval = (1 + pline->last_y+yval)/2;
743 /* (rounding UP, please) */
744
745 /* draw the label */
746 plotter_temp_color(p, pline->color);
747 plotter_text(p, tv_avg, avg_yval, "l", pline->label);
748
749 /* remember that it's been done */
750 pline->labelled = 1;
751 }
752 }
753
754 /* draw a dot at the current point */
755 plotter_perm_color(p, pline->color);
756 plotter_dot(p, xval, yval);
757
758 /* if this isn't the FIRST point, connect with a line */
759 if (!ZERO_TIME(&pline->last_time)) {
760 plotter_line(p,
761 xval, yval,
762 pline->last_time, pline->last_y);
763 }
764
765 /* remember this point for the next line segment */
766 pline->last_time = xval;
767 pline->last_y = yval;
768 }
769
770 /* This function may be called with 0, 2 or 4 arguments depending on plot command. */
771 static void
CallDoPlot(PLOTTER pl,char * plot_cmd,int plot_argc,...)772 CallDoPlot(
773 PLOTTER pl,
774 char *plot_cmd,
775 int plot_argc,
776 ...)
777 {
778 struct timeval t1;
779 u_long x1 = 0;
780 struct timeval t2;
781 u_long x2 = 0;
782 va_list ap;
783 struct plotter_info *ppi;
784 char fmt[200];
785
786 if (pl == NO_PLOTTER)
787 return;
788
789 if (pl > plotter_ix) {
790 fprintf(stderr,"Illegal plotter: %d\n", pl);
791 exit(-1);
792 }
793
794 ppi = &pplotters[pl];
795
796 /* Get the arguments from the variable list */
797 va_start(ap, plot_argc);
798 if(plot_argc > 0)
799 {
800 t1 = va_arg(ap, struct timeval);
801 x1 = va_arg(ap, u_long);
802 }
803 if(plot_argc > 2)
804 {
805 t2 = va_arg(ap, struct timeval);
806 x2 = va_arg(ap, u_long);
807 }
808 va_end(ap);
809
810 memset(fmt, 0, sizeof(fmt));
811
812 if(ppi->axis_switched) {
813 switch(plot_argc) {
814 case 0:
815 snprintf(fmt, sizeof(fmt), "%s", plot_cmd);
816 DoPlot(pl, fmt);
817 break;
818 case 2:
819 snprintf(fmt, sizeof(fmt), "%s %%u -%%s", plot_cmd);
820 DoPlot(pl, fmt,
821 x1, xp_timestamp(pl,t1));
822 break;
823 case 4:
824 snprintf(fmt, sizeof(fmt), "%s %%u -%%s %%u -%%s", plot_cmd);
825 DoPlot(pl, fmt,
826 x1, xp_timestamp(pl,t1),
827 x2, xp_timestamp(pl,t2));
828 break;
829 default:
830 fprintf(stderr, "CallDoPlot: Illegal number of arguments (%d)\n", plot_argc);
831 }
832 }
833 else {
834 switch(plot_argc) {
835 case 0:
836 snprintf(fmt, sizeof(fmt), "%s", plot_cmd);
837 DoPlot(pl, fmt);
838 break;
839 case 2:
840 snprintf(fmt, sizeof(fmt), "%s %%s %%u", plot_cmd);
841 DoPlot(pl, fmt,
842 xp_timestamp(pl,t1), x1);
843 break;
844 case 4:
845 snprintf(fmt, sizeof(fmt), "%s %%s %%u %%s %%u", plot_cmd);
846 DoPlot(pl, fmt,
847 xp_timestamp(pl,t1), x1,
848 xp_timestamp(pl,t2), x2);
849 break;
850 default:
851 fprintf(stderr, "CallDoPlot: Illegal number of arguments (%d)\n", plot_argc);
852 }
853 }
854
855 return;
856 }
857
858 static void
WritePlotHeader(PLOTTER pl)859 WritePlotHeader(
860 PLOTTER pl)
861 {
862 MFILE *f = NULL;
863 struct plotter_info *ppi;
864
865 if (pl == NO_PLOTTER)
866 return;
867
868 if (pl > plotter_ix) {
869 fprintf(stderr,"Illegal plotter: %d\n", pl);
870 exit(-1);
871 }
872
873 ppi = &pplotters[pl];
874
875 if ((f = ppi->fplot) == NULL)
876 return;
877
878 if(ppi->axis_switched) {
879 /* Header for the Time Line Charts */
880 Mfprintf(f,"%s %s\n", "unsigned", "dtime");
881 }
882 else {
883 /* Header for all other plots */
884 /* graph coordinates... */
885 /* X coord is timeval unless graph_time_zero is true */
886 /* Y is signed except when it's a sequence number */
887 /* ugly hack -- unsigned makes the graphs hard to work with and is
888 only needed for the time sequence graphs */
889 /* suggestion by Michele Clark at UNC - make them double instead */
890 Mfprintf(f,"%s %s\n",
891 graph_time_zero?"dtime":"timeval",
892 ((strcmp(ppi->ylabel,"sequence number") == 0)&&(!graph_seq_zero))?
893 "double":"signed");
894 }
895
896 if (show_title) {
897 if (xplot_title_prefix)
898 Mfprintf(f,"title\n%s %s\n",
899 ExpandFormat(xplot_title_prefix),
900 ppi->title);
901 else
902 Mfprintf(f,"title\n%s\n", ppi->title);
903 }
904
905 Mfprintf(f,"xlabel\n%s\n", ppi->xlabel);
906 Mfprintf(f,"ylabel\n%s\n", ppi->ylabel);
907
908 /* Indicate that the header has now been written to the plotter file */
909 ppi->header_done = TRUE;
910
911 return;
912 }
913
914 /* Switch the x and y axis type (Needed for Time Line Charts. Default = FLASE) */
plotter_switch_axis(PLOTTER pl,Bool flag)915 void plotter_switch_axis(
916 PLOTTER pl,
917 Bool flag)
918 {
919 struct plotter_info *ppi = &pplotters[pl];
920
921 ppi->axis_switched = flag;
922 }
923
924