src/sn_network.c: Fix a bug in sn_network_normalize.
[sort-networks.git] / src / sn_network.c
1 /**
2  * collectd - src/sn_network.c
3  * Copyright (C) 2008,2009  Florian octo Forster
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the
7  * Free Software Foundation; only version 2 of the License is applicable.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
17  *
18  * Authors:
19  *   Florian octo Forster <octo at verplant.org>
20  **/
21
22 #ifndef _ISOC99_SOURCE
23 # define _ISOC99_SOURCE
24 #endif
25 #ifndef _POSIX_C_SOURCE
26 # define _POSIX_C_SOURCE 200112L
27 #endif
28
29 #if 0
30 # define DPRINTF(...) fprintf (stderr, "sn_network: " __VA_ARGS__)
31 #else
32 # define DPRINTF(...) /**/
33 #endif
34
35 #include <stdlib.h>
36 #include <stdio.h>
37 #include <string.h>
38 #include <strings.h>
39 #include <ctype.h>
40 #include <assert.h>
41
42 #include "sn_network.h"
43 #include "sn_random.h"
44
45 sn_network_t *sn_network_create (int inputs_num) /* {{{ */
46 {
47   sn_network_t *n;
48
49   n = (sn_network_t *) malloc (sizeof (sn_network_t));
50   if (n == NULL)
51     return (NULL);
52   memset (n, '\0', sizeof (sn_network_t));
53
54   n->inputs_num = inputs_num;
55
56   return (n);
57 } /* }}} sn_network_t *sn_network_create */
58
59 void sn_network_destroy (sn_network_t *n) /* {{{ */
60 {
61   if (n == NULL)
62     return;
63
64   if (n->stages != NULL)
65   {
66     int i;
67     for (i = 0; i < n->stages_num; i++)
68     {
69       sn_stage_destroy (n->stages[i]);
70       n->stages[i] = NULL;
71     }
72     free (n->stages);
73     n->stages = NULL;
74   }
75
76   free (n);
77 } /* }}} void sn_network_destroy */
78
79 sn_network_t *sn_network_create_odd_even_mergesort (int inputs_num) /* {{{ */
80 {
81   sn_network_t *n;
82
83   n = sn_network_create (inputs_num);
84
85   assert (inputs_num > 0);
86   if (inputs_num == 1)
87   {
88     return (n);
89   }
90   if (inputs_num == 2)
91   {
92     sn_stage_t *s;
93     sn_comparator_t c;
94
95     c.min = 0;
96     c.max = 1;
97
98     s = sn_stage_create (/* depth = */ 0);
99     sn_stage_comparator_add (s, &c);
100     sn_network_stage_add (n, s);
101
102     return (n);
103   }
104   else
105   {
106     sn_network_t *n_left;
107     sn_network_t *n_right;
108     int inputs_left;
109     int inputs_right;
110
111     inputs_left = inputs_num / 2;
112     inputs_right = inputs_num - inputs_left;
113
114     n_left = sn_network_create_odd_even_mergesort (inputs_left);
115     if (n_left == NULL)
116       return (NULL);
117
118     n_right = sn_network_create_odd_even_mergesort (inputs_right);
119     if (n_right == NULL)
120     {
121       sn_network_destroy (n_left);
122       return (NULL);
123     }
124
125     n = sn_network_combine_odd_even_merge (n_left, n_right);
126
127     sn_network_destroy (n_left);
128     sn_network_destroy (n_right);
129
130     if (n != NULL)
131       sn_network_compress (n);
132
133     return (n);
134   }
135 } /* }}} sn_network_t *sn_network_create_odd_even_mergesort */
136
137 int sn_network_stage_add (sn_network_t *n, sn_stage_t *s) /* {{{ */
138 {
139   sn_stage_t **temp;
140
141   temp = (sn_stage_t **) realloc (n->stages, (n->stages_num + 1)
142       * sizeof (sn_stage_t *));
143   if (temp == NULL)
144     return (-1);
145
146   n->stages = temp;
147   SN_STAGE_DEPTH (s) = n->stages_num;
148   n->stages[n->stages_num] = s;
149   n->stages_num++;
150
151   return (0);
152 } /* }}} int sn_network_stage_add */
153
154 int sn_network_stage_remove (sn_network_t *n, int s_num) /* {{{ */
155 {
156   int nmemb = n->stages_num - (s_num + 1);
157   sn_stage_t **temp;
158
159   assert (s_num < n->stages_num);
160
161   sn_stage_destroy (n->stages[s_num]);
162   n->stages[s_num] = NULL;
163
164   if (nmemb > 0)
165   {
166     memmove (n->stages + s_num, n->stages + (s_num + 1),
167         nmemb * sizeof (sn_stage_t *));
168     n->stages[n->stages_num - 1] = NULL;
169   }
170   n->stages_num--;
171
172   /* Free the unused memory */
173   if (n->stages_num == 0)
174   {
175     free (n->stages);
176     n->stages = NULL;
177   }
178   else
179   {
180     temp = (sn_stage_t **) realloc (n->stages,
181         n->stages_num * sizeof (sn_stage_t *));
182     if (temp == NULL)
183       return (-1);
184     n->stages = temp;
185   }
186
187   return (0);
188 } /* }}} int sn_network_stage_remove */
189
190 sn_network_t *sn_network_clone (const sn_network_t *n) /* {{{ */
191 {
192   sn_network_t *n_copy;
193   int i;
194
195   n_copy = sn_network_create (n->inputs_num);
196   if (n_copy == NULL)
197     return (NULL);
198
199   for (i = 0; i < n->stages_num; i++)
200   {
201     sn_stage_t *s;
202     int status;
203
204     s = sn_stage_clone (n->stages[i]);
205     if (s == NULL)
206       break;
207
208     status = sn_network_stage_add (n_copy, s);
209     if (status != 0)
210       break;
211   }
212
213   if (i < n->stages_num)
214   {
215     sn_network_destroy (n_copy);
216     return (NULL);
217   }
218
219   return (n_copy);
220 } /* }}} sn_network_t *sn_network_clone */
221
222 int sn_network_show (sn_network_t *n) /* {{{ */
223 {
224   int i;
225
226   for (i = 0; i < n->stages_num; i++)
227     sn_stage_show (n->stages[i]);
228
229   return (0);
230 } /* }}} int sn_network_show */
231
232 int sn_network_invert (sn_network_t *n) /* {{{ */
233 {
234   int i;
235
236   for (i = 0; i < n->stages_num; i++)
237     sn_stage_invert (n->stages[i]);
238
239   return (0);
240 } /* }}} int sn_network_invert */
241
242 int sn_network_shift (sn_network_t *n, int sw) /* {{{ */
243 {
244   int i;
245
246   for (i = 0; i < n->stages_num; i++)
247     sn_stage_shift (n->stages[i], sw, SN_NETWORK_INPUT_NUM (n));
248
249   return (0);
250 } /* }}} int sn_network_shift */
251
252 int sn_network_compress (sn_network_t *n) /* {{{ */
253 {
254   int i;
255   int j;
256   int k;
257
258   for (i = 1; i < n->stages_num; i++)
259   {
260     sn_stage_t *s;
261     
262     s = n->stages[i];
263     
264     for (j = 0; j < SN_STAGE_COMP_NUM (s); j++)
265     {
266       sn_comparator_t *c = SN_STAGE_COMP_GET (s, j);
267       int move_to = i;
268
269       for (k = i - 1; k >= 0; k--)
270       {
271         int conflict;
272
273         conflict = sn_stage_comparator_check_conflict (n->stages[k], c);
274         if (conflict == 0)
275         {
276           move_to = k;
277           continue;
278         }
279
280         if (conflict == 2)
281           move_to = -1;
282         break;
283       }
284
285       if (move_to < i)
286       {
287         if (move_to >= 0)
288           sn_stage_comparator_add (n->stages[move_to], c);
289         sn_stage_comparator_remove (s, j);
290         j--;
291       }
292     }
293   }
294
295   while ((n->stages_num > 0)
296       && (SN_STAGE_COMP_NUM (n->stages[n->stages_num - 1]) == 0))
297     sn_network_stage_remove (n, n->stages_num - 1);
298
299   return (0);
300 } /* }}} int sn_network_compress */
301
302 int sn_network_normalize (sn_network_t *n) /* {{{ */
303 {
304   int i;
305
306   for (i = 0; i < n->stages_num; i++)
307   {
308     sn_stage_t *s;
309     int j;
310
311     s = n->stages[i];
312
313     for (j = 0; j < SN_STAGE_COMP_NUM (s); j++)
314     {
315       sn_comparator_t *c;
316       int min;
317       int max;
318
319       c = SN_STAGE_COMP_GET (s, j);
320
321       min = c->min;
322       max = c->max;
323
324       if (min > max)
325       {
326         int k;
327
328         for (k = i; k < n->stages_num; k++) 
329           sn_stage_swap (n->stages[k], min, max);
330
331         i = -1;
332         break; /* for (j) */
333       }
334     } /* for (j = 0 .. #comparators) */
335   } /* for (i = n->stages_num - 1 .. 0) */
336
337   return (0);
338 } /* }}} int sn_network_normalize */
339
340 int sn_network_cut_at (sn_network_t *n, int input, /* {{{ */
341     enum sn_network_cut_dir_e dir)
342 {
343   int i;
344   int position = input;
345
346   for (i = 0; i < n->stages_num; i++)
347   {
348     sn_stage_t *s;
349     int new_position;
350     
351     s = n->stages[i];
352     new_position = sn_stage_cut_at (s, position, dir);
353     
354     if (position != new_position)
355     {
356       int j;
357
358       for (j = 0; j < i; j++)
359         sn_stage_swap (n->stages[j], position, new_position);
360     }
361
362     position = new_position;
363   }
364
365   assert (((dir == DIR_MIN) && (position == 0))
366       || ((dir == DIR_MAX) && (position == (n->inputs_num - 1))));
367
368   for (i = 0; i < n->stages_num; i++)
369     sn_stage_remove_input (n->stages[i], position);
370
371   n->inputs_num--;
372
373   return (0);
374 } /* }}} int sn_network_cut_at */
375
376 /* sn_network_concatenate
377  *
378  * `Glues' two networks together, resulting in a comparator network with twice
379  * as many inputs but one that doesn't really sort anymore. It produces a
380  * bitonic sequence, though, that can be used by the mergers below. */
381 static sn_network_t *sn_network_concatenate (sn_network_t *n0, /* {{{ */
382     sn_network_t *n1)
383 {
384   sn_network_t *n;
385   int stages_num;
386   int i;
387   int j;
388
389   stages_num = (n0->stages_num > n1->stages_num)
390     ? n0->stages_num
391     : n1->stages_num;
392
393   n = sn_network_create (n0->inputs_num + n1->inputs_num);
394   if (n == NULL)
395     return (NULL);
396
397   for (i = 0; i < stages_num; i++)
398   {
399     sn_stage_t *s = sn_stage_create (i);
400
401     if (i < n0->stages_num)
402       for (j = 0; j < SN_STAGE_COMP_NUM (n0->stages[i]); j++)
403       {
404         sn_comparator_t *c = SN_STAGE_COMP_GET (n0->stages[i], j);
405         sn_stage_comparator_add (s, c);
406       }
407
408     if (i < n1->stages_num)
409       for (j = 0; j < SN_STAGE_COMP_NUM (n1->stages[i]); j++)
410       {
411         sn_comparator_t *c_orig = SN_STAGE_COMP_GET (n1->stages[i], j);
412         sn_comparator_t  c_copy;
413
414         SN_COMP_MIN(&c_copy) = SN_COMP_MIN(c_orig) + n0->inputs_num;
415         SN_COMP_MAX(&c_copy) = SN_COMP_MAX(c_orig) + n0->inputs_num;
416
417         sn_stage_comparator_add (s, &c_copy);
418       }
419
420     sn_network_stage_add (n, s);
421   }
422
423   return (n);
424 } /* }}} sn_network_t *sn_network_concatenate */
425
426 static int sn_network_add_bitonic_merger_recursive (sn_network_t *n, /* {{{ */
427     int low, int num)
428 {
429   sn_stage_t *s;
430   int m;
431   int i;
432
433   if (num == 1)
434     return (0);
435
436   s = sn_stage_create (n->stages_num);
437   if (s == NULL)
438     return (-1);
439
440   m = num / 2;
441
442   for (i = low; i < (low + m); i++)
443   {
444     sn_comparator_t c;
445
446     c.min = i;
447     c.max = i + m;
448
449     sn_stage_comparator_add (s, &c);
450   }
451
452   sn_network_stage_add (n, s);
453
454   sn_network_add_bitonic_merger_recursive (n, low, m);
455   sn_network_add_bitonic_merger_recursive (n, low + m, m);
456
457   return (0);
458 } /* }}} int sn_network_add_bitonic_merger_recursive */
459
460 static int sn_network_add_bitonic_merger (sn_network_t *n) /* {{{ */
461 {
462 #if 0
463   sn_stage_t *s;
464   int m;
465   int i;
466
467   s = sn_stage_create (n->stages_num);
468   if (s == NULL)
469     return (-1);
470
471   m = n->inputs_num / 2;
472
473   for (i = 0; i < m; i++)
474   {
475     sn_comparator_t c;
476
477     c.min = i;
478     c.max = n->inputs_num - (i + 1);
479
480     sn_stage_comparator_add (s, &c);
481   }
482
483   sn_network_stage_add (n, s);
484
485   sn_network_add_bitonic_merger_recursive (n, 0, m);
486   sn_network_add_bitonic_merger_recursive (n, m, m);
487 #else
488   sn_network_add_bitonic_merger_recursive (n, 0, SN_NETWORK_INPUT_NUM (n));
489 #endif
490
491   return (0);
492 } /* }}} int sn_network_add_bitonic_merger */
493
494 static int sn_network_add_odd_even_merger (sn_network_t *n, /* {{{ */
495     int *indizes_left, int indizes_left_num,
496     int *indizes_right, int indizes_right_num)
497 {
498   int tmp_left[indizes_left_num];
499   int tmp_left_num;
500   int tmp_right[indizes_left_num];
501   int tmp_right_num;
502   int max_index;
503   sn_stage_t *s;
504   int i;
505
506   if ((indizes_left_num == 0) || (indizes_right_num == 0))
507   {
508     return (0);
509   }
510   else if ((indizes_left_num == 1) && (indizes_right_num == 1))
511   {
512     sn_comparator_t c;
513     sn_stage_t *s;
514
515     c.min = *indizes_left;
516     c.max = *indizes_right;
517
518     s = sn_stage_create (n->stages_num);
519     if (s == NULL)
520       return (-1);
521
522     sn_stage_comparator_add (s, &c);
523     sn_network_stage_add (n, s);
524
525     return (0);
526   }
527
528   /* Merge odd sequences */
529   tmp_left_num = (indizes_left_num + 1) / 2;
530   for (i = 0; i < tmp_left_num; i++)
531     tmp_left[i] = indizes_left[2 * i];
532
533   tmp_right_num = (indizes_right_num + 1) / 2;
534   for (i = 0; i < tmp_right_num; i++)
535     tmp_right[i] = indizes_right[2 * i];
536
537   sn_network_add_odd_even_merger (n,
538       tmp_left, tmp_left_num,
539       tmp_right, tmp_right_num);
540
541   /* Merge even sequences */
542   tmp_left_num = indizes_left_num / 2;
543   for (i = 0; i < tmp_left_num; i++)
544     tmp_left[i] = indizes_left[(2 * i) + 1];
545
546   tmp_right_num = indizes_right_num / 2;
547   for (i = 0; i < tmp_right_num; i++)
548     tmp_right[i] = indizes_right[(2 * i) + 1];
549
550   sn_network_add_odd_even_merger (n,
551       tmp_left, tmp_left_num,
552       tmp_right, tmp_right_num);
553
554   /* Apply ``comparison-interchange'' operations. */
555   s = sn_stage_create (n->stages_num);
556
557   max_index = indizes_left_num + indizes_right_num;
558   if ((max_index % 2) == 0)
559     max_index -= 3;
560   else
561     max_index -= 2;
562
563   for (i = 1; i <= max_index; i += 2)
564   {
565     sn_comparator_t c;
566
567     if (i < indizes_left_num)
568       c.min = indizes_left[i];
569     else
570       c.min = indizes_right[i - indizes_left_num];
571
572     if ((i + 1) < indizes_left_num)
573       c.max = indizes_left[i + 1];
574     else
575       c.max = indizes_right[i + 1 - indizes_left_num];
576
577     sn_stage_comparator_add (s, &c);
578   }
579
580   sn_network_stage_add (n, s);
581
582   return (0);
583 } /* }}} int sn_network_add_odd_even_merger */
584
585 static sn_network_t *sn_network_combine_bitonic_shift (sn_network_t *n0, /* {{{ */
586     sn_network_t *n1, int do_shift)
587 {
588   sn_network_t *n;
589   sn_network_t *n1_clone;
590   int shift;
591
592   n1_clone = sn_network_clone (n1);
593   if (n1_clone == NULL)
594     return (NULL);
595
596   sn_network_invert (n1_clone);
597
598   n = sn_network_concatenate (n0, n1_clone);
599   if (n == NULL)
600     return (NULL);
601
602   sn_network_destroy (n1_clone);
603
604   if (do_shift)
605     shift = sn_bounded_random (0, SN_NETWORK_INPUT_NUM (n) - 1);
606   else
607     shift = 0;
608
609   if (shift > 0)
610   {
611     DPRINTF ("sn_network_combine_bitonic_shift: Shifting by %i.\n", shift);
612     sn_network_shift (n, shift);
613   }
614
615   sn_network_add_bitonic_merger (n);
616
617   return (n);
618 } /* }}} sn_network_t *sn_network_combine_bitonic_shift */
619
620 sn_network_t *sn_network_combine_bitonic (sn_network_t *n0, /* {{{ */
621     sn_network_t *n1)
622 {
623   return (sn_network_combine_bitonic_shift (n0, n1, /* do_shift = */ 0));
624 } /* }}} sn_network_t *sn_network_combine_bitonic */
625
626 sn_network_t *sn_network_combine_odd_even_merge (sn_network_t *n0, /* {{{ */
627     sn_network_t *n1)
628 {
629   sn_network_t *n;
630   int indizes_left[n0->inputs_num];
631   int indizes_left_num;
632   int indizes_right[n1->inputs_num];
633   int indizes_right_num;
634   int status;
635   int i;
636
637   indizes_left_num = n0->inputs_num;
638   indizes_right_num = n1->inputs_num;
639   for (i = 0; i < indizes_left_num; i++)
640     indizes_left[i] = i;
641   for (i = 0; i < indizes_right_num; i++)
642     indizes_right[i] = indizes_left_num + i;
643
644   n = sn_network_concatenate (n0, n1);
645   if (n == NULL)
646     return (NULL);
647
648   status = sn_network_add_odd_even_merger (n,
649       indizes_left, indizes_left_num,
650       indizes_right, indizes_right_num);
651   if (status != 0)
652   {
653     sn_network_destroy (n);
654     return (NULL);
655   }
656
657   sn_network_compress (n);
658   return (n);
659 } /* }}} sn_network_t *sn_network_combine */
660
661 sn_network_t *sn_network_combine (sn_network_t *n0, /* {{{ */
662     sn_network_t *n1, int is_power_of_two)
663 {
664   sn_network_t *n;
665
666   if ((is_power_of_two != 0) && (sn_bounded_random (0, 9) == 0))
667   {
668     DPRINTF ("sn_network_combine: Using the bitonic merger.\n");
669     n = sn_network_combine_bitonic_shift (n0, n1, /* do_shift = */ 1);
670   }
671   else
672   {
673     DPRINTF ("sn_network_combine: Using the odd-even merger.\n");
674     n = sn_network_combine_odd_even_merge (n0, n1);
675   }
676
677   sn_network_compress (n);
678
679   return (n);
680 } /* }}} sn_network_t *sn_network_combine */
681
682 int sn_network_sort (sn_network_t *n, int *values) /* {{{ */
683 {
684   int status;
685   int i;
686
687   status = 0;
688   for (i = 0; i < n->stages_num; i++)
689   {
690     status = sn_stage_sort (n->stages[i], values);
691     if (status != 0)
692       return (status);
693   }
694
695   return (status);
696 } /* }}} int sn_network_sort */
697
698 int sn_network_brute_force_check (sn_network_t *n) /* {{{ */
699 {
700   int test_pattern[n->inputs_num];
701   int values[n->inputs_num];
702   int status;
703   int i;
704
705   memset (test_pattern, 0, sizeof (test_pattern));
706   while (42)
707   {
708     int previous;
709     int overflow;
710
711     /* Copy the current pattern and let the network sort it */
712     memcpy (values, test_pattern, sizeof (values));
713     status = sn_network_sort (n, values);
714     if (status != 0)
715       return (status);
716
717     /* Check if the array is now sorted. */
718     previous = values[0];
719     for (i = 1; i < n->inputs_num; i++)
720     {
721       if (previous > values[i])
722         return (1);
723       previous = values[i];
724     }
725
726     /* Generate the next test pattern */
727     overflow = 1;
728     for (i = 0; i < n->inputs_num; i++)
729     {
730       if (test_pattern[i] == 0)
731       {
732         test_pattern[i] = 1;
733         overflow = 0;
734         break;
735       }
736       else
737       {
738         test_pattern[i] = 0;
739         overflow = 1;
740       }
741     }
742
743     /* Break out of the while loop if we tested all possible patterns */
744     if (overflow == 1)
745       break;
746   } /* while (42) */
747
748   /* All tests successfull */
749   return (0);
750 } /* }}} int sn_network_brute_force_check */
751
752 sn_network_t *sn_network_read (FILE *fh) /* {{{ */
753 {
754   sn_network_t *n;
755   char buffer[64];
756
757   int opt_inputs = 0;
758
759   while (fgets (buffer, sizeof (buffer), fh) != NULL)
760   {
761     char *str_key = buffer;
762     char *str_value = NULL;
763     int   buffer_len = strlen (buffer);
764
765     while ((buffer_len > 0) && ((buffer[buffer_len - 1] == '\n')
766           || (buffer[buffer_len - 1] == '\r')))
767     {
768       buffer_len--;
769       buffer[buffer_len] = '\0';
770     }
771     if (buffer_len == 0)
772       break;
773
774     str_value = strchr (buffer, ':');
775     if (str_value == NULL)
776     {
777       printf ("Cannot parse line: %s\n", buffer);
778       continue;
779     }
780
781     *str_value = '\0'; str_value++;
782     while ((*str_value != '\0') && (isspace (*str_value) != 0))
783       str_value++;
784
785     if (strcasecmp ("Inputs", str_key) == 0)
786       opt_inputs = atoi (str_value);
787     else
788       printf ("Unknown key: %s\n", str_key);
789   } /* while (fgets) */
790
791   if (opt_inputs < 2)
792     return (NULL);
793
794   n = sn_network_create (opt_inputs);
795
796   while (42)
797   {
798     sn_stage_t *s;
799
800     s = sn_stage_read (fh);
801     if (s == NULL)
802       break;
803
804     sn_network_stage_add (n, s);
805   }
806
807   if (SN_NETWORK_STAGE_NUM (n) < 1)
808   {
809     sn_network_destroy (n);
810     return (NULL);
811   }
812
813   return (n);
814 } /* }}} sn_network_t *sn_network_read */
815
816 sn_network_t *sn_network_read_file (const char *file) /* {{{ */
817 {
818   sn_network_t *n;
819   FILE *fh;
820
821   fh = fopen (file, "r");
822   if (fh == NULL)
823     return (NULL);
824
825   n = sn_network_read (fh);
826
827   fclose (fh);
828
829   return (n);
830 } /* }}} sn_network_t *sn_network_read_file */
831
832 int sn_network_write (sn_network_t *n, FILE *fh) /* {{{ */
833 {
834   int i;
835
836   fprintf (fh, "Inputs: %i\n", n->inputs_num);
837   fprintf (fh, "\n");
838
839   for (i = 0; i < n->stages_num; i++)
840     sn_stage_write (n->stages[i], fh);
841
842   return (0);
843 } /* }}} int sn_network_write */
844
845 int sn_network_write_file (sn_network_t *n, const char *file) /* {{{ */
846 {
847   int status;
848   FILE *fh;
849
850   fh = fopen (file, "w");
851   if (fh == NULL)
852     return (-1);
853
854   status = sn_network_write (n, fh);
855
856   fclose (fh);
857
858   return (status);
859 } /* }}} int sn_network_write_file */
860
861 int sn_network_serialize (sn_network_t *n, char **ret_buffer, /* {{{ */
862     size_t *ret_buffer_size)
863 {
864   char *buffer;
865   size_t buffer_size;
866   int status;
867   int i;
868
869   buffer = *ret_buffer;
870   buffer_size = *ret_buffer_size;
871
872 #define SNPRINTF_OR_FAIL(...) \
873   status = snprintf (buffer, buffer_size, __VA_ARGS__); \
874   if ((status < 1) || (status >= buffer_size)) \
875     return (-1); \
876   buffer += status; \
877   buffer_size -= status;
878
879   SNPRINTF_OR_FAIL ("Inputs: %i\r\n\r\n", n->inputs_num);
880
881   for (i = 0; i < n->stages_num; i++)
882   {
883     status = sn_stage_serialize (n->stages[i], &buffer, &buffer_size);
884     if (status != 0)
885       return (status);
886   }
887
888   *ret_buffer = buffer;
889   *ret_buffer_size = buffer_size;
890   return (0);
891 } /* }}} int sn_network_serialize */
892
893 sn_network_t *sn_network_unserialize (char *buffer, /* {{{ */
894     size_t buffer_size)
895 {
896   sn_network_t *n;
897   int opt_inputs = 0;
898
899   if (buffer_size == 0)
900     return (NULL);
901
902   /* Read options first */
903   while (buffer_size > 0)
904   {
905     char *endptr;
906     char *str_key;
907     char *str_value;
908     char *line;
909     int   line_len;
910
911     line = buffer;
912     endptr = strchr (buffer, '\n');
913     if (endptr == NULL)
914       return (NULL);
915
916     *endptr = 0;
917     endptr++;
918     buffer = endptr;
919     line_len = strlen (line);
920
921     if ((line_len > 0) && (line[line_len - 1] == '\r'))
922     {
923       line[line_len - 1] = 0;
924       line_len--;
925     }
926
927     if (line_len == 0)
928       break;
929
930     str_key = line;
931     str_value = strchr (line, ':');
932     if (str_value == NULL)
933     {
934       printf ("Cannot parse line: %s\n", line);
935       continue;
936     }
937
938     *str_value = '\0'; str_value++;
939     while ((*str_value != '\0') && (isspace (*str_value) != 0))
940       str_value++;
941
942     if (strcasecmp ("Inputs", str_key) == 0)
943       opt_inputs = atoi (str_value);
944     else
945       printf ("Unknown key: %s\n", str_key);
946   } /* while (fgets) */
947
948   if (opt_inputs < 2)
949     return (NULL);
950
951   n = sn_network_create (opt_inputs);
952
953   while (42)
954   {
955     sn_stage_t *s;
956
957     s = sn_stage_unserialize (&buffer, &buffer_size);
958     if (s == NULL)
959       break;
960
961     sn_network_stage_add (n, s);
962   }
963
964   if (SN_NETWORK_STAGE_NUM (n) < 1)
965   {
966     sn_network_destroy (n);
967     return (NULL);
968   }
969
970   return (n);
971 } /* }}} sn_network_t *sn_network_unserialize */
972
973 /* vim: set sw=2 sts=2 et fdm=marker : */