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