Added SILC Thread Queue API
[silc.git] / util / robodoc / Source / util.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <ctype.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <stdarg.h>             /* for RB_Say() */
8
9 #include "robodoc.h"
10 #include "links.h"
11 #include "headers.h"
12 #include "folds.h"
13 #include "items.h"
14 #include "util.h"
15 #include "time.h"
16
17
18
19
20 /****f* ROBODoc/RB_FilePart [2.0x]
21  * NAME
22  *   RB_FilePart
23  * SYNOPSIS
24  *   char *RB_FilePart(char *file_name)
25  * FUNCTION
26  *   return the basename (like Amiga/Dos/FilePart())
27  * NOTES
28  *   koessi
29  * SEE ALSO
30  * SOURCE
31  */
32
33 char *
34 RB_FilePart (char *file_name)
35 {
36   char *cur_char;
37   char c;
38
39   if ((cur_char = file_name) != NULL)
40     {
41       for (; (c = *cur_char) != '\0'; ++cur_char)
42         {
43           if ((c == '/') || (c == ':'))
44             {
45               ++cur_char;
46               while ('/' == *cur_char)
47                 ++cur_char;
48
49               if (*cur_char)
50                 file_name = cur_char;
51             }
52         }
53     }
54   return (file_name);
55 }
56
57 /* Same except remove trailing dot (.). -Pekka */
58 char *
59 RB_FilePartStart (char *file_name)
60 {
61   char *cur_char;
62   char c;
63
64   if ((cur_char = file_name) != NULL)
65     {
66       for (; (c = *cur_char) != '\0'; ++cur_char)
67         {
68           if ((c == '/') || (c == ':'))
69             {
70               ++cur_char;
71               while ('/' == *cur_char)
72                 ++cur_char;
73
74               if (*cur_char)
75                 file_name = cur_char;
76             }
77         }
78     }
79
80   if (strchr(file_name, '.'))
81     *strchr(file_name, '.') = '\0';
82
83   return (file_name);
84 }
85
86 /*** RB_File_Part ***/
87
88
89
90 /****f* ROBODoc/RB_Analyse_Defaults_File [3.0b]
91  * NAME
92  *   RB_Analyse_Defaults_file -- read default from defaults file
93  * SYNOPSIS
94  *   RB_Analyse_Defaults_file
95  * FUNCTION
96  *   Read the default vaules from the default file.
97  * NOTES
98  *   FS: The use of while (!feof(defaults_file)) {
99  *       is wrong here. Should check return value of
100  *       fgets().
101  * SOURCE
102  */
103
104 void
105 RB_Analyse_Defaults_File ()
106 {
107   FILE *defaults_file;
108
109   /* defaults file in working directory? */
110   defaults_file = fopen ("robodoc.defaults", "r");
111   if (defaults_file == NULL)
112     {
113       /* try again from the directory from 
114          which this application was started  */
115 #ifdef _MSC_VER
116       /* windows */
117       char path[_MAX_PATH], *c;
118
119       strcpy (path, whoami);
120       if ((c = strrchr (path, '\\')) != NULL)
121         {
122           *c = '\0';
123           strcat (path, "\\");
124         }
125       strcat (path, "robodoc.defaults");
126       defaults_file = fopen (path, "r");
127 #else
128       /* non-windows ... to be done */
129 #endif /* _MSC_VER */
130     }
131   if (defaults_file != NULL)
132     {
133       while (!feof (defaults_file))
134         {
135           char *cur_char;
136
137           *line_buffer = '\0';
138
139           fgets (line_buffer, MAX_LINE_LEN, defaults_file);
140
141           if (*line_buffer != '\n')
142             {
143               int item_type;
144
145               item_type = RB_Get_Item_Type (line_buffer);
146               if (item_type != NO_ITEM)
147                 {
148                   char *values;
149
150                   item_attributes[item_type] = ITEM_NAME_LARGE_FONT;
151
152                   cur_char = line_buffer + strlen (item_names[item_type]);
153                   for (; *cur_char && isspace (*cur_char); cur_char++);
154
155                   while (*cur_char)
156                     {
157                       for (values = cur_char;
158                            *cur_char && !isspace (*cur_char);
159                            cur_char++);
160                       if (*cur_char)
161                         {
162                           int item_attr;
163
164                           *cur_char = '\0';
165                           item_attr = RB_Get_Item_Attr (values);
166                           if (item_attr != MAKE_NORMAL)
167                             {
168                               RB_Say ("Default: %s = %s\n", 
169                                       item_names[item_type],
170                                       item_attr_names[item_attr]);
171                               item_attributes[item_type] |=
172                                 (1 << (item_attr + 1));
173                             }
174                         }
175                       for (cur_char++; *cur_char && isspace (*cur_char);
176                            cur_char++);
177                     }
178                 }
179             }
180         }
181       fclose (defaults_file);
182     }
183 /* else { printf("%s: WARNING, robodoc.defaults file was not found.\n",
184  * whoami); printf("\t\tyou should really use one.\n"); } */
185 }
186
187 /**********/
188
189
190
191 /****f* ROBODoc/RB_Skip_Remark_Marker [2.0e]
192  * NAME
193  *    RB_Skip_Remark_Marker
194  * SYNOPSIS
195  *     text  = RB_Skip_Remark_Marker (line_buffer)
196  *    char *                            char *
197  * FUNCTION
198  *    Scan and search for a recognized remark marker; skip past the
199  *    marker to the body of the text
200  * NOTE
201  *    This should be in generator.c
202  * SOURCE
203  */
204
205 char *
206 RB_Skip_Remark_Marker (char *line_buffer)
207 {
208   int marker, found;
209   char *cur_char, *cur_mchar;
210
211   found = FALSE;
212   cur_char = NULL;
213   for (marker = 0;
214        ((cur_mchar = remark_markers[marker]) != NULL) && !found;
215        marker++)
216     {
217       for (found = TRUE, cur_char = line_buffer;
218            *cur_mchar && *cur_char && found;
219            cur_mchar++, cur_char++)
220         {
221           if (tolower(*cur_mchar) != tolower(*cur_char))
222             found = FALSE;
223         }
224     }
225   return (cur_char);
226 }
227
228 /**************/
229
230
231
232
233 /****f* ROBODoc/RB_Slow_Sort [2.0]
234  * NAME
235  *   RB_Slow_Sort -- sort list of headers alphabetically
236  * SYNOPSIS
237  *   RB_Slow_Sort ()
238  * FUNCTION
239  *   Sorts the list of headers according to the header name
240  *   in alphabetically fashion.
241  * NOTES
242  *   This isn't a particularly speedy way of sorting.
243  * SOURCE
244  */
245
246 void
247 RB_Slow_Sort (void)
248 {
249   struct RB_header *cur_header, *unsorted_headers, *bigger_header;
250
251   if ((unsorted_headers = first_header) != NULL)
252     {                           /* additional
253                                  * check *koessi */
254       for (first_header = NULL;
255            unsorted_headers->next_header;)
256         {
257           for (bigger_header = unsorted_headers,
258                cur_header = bigger_header->next_header;
259                cur_header;
260                cur_header = cur_header->next_header)
261             {
262               if (strcmp (cur_header->name, bigger_header->name) > 0)
263                 bigger_header = cur_header;
264             }
265           RB_Remove_From_List (&unsorted_headers, bigger_header);
266           RB_Insert_In_List (&first_header, bigger_header);
267         }
268       RB_Insert_In_List (&first_header, unsorted_headers);
269     }
270 }
271
272 /*********/
273
274
275 /****f* ROBODoc/RB_Insert_In_List [2.0]
276  * NAME
277  *   RB_Insert_In_List -- Insert a header in a list.
278  * SYNOPSIS
279  *   RB_Insert_In_List (anchor,new_header)
280  *
281  *   RB_Insert_In_List (struct RB_header **, struct RB_header *)
282  * FUNCTION
283  *   Insert a node in a doubly linked list.
284  * INPUTS
285  *   anchor     - pointer to the first node in the list.
286  *   new_header - node to be inserted.
287  * MODIFICATION HISTORY
288  *   8. August 1995      --  optimized by koessi
289  * NOTES
290  *   
291  * SOURCE
292  */
293
294 void
295 RB_Insert_In_List (struct RB_header **anchor,
296                    struct RB_header *new_header)
297 {
298   struct RB_header *old_header;
299
300   if ((old_header = *anchor) != NULL)
301     old_header->prev_header = new_header;
302   new_header->next_header = old_header;
303   new_header->prev_header = NULL;
304   *anchor = new_header;
305 }
306
307 /*** RB_Insert_In_List ***/
308
309 /****f* ROBODoc/RB_Reverse_List [2.0]
310  * NAME
311  *   RB_Reverse_List -- Insert a header in a list.
312  * SYNOPSIS
313  *   RB_Reverse_List (void)
314  * FUNCTION
315  *
316  * INPUTS
317  *
318  * MODIFICATION HISTORY
319  *
320  * NOTES
321  *
322  * SOURCE
323  */
324
325 void
326 RB_Reverse_List (void)
327 {
328   struct RB_header *cur_header;
329   struct RB_header *temp_header;
330
331   for (cur_header = first_header;
332        cur_header;
333     )
334     {
335       first_header = cur_header;
336       temp_header = cur_header->next_header;
337       cur_header->next_header = cur_header->prev_header;
338       cur_header->prev_header = temp_header;
339       cur_header = temp_header;
340     }
341 }
342
343 /*** ***/
344
345
346 /****f* ROBODoc/RB_Remove_From_List [2.0]
347  * NAME
348  *   RB_Remove_From_List -- remove a header from a list.
349  * SYNOPSIS
350  *   RB_Remove_From_List (anchor, old_header)
351  *   RB_Remove_From_List (struct RB_header **, struct RB_header *)
352  * MODIFICATION HISTORY
353  *   8. August 1995      --  optimized by koessi
354  * SOURCE
355  */
356
357 void
358 RB_Remove_From_List (struct RB_header **anchor,
359                      struct RB_header *old_header)
360 {
361   struct RB_header *next_header = old_header->next_header;
362   struct RB_header *prev_header = old_header->prev_header;
363
364   if (next_header)
365     next_header->prev_header = prev_header;
366   if (prev_header)
367     prev_header->next_header = next_header;
368   else
369     *anchor = next_header;
370 }
371
372 /********/
373
374
375 /****f* ROBODoc/RB_Alloc_Header [2.01]
376  * NAME
377  *   RB_Alloc_Header            -- oop
378  * SYNOPSIS
379  *   struct RB_header *RB_Alloc_Header( void )
380  * FUNCTION
381  *   allocate the struct RB_header
382  * RESULT
383  *   struct RB_header *      -- all attributes/pointers set to zero
384  * AUTHOR
385  *   Koessi
386  * SEE ALSO
387  *   RB_Free_Header()
388  * SOURCE
389  */
390
391 struct RB_header *
392 RB_Alloc_Header (void)
393 {
394   struct RB_header *new_header;
395
396   if ((new_header = malloc (sizeof (struct RB_header))) != NULL)
397       memset (new_header, 0, sizeof (struct RB_header));
398   else
399     RB_Panic ("out of memory! [Alloc Header]\n");
400   return (new_header);
401 }
402
403 /********/
404
405
406 /****f* ROBODoc/RB_Free_Header [2.01]
407  * NAME
408  *   RB_Free_Header             -- oop
409  * SYNOPSIS
410  *   void RB_Free_Header( struct RB_header *header )
411  * FUNCTION
412  *   free struct RB_header and associated strings
413  * INPUTS
414  *   struct RB_header *header -- this one
415  * AUTHOR
416  *   Koessi
417  * SEE ALSO
418  *   RB_Alloc_Header(), RB_Close_The_Shop()
419  * SOURCE
420  */
421
422 void
423 RB_Free_Header (struct RB_header *header)
424 {
425   if (header)
426     {
427       if (header->version)
428         free (header->version);
429       if (header->name)
430         free (header->name);
431       if (header->contents)
432         free (header->contents);
433       free (header);
434     }
435 }
436
437 /************/
438
439
440 /****i* ROBODoc/RB_WordLen [2.01]
441  * NAME
442  *   RB_WordLen -- like strlen
443  * SYNOPSIS
444  *   int RB_WordLen( char *str )
445  * FUNCTION
446  *   get the amount of bytes until next space
447  * INPUTS
448  *   char *str -- the word
449  * RESULT
450  *   int -- length of the next word or 0
451  * AUTHOR
452  *   Koessi
453  * SEE ALSO
454  *   RB_Find_Header_Name()
455  * SOURCE
456  */
457
458 int
459 RB_WordLen (char *str)
460 {
461   int len;
462   char c;
463
464   for (len = 0; ((c = *str) != '\0') && !isspace (c) && (c != '\n');
465        ++str, ++len);
466   return (len);
467 }
468
469 /*** RB_WordLen ***/
470
471
472 /****i* ROBODoc/RB_StrDup [2.01]
473  * NAME
474  *   RB_StrDup
475  * SYNOPSIS
476  *   char *RB_StrDup( char *str )
477  * FUNCTION
478  *   duplicate the given string
479  * INPUTS
480  *   char *str               -- source
481  * RESULT
482  *   char *                  -- destination
483  * AUTHOR
484  *   Koessi
485  * SOURCE
486  */
487
488 char *
489 RB_StrDup (char *str)
490 {
491   char *dupstr;
492   if ((dupstr = malloc ((strlen (str) + 1) * sizeof (char))) != NULL)
493       strcpy (dupstr, str);
494   else
495     RB_Panic ("out of memory! [StrDup]\n");
496   return (dupstr);
497 }
498
499 /*** RB_StrDup ***/
500
501
502 /****f* ROBODoc/RB_CookStr [3.0h]
503  * NAME
504  *   RB_CookStr
505  * SYNOPSIS
506  *   char *RB_CookStr( char *str )
507  * FUNCTION
508  *   duplicate the given string, massaging it for the current output_mode
509  * INPUTS
510  *   char *str               -- source
511  * RESULT
512  *   char *                  -- destination
513  * AUTHOR
514  *   apang
515  * NOTES
516  *   Doesn't try/need to be as aggressive as RB_Generate_Item_Body()
517  * SOURCE
518  */
519
520 char *
521 RB_CookStr (char *str)
522 {
523   static char work_buf[MAX_LINE_LEN];
524   char *cptr, c;
525   int i;
526
527   cptr = work_buf;
528   switch (output_mode)
529     {
530     case LATEX:
531       for (i = 0; ((c = *str++) != '\0') && (i < (MAX_LINE_LEN - 1));)
532         {
533           i++;
534           if (c == '_')
535             {
536               if (i < (MAX_LINE_LEN - 1))
537                 {
538                   *cptr++ = '\\';
539                   *cptr++ = '_';
540                   i++;
541                 }
542               else
543                 {
544                   break;
545                 }
546             }
547           else
548             {
549               *cptr++ = c;
550             }
551         }
552       break;
553
554     case RTF:
555       for (; (c = *str++) != '\0';)
556         {
557           if (isalnum (c) || c == '.' || c == '_')
558             {
559               *cptr++ = c;
560             }
561         }
562       break;
563
564     default:
565       return RB_StrDup (str);
566     }
567
568   *cptr = '\0';
569   return RB_StrDup (work_buf);
570 }
571
572 /*** RB_CookStr ***/
573
574
575 /****f* ROBODoc/RB_Say [2.01]
576  * NAME
577  *   RB_Say                     -- varargs
578  * SYNOPSIS
579  *   void RB_Say( char *what, char *why, ... )
580  * FUNCTION
581  *   say what's going on
582  * INPUTS
583  *   char *format            -- formatstring
584  *    ...                    -- parameters
585  * AUTHOR
586  *   Koessi
587  * SOURCE
588  */
589
590 void
591 RB_Say (char *format,...)
592 {
593   va_list ap;
594
595   if (course_of_action & DO_TELL)
596     {
597       va_start (ap, format);
598       printf ("%s: ", whoami);
599       vprintf (format, ap);
600       va_end (ap);
601     }
602 }
603
604 /*** RB_Say ***/
605
606
607 /****f* ROBODoc/RB_Panic [2.01]
608  * NAME
609  *   RB_Panic -- free resources and shut down
610  * SYNOPSIS
611  *   void RB_Panic( char *format, char *why, ... )
612  * FUNCTION
613  *   Print error message.
614  *   Frees all resources used by robodoc.
615  *   Terminates program
616  * INPUTS
617  *   char *format            -- formatstring
618  *   ...                     -- parameters
619  * AUTHOR
620  *   Koessi
621  * SOURCE
622  */
623
624 void
625 RB_Panic (char *format,...)
626 {
627   va_list ap;
628
629   va_start (ap, format);
630   printf ("%s: FATAL ERROR - [line %d]\n", whoami, line_number);
631   printf ("%s: %s\n%s: ", whoami, line_buffer, whoami);
632   vprintf (format, ap);
633   printf ("%s: closing down...\n", whoami);
634   va_end (ap);
635   RB_Close_The_Shop ();
636   exit (EXIT_FAILURE);
637 }
638
639 /*** RB_Panic ***/
640
641
642
643
644 /****f* ROBODoc/RB_Str_Case_Cmp
645  * NAME
646  *   RB_Str_Case_Cmp
647  * SYNOPSIS
648  *   int      RB_Str_Case_Cmp(char *, char *)
649  *   result = RB_Str_Case_Cmp(s, t)
650  * FUNCTION
651  *   Compare two strings, regardless of the case of the characters.
652  * RESULT
653  *    0  s == t
654  *   -1  s < t
655  *    1  s > t
656  * SOURCE
657  */
658
659 int
660 RB_Str_Case_Cmp (char *s, char *t)
661 {
662   for (; tolower (*s) == tolower (*t); s++, t++)
663     if (*s == '\0')
664       return 0;
665   return (int) (tolower (*s) - tolower (*t));
666 }
667
668 /*********/
669
670
671 /****f* ROBODoc/RB_TimeStamp
672  * NAME
673  *   RB_TimeStamp -- print a time stamp
674  *****
675  */
676
677 void 
678 RB_TimeStamp (FILE * f)
679 {
680   time_t ttp;
681   char timeBuffer[255];
682
683   time (&ttp);
684   strftime (timeBuffer, 255, "%a %b %d %H:%M:%S %Y\n", localtime (&ttp));
685   fprintf (f, "%s", timeBuffer);
686 }