The LevAWC Project
 All Data Structures Files Functions Variables Typedefs Enumerations Macros Pages
demo14.c
1 /*
2  * _____
3  * ANSI / ___/
4  * / /__
5  * \___/
6  *
7  * Filename: demo14.c
8  * Author : Dan Levin
9  * Date : Fri Feb 20 13:26:47 2015
10  * Version : 0.51
11  * ---
12  * Description: A demo program for testing/showing Dijkstra's Shortest Path
13  * Algorithm - as "The EU City Criss Cross Tour".
14  *
15  * Revision history: (this is where you document the diffs between versions...)
16  * Date Revision
17  * 150206 This source is created for version 0.51..
18  *
19  *
20  */
21 
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <time.h>
25 #include "graph.h"
26 #include "algo.h"
27 #include "utils.h"
28 
29 #ifndef OK
30 #define OK 0
31 #endif
32 
33 #define KEYSIZ BUFSIZ/4
34 #define ERRSIZ BUFSIZ/4
35 #define COMMENTCHAR '#'
36 #define MYFILLCHAR '-'
37 
38 /* Global variables */
39 
40 int row_ctr;
41 
42 typedef struct MyCitydata_
43 {
44  int id;
45  char name[KEYSIZ];
46 } *MyCitydata;
47 
48 /* String macro for the main menu... */
49 #define MAIN_MENU_ROW "--- EU CITY CRISS-CROSS TOUR DEMO ---\nMENU: 0=Exit 1=Make_Tour 2=Min_Span_Tree 3=Print_Graph\nSelection"
50 
51 /* FUNCTION-DECLARATIONS */
52 /* Application-specifik callbacks */
53 void my_destroy(void *data); /* Callback for deallocating vertex memory */void print(const void *data);
54 int my_match(const void *, const void *); /* Callback for matching vertices */
55 int my_cmp(const void *key1, /* Callback for comparing vetices */
56  const void *key2);
57 int my_chchk(int ch); /* Callback for testing char input */
58 void vtx_prt(const void *vtxdata); /* Callback for printing vertex data */
59 void edge_prt(const void *edgedata); /* Callback for printing edge data */
60 
61 /* Menu selection (handling) functions */
62 void make_tour(Graph gr); /* Make a tour - and calculate shortest path.. */
63 void min_span_tree(Graph gr); /* Calculate the Minimum Spanning Tree */
64 void final_status(Graph gr); /* Final status.. */
65 
66 /* Misc. application functions.. */
67 int read_graphdata(Graph gr, char *filename); /* Read graph(=vertex/edge) data from textfile */
68 int read_vertices(Graph gr, FILE *fp); /* Read vertex data */
69 int read_edges(Graph gr, FILE *fp); /* Read edge data */
70 void printroute(DspVertexdata spvtx); /* Print route info */
71 void error_mess(const char *str); /* Output error messages on stderr */
72 void print_vertices(Graph gr); /* Print all vertices(=destinations) on screen */
73 void prt_fill(char *str, char fillchar, /* Right fill a string field up to length 'fieldlen' with 'fillchar' */
74  int fieldlen);
75 
76 /* END-OF-FUNCTION-DECLARATIONS */
77 
78 /* FUNCTION DEFINITIONS - the rest of the program */
79 /* --- Function: void my_destroy(void *data) --- */
80 void my_destroy(void *data)
81 {
82  DspVertexdata vdata;
83  MyCitydata mcd;
84 
85  vdata = (DspVertexdata)data;
86  mcd = (MyCitydata)(vdata->data);
87  free(mcd);
88  free(vdata);
89 }
90 
91 /* --- Function: int my_chchk(int ch) --- */
92 int my_chchk(int ch)
93 {
94  return strchr("YyNn", ch) ? 1 : 0;
95 }
96 
97 /* --- Function: void printvtx(const void *data) --- */
98 void printvtx(const void *data)
99 {
100  DspVertexdata vdata;
101  MyCitydata mcd;
102 
103  vdata = (DspVertexdata)data;
104  mcd = (MyCitydata)(vdata->data);
105 
106  printf("%02d", mcd->id);
107 }
108 
109 /* --- Function: void printvtx(const void *data) --- */
110 void printedge(const void *data)
111 {
112  DspVertexdata vdata;
113  MyCitydata mcd;
114 
115  vdata = (DspVertexdata)data;
116  mcd = (MyCitydata)(vdata->data);
117 
118  printf("%02d|%-3.3s|", mcd->id, mcd->name);
119 }
120 
121 /* --- Function: int my_match(const void *k1, const void *k2) --- */
122 int my_match(const void *k1, const void *k2)
123 {
124  DspVertexdata vdata;
125  MyCitydata mcd1, mcd2;
126 
127  vdata = (DspVertexdata)k1;
128  mcd1 = (MyCitydata)(vdata->data);
129  vdata = (DspVertexdata)k2;
130  mcd2 = (MyCitydata)(vdata->data);
131 
132  return mcd1->id == mcd2->id;
133 }
134 
135 /* --- Function: int my_cmp(const int *key1, const int *key2) --- */
136 int my_cmp(const void *key1, const void *key2)
137 {
138  DspVertexdata vdata;
139  MyCitydata mcd1, mcd2;
140 
141  vdata = (DspVertexdata)key1;
142  mcd1 = (MyCitydata)(vdata->data);
143  vdata = (DspVertexdata)key2;
144  mcd2 = (MyCitydata)(vdata->data);
145 
146  return mcd1->id - mcd2->id;
147 }
148 
149 int read_graphdata(Graph gr, char *filename)
150 {
151  FILE *fp;
152  char errmess[ERRSIZ];
153 
154  FILCHK((fp = fopen(filename, "rt")));
155 
156  if (read_vertices(gr, fp) != OK)
157  {
158  sprintf(errmess, "\nError when reading data(=vertices) from file %s!", filename);
159  error_mess(errmess); /* Print error message */
160  fclose(fp); /* Close data file */
161  exit(EXIT_FAILURE);
162  }
163 
164  rewind(fp);
165 
166  if (read_edges(gr, fp) != OK)
167  {
168  sprintf(errmess, "\nError when reading data(=edges) from file %s!", filename);
169  error_mess(errmess); /* Print error message */
170  fclose(fp); /* Close data file */
171  exit(EXIT_FAILURE);
172  }
173 
174  fclose(fp);
175 
176  /* Everything is OK */
177  return 0;
178 }
179 
180 int read_vertices(Graph gr, FILE *fp)
181 {
182  char buf[BUFSIZ], bufcopy[BUFSIZ], tmp[KEYSIZ];
183  char *commentptr, *pc;
184  char errmess[ERRSIZ];
185  DspVertexdata vtxdata;
186  MyCitydata my_city;
187 
188  int retval;
189 
190  /* Read rows from datafile into row buffer 'buf'.. */
191  while (fgets(buf, BUFSIZ, fp) != NULL)
192  {
193  /* Remove comments from buffer */
194  if ((commentptr = strchr(buf, COMMENTCHAR)) != NULL)
195  *commentptr = '\0';
196 
197  /* Get rid of starting or trailing blank characters in buffer */
198  strtrim(buf, isspace, isspace);
199 
200  /* If buffer is NOT empty... */
201  if (*buf)
202  {
203  /* Save a copy of input buffer */
204  strcpy(bufcopy, buf);
205 
206  /* Read the first field.. */
207  pc = strtok(buf, ",;");
208 
209  /* Allocate memory for a vertex - with error handling.. */
210  /* Data type 'struct DspVertexdata_' - defined in file 'algo.h'.. */
211  MALCHK((vtxdata = malloc(sizeof(struct DspVertexdata_))));
212  /* Data type 'struct MyCitydata_' - defined above.. */
213  MALCHK((my_city = malloc(sizeof(struct MyCitydata_))));
214  /* Link the structures together.. */
215  vtxdata->data = my_city;
216 
217  /* Copy field data into temp. field buffer... */
218  strcpy(tmp, pc);
219  strtrim(tmp, isspace, isspace);
220 
221  /* If wrong format - OR - temp. buffer empty.. */
222  if (!isunsignedfloat(tmp) || *tmp=='\0') /* Bailing out... */
223  {
224  sprintf(errmess, "\nData error - when reading key data(=%s) - on this line:\n%s",
225  tmp, bufcopy);
226  error_mess(errmess); /* Print error message */
227  /* Free city memory */
228  free(my_city);
229  /* Free vertex memory */
230  free(vtxdata);
231  exit(EXIT_FAILURE);
232  }
233 
234  /* Copy and convert temp. field buffer into vertex structure... */
235  my_city->id = atoi(tmp);
236 
237  /* Read next field... */
238  pc = strtok(NULL, ",;");
239 
240  /* If field data exists.. */
241  if (*pc)
242  {
243  /* Copy & trim field into vertex structure.. */
244  strcpy(my_city->name, pc);
245  strtrim(my_city->name, isspace, isspace);
246  }
247  else /* Bailing out... */
248  {
249  sprintf(errmess, "\nData missing - when reading data(=%s) - on this line:\n%s",
250  pc, bufcopy);
251  error_mess(errmess); /* Print error message */
252  /* Free dyn. allocated memory */
253  my_destroy(vtxdata);
254  exit(EXIT_FAILURE);
255  }
256 
257  /* Insert vertex into graph - with error control */
258  if ((retval = GRAPHinsvertex(gr, vtxdata)) != OK)
259  {
260  /* Prepare and output error message */
261  sprintf(errmess, "\nError when inserting vertex data into graph - from this line:\n%s", bufcopy);
262  error_mess(errmess);
263  /* Free dyn. allocated memory */
264  my_destroy(vtxdata);
265  /* Return error code.. */
266  return retval;
267  }
268  }
269  }
270  /* Everything is OK */
271  return 0;
272 }
273 
274 int read_edges(Graph gr, FILE *fp)
275 {
276  int state, fldctr;
277  char buf[BUFSIZ], bufcopy[BUFSIZ], tmp[KEYSIZ];
278  char *commentptr, *pc;
279  char errmess[ERRSIZ];
280  struct DspVertexdata_ tmpvtxdata, tmpedgedata;
281  struct MyCitydata_ cty_data, cty_data2;
282  VertexNode vtxnode;
283  /* EdgeNode enode; */
284  DspVertexdata edata, tmpdata;
285  MyCitydata mycitydata;
286  int retval;
287 
288  /* Link 2 tmp structures together... */
289  tmpvtxdata.data = &cty_data;
290  tmpedgedata.data = &cty_data2;
291 
292  /* Read rows from datafile into row buffer 'buf'.. */
293  while (fgets(buf, BUFSIZ, fp) != NULL)
294  {
295  /* Remove comments from buffer */
296  if ((commentptr = strchr(buf, COMMENTCHAR)) != NULL)
297  *commentptr = '\0';
298 
299  /* Get rid of starting or trailing blank characters in buffer */
300  strtrim(buf, isspace, isspace);
301 
302  /* If buffer is NOT empty... */
303  if (*buf)
304  {
305  /* Save a copy of input row buffer */
306  strcpy(bufcopy, buf);
307 
308  /* Read the first field.. */
309  pc = strtok(buf, ",;");
310 
311  /* Copy field data into temp. field buffer... */
312  strcpy(tmp, pc);
313  strtrim(tmp, isspace, isspace);
314 
315  /* If wrong format - OR - temp. buffer empty.. */
316  if (!isunsigned(tmp) || *tmp=='\0') /* Bailing out... */
317  {
318  sprintf(errmess, "\nData error - when reading key data(=%s) - on this line:\n%s",
319  tmp, bufcopy);
320  error_mess(errmess); /* Print error message */
321  exit(EXIT_FAILURE);
322  }
323 
324  /* Copy and convert temp. field buffer into temp. vertex structure... */
325  cty_data.id = atoi(tmp);
326 
327  /* Read next field - and dump it... */
328  pc = strtok(NULL, ",;");
329 
330  /* If field data is missing.. */
331  if (pc == NULL)
332  {
333  sprintf(errmess, "\nData missing - when reading data - on this line:\n%s", bufcopy);
334  error_mess(errmess); /* Print error message */
335  exit(EXIT_FAILURE);
336  }
337 
338  /* Now - start reading edge data.. */
339  state = 1; /* Set state to 1 initially */
340  fldctr = 1; /* Set field counter to 1 inintially */
341 
342  while ((pc = strtok(NULL, ",;")) != NULL)
343  {
344  switch (state)
345  {
346  case 1: /* Read edge key */
347  /* Allocate memory for edge - with error handling.. */
348  MALCHK((edata = malloc(sizeof(struct DspVertexdata_))));
349  MALCHK((mycitydata = malloc(sizeof(struct DspVertexdata_))));
350 
351  /* Link the 2 dyn. allocated structures together */
352  edata->data = mycitydata;
353 
354  /* Copy field data into temp. field buffer.. */
355  strcpy(tmp, pc);
356  strtrim(tmp, isspace, isspace); /* Trimming.. */
357 
358  /* If wrong format - OR - temp. buffer empty.. */
359  if (!isunsigned(tmp) || *tmp=='\0') /* Bailing out... */
360  {
361  sprintf(errmess, "\nData error - when reading key data(=%s) - on this line:\n%s",
362  tmp, bufcopy);
363  error_mess(errmess); /* Print error message */
364  /* Free dyn. allocated memory */
365  my_destroy(edata);
366  exit(EXIT_FAILURE);
367  }
368 
369  /* Copy and convert temp. field buffer into edge structure... */
370  mycitydata->id = atoi(tmp);
371 
372  /* Get additional data from vertex, which is one part of the current edge.. */
373  /* edgetmp.key = pedge->key; */
374  cty_data2.id = mycitydata->id;
375 
376  /* Look it up in the graph.. */
377  vtxnode = GRAPHfindvertex(gr, &tmpedgedata);
378  assert(vtxnode!=NULL);
379 
380  /* If found - copy field data - from vertexdata to edgedata.. */
381  if ((tmpdata = (DspVertexdata)GRAPHgetvertexdata(vtxnode)) != NULL)
382  strcpy(mycitydata->name, ((MyCitydata)(tmpdata->data))->name);
383 
384  state = 2;
385  break;
386 
387  case 2: /* Read weight */
388  strcpy(tmp, pc);
389  strtrim(tmp, isspace, isspace);
390 
391  if (!isunsignedfloat(tmp) || *tmp=='\0')
392  {
393  sprintf(errmess, "\nData error - when reading edge weight data(=%s) - on this line:\n%s", tmp, bufcopy);
394  error_mess(errmess); /* Print error message */
395  /* Free dyn. allocated memory */
396  my_destroy(edata);
397  exit(EXIT_FAILURE);
398  }
399  edata->weight = atof(tmp);
400 
401  /* Insert edge into graph... */
402  if ((retval = GRAPHinsedge(gr, &tmpvtxdata, edata)) != OK)
403  {
404  sprintf(errmess, "\nError when inserting edge from %d to %d - on this line:\n%s",
405  cty_data.id, mycitydata->id, bufcopy);
406  error_mess(errmess);
407  /* Free dyn. allocated memory */
408  my_destroy(edata);
409  return retval;
410  }
411  state = 1;
412  break;
413  }
414  fldctr++; /* Increment the field counter */
415  }
416 
417  if (!(fldctr%2)) /* If field counter is even.. */
418  {
419  sprintf(errmess, "\nData corrupt (wrong number of fields?) - on this line:\n%s", bufcopy);
420  error_mess(errmess);
421  /* Free dyn. allocated memory */
422  my_destroy(edata);
423  exit(EXIT_FAILURE);
424  }
425  }
426  }
427 
428  /* Everything is OK */
429  return 0;
430 }
431 
432 void printroute(DspVertexdata vtxdata)
433 {
434  MyCitydata cty_data;
435 
436  if (vtxdata == NULL)
437  return;
438  printroute(vtxdata->parent);
439 
440  cty_data = (MyCitydata)(vtxdata->data);
441  printf("%02d %-10.10s --> %.1f km\n", cty_data->id, cty_data->name, vtxdata->distance);
442 }
443 
444 void error_mess(const char *str)
445 {
446  fprintf(stderr, "%s\n", str);
447 }
448 
449 void vtx_prt(const void *vtxdata)
450 {
451  DspVertexdata vdata;
452  MyCitydata cty_data;
453 
454  vdata = (DspVertexdata)vtxdata;
455  cty_data = (MyCitydata)(vdata->data);
456 
457  if (row_ctr%15 == 0)
458  {
459  prompt_and_pause("\n\n");
460  my_clearscrn();
461  }
462  printf("%02d %-12.12s", cty_data->id, cty_data->name);
463  row_ctr++;
464 }
465 
466 void edge_prt(const void *edgedata)
467 {
468  DspVertexdata edata;
469  MyCitydata cty_data;
470 
471  edata = (DspVertexdata)edgedata;
472  cty_data = (MyCitydata)(edata->data);
473 
474  printf("%02d|%-3.3s|%4.1f|", cty_data->id, cty_data->name, edata->weight);
475 }
476 
477 /* --- Function: void prt_fill(char *str, char fillchar, int fieldlen) --- */
478 void prt_fill(char *str, char fillchar, int fieldlen)
479 {
480  int i=0, slen;
481  char *pc;
482 
483  pc = str;
484  slen = strlen(str);
485 
486  while (i < fieldlen)
487  {
488  (i - slen) < 0 ? putchar(*pc) : putchar(fillchar);
489  i++;
490  pc++;
491  }
492 }
493 
494 /* --- Function: void print_vertices(Graph gr) --- */
495 void print_vertices(Graph gr)
496 {
497  VertexNode vtxnode;
498  DspVertexdata vdata;
499  MyCitydata cty_data;
500  int i;
501 
502  for (i = 0, vtxnode = GRAPHgetvertexhead(gr); vtxnode != NULL; ++i, vtxnode = GRAPHgetvertexnext(vtxnode))
503  {
504  vdata = (DspVertexdata)GRAPHgetvertexdata(vtxnode);
505  cty_data = (MyCitydata)(vdata->data);
506 
507  if (i%5 == 0)
508  {
509  printf("\n %02d ", cty_data->id);
510  }
511  else
512  {
513  printf(" %02d ", cty_data->id);
514  }
515  prt_fill(cty_data->name, MYFILLCHAR, 11);
516  }
517 }
518 
519 /* --- Function: void make_tour(Graph gr) --- */
520 void make_tour(Graph gr)
521 {
522  int start, dest, nr_of_vtcs, retval;
523  char reply;
524  struct DspVertexdata_ tmpvtxdata;
525  struct MyCitydata_ tmpctydata;
526  DspVertexdata vtxdata;
527  MyCitydata mcd;
528  char startname[KEYSIZ];
529  char destname[KEYSIZ];
530  VertexNode vtxnode;
531  Slist my_destpaths = NULL;
532 
533  my_clearscrn();
534  printf("--- MAKE A TOUR - ENTER START & DESTINATION ---\n");
535  printf("\nDestinations:");
536  print_vertices(gr); /* Print target destination in graph.. */
537  printf("\n");
538  tmpvtxdata.data = &tmpctydata; /* Link temp. structures together.. */
539  nr_of_vtcs = GRAPHvcount(gr);
540 
541  /* Read start nr.. */
542  start = read_int("Start ", 1, nr_of_vtcs);
543  /* Get corresponding city name from graph */
544  tmpctydata.id = start;
545  vtxnode = GRAPHfindvertex(gr, &tmpvtxdata);
546  assert(vtxnode != NULL);
547  /* Get the city name.. */
548  vtxdata = (DspVertexdata)GRAPHgetvertexdata(vtxnode);
549  mcd = (MyCitydata)vtxdata->data;
550  strcpy(startname, mcd->name);
551  printf("Start : %d %-11.11s", start, startname);
552 
553  /* Make call to ALGOdsp() - this is where the work is done... */
554  if ((retval = ALGOdsp(gr, &tmpvtxdata, &my_destpaths, my_match)) != OK)
555  {
556  error_mess("Something went wrong in call to 'ALGOdsp()' - bailing out..!");
557  GRAPHdestroy(gr);
558  exit(-1);
559  }
560  assert(my_destpaths != NULL);
561 
562  do
563  {
564  dest = read_int("Destination", 1, nr_of_vtcs);
565  /* Get corresponding city name from graph */
566  tmpctydata.id = dest;
567  vtxnode = GRAPHfindvertex(gr, &tmpvtxdata);
568  assert(vtxnode != NULL);
569  /* Get the city name.. */
570  vtxdata = (DspVertexdata)GRAPHgetvertexdata(vtxnode);
571  mcd = (MyCitydata)vtxdata->data;
572  strcpy(destname, mcd->name);
573  printf("Destination: %d %-11.11s", dest, destname);
574 
575  /* Call function 'print_route()' here... */
576  printf("\nOptimized route:\n");
577  printroute(vtxdata);
578 
579  reply = read_char("\nTry another destination (y/n)? ", 0, 0, my_chchk);
580 
581  if (reply == 'y' || reply == 'y')
582  {
583  my_clearscrn();
584  printf("--- MAKE A TOUR - ENTER NEW DESTINATION ---\n");
585  printf("\nDestinations:");
586  print_vertices(gr);
587  printf("\n\n");
588  printf("Start: %d %-11.11s", start, startname);
589  }
590  } while (reply == 'y' || reply == 'Y');
591 
592  SLISTdestroy(my_destpaths);
593 }
594 
595 /* --- Calculate the Minimum Spanning Tree --- */
596 void min_span_tree(Graph gr)
597 {
598  assert(gr != NULL);
599 
600  my_clearscrn();
601  printf("--- MIMIMAL SPANNING TREE ---");
602  prompt_and_pause("\n\nComing up in next version..");
603 }
604 
605 /* --- Function: void final_status(Graph gr) --- */
606 void final_status(Graph gr)
607 {
608  assert(gr != NULL);
609  prompt_and_pause("\n\nThat's all folks...- Bye!");
610 }
611 
612 int main(void)
613 {
614  Graph mygraph;
615  char grdatafile[] = "dsp_data.txt";
616  int menu_choice;
617 
618 
619  /* Enter menu loop.. */
620  do
621  {
622  if ((mygraph = GRAPHinit(my_match, my_destroy)) == NULL)
623  {
624  printf("\nFatal error - bailing out...\n!");
625  exit(EXIT_FAILURE);
626  }
627 
628  if (read_graphdata(mygraph, grdatafile) != OK)
629  {
630  printf("\nFailed to read data from file: %s", grdatafile);
631  exit(EXIT_FAILURE);
632  }
633 
634  menu_choice = menu(MAIN_MENU_ROW, 0, 3);
635 
636  switch (menu_choice)
637  {
638  case 1:
639  make_tour(mygraph);
640  break;
641  case 2:
642  min_span_tree(mygraph);
643  break;
644  case 3:
645  my_clearscrn();
646  printf("--- PRINT VERTICES(=%d) AND EDGES(=%d) ---\n", GRAPHvcount(mygraph), GRAPHecount(mygraph));
647  row_ctr=1; /* Initialize row counter.. */
648  GRAPHprint(mygraph, vtx_prt, edge_prt);
649  prompt_and_pause("\n\n");
650  break;
651  default:
652  final_status(mygraph);
653  break;
654  }
655  GRAPHdestroy(mygraph);
656  }
657  while (menu_choice);
658 
659  return 0;
660 }