Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dtappbuilder / src / abmf / parse_c.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: parse_c.c /main/4 1996/10/02 13:32:03 drk $ */
24 /*
25  * File: parse_c.c
26  *
27  * Parses a C file for stubs merge.
28  */
29
30 #ifndef _POSIX_SOURCE
31 #define _POSIX_SOURCE 1
32 #endif
33
34 #include <stdlib.h>
35 #include <string.h>
36 #include <stdio.h>
37 #include <ctype.h>
38 #include <ab_private/AB.h>
39 #include <ab_private/util_err.h>
40 #include <ab/util_types.h>
41 #include <ab_private/util.h>
42 #include <ab_private/abio.h>
43 #include "parse_cP.h"
44
45 /* DTB_USER_CODE_START */
46 /* DTB_USER_CODE_END*/
47
48 #define MAX_USER_SEGS_PER_SEG   10
49
50 /*
51  * Buffered file
52  */
53 typedef struct
54 {
55     FILE                *stream;
56     BOOL                reverse;
57     BOOL                eof;
58
59     /* the offsets of the last 2 newlines read from the file */
60     long                lastNewlineOff;
61     long                lastNewlineOff2;
62
63     /* DTB_USER_CODE_START */
64     int                 userField1;
65     char                *userField2;
66     /* DTB_USER_CODE_END */
67 } BFileRec, *BFile;
68
69 typedef struct
70 {
71     BOOL        forward;
72     long        offset;
73     long        lastNewlineOff;
74     long        lastNewlineOff2;
75 } BFileStateRec, *BFileState;
76
77 static int      bfile_construct(BFile, FILE *file);
78 static int      bfile_destruct(BFile);
79 static BOOL     bfile_is_forward(BFile file);
80 static BOOL     bfile_is_reverse(BFile file);
81 static int      bfile_get_char(BFile);
82 static int      bfile_backup(BFile, long numBytes);
83 static long     bfile_get_off(BFile);
84 static int      bfile_set_off(BFile, long off);
85 static BOOL     bfile_eof(BFile);
86 static int      bfile_set_file(BFile, FILE *stream);
87 static int      bfile_reverse(BFile);
88 static int      bfile_forward(BFile);
89 static int      bfile_save_state(BFile, BFileState);
90 static int      bfile_restore_state(BFile, BFileState);
91
92
93 typedef enum
94 {
95     COMMENT_UNDEF = 0,
96     COMMENT_SLASH_STAR,
97     COMMENT_SLASH_SLASH,
98     COMMENT_TYPE_NUM_VALUES
99 } COMMENT_TYPE;
100
101
102 typedef enum
103 {
104     MAGIC_CMT_UNDEF = 0,
105     MAGIC_CMT_USER_START,
106     MAGIC_CMT_USER_END,
107     MAGIC_COMMENT_TYPE_NUM_VALUES       /* must be last */
108 } MAGIC_COMMENT_TYPE;
109 #define MAGIC_COMMENT_MAX_LEN   (20)
110 #define MAGIC_COMMENT_MAX_SIZE  (MAGIC_COMMENT_MAX_LEN+1)
111
112 static STRING   magicCommentUserStart = "DTB_USER_CODE_START";
113 static STRING   magicCommentUserEnd = "DTB_USER_CODE_END";
114
115
116 static int      write_func_var_decl(FILE *file, CSeg cseg);
117 static int      write_func_as_strings(FILE *file, CSeg cseg);
118 static int      get_seg(BFile file, CSeg cseg);
119 static int      skip_line(BFile file);
120 static int      skip_string_const(BFile file);
121 static int      skip_char_const(BFile file);
122 static int      skip_white(BFile file);
123 static int      skip_white_and_comment(BFile file);
124 static int      write_c_string(FILE *file, STRING value);
125 static int      find_user_seg_end(BFile file, CUserSegs userSegs);
126 static int      find_func_name(
127                         BFile   file, 
128                         long    funcOff, 
129                         long    bodyOff,
130                         long    *nameOffPtr,
131                         long    *nameLenPtr);
132 static int      find_func_proto(
133                         BFile   file,
134                         long    funcOff,
135                         long    nameOff,
136                         long    bodyOff,
137                         long    *protoOff,
138                         long    *protoLen);
139
140 static int      trim_opening_comment(
141                         BFile   file,
142                         long    *funcOffPtr,
143                         long    *funcLenPtr,
144                         long    protoOff
145                 );
146
147 static int      grab_string_from_file(
148                         STRING *stringPtr,
149                         BFile   file,
150                         long    stringOff,
151                         long    stringLen
152                 );
153 static int      find_seg(
154
155                         BFile           file,
156                         CSEG_TYPE       *csegTypePtr,
157                         char            *namePtr,
158                         long            *segOffPtr,
159                         long            *segLenPtr,
160                         long            *bodyOffPtr,
161                         long            *bodyLenPtr,
162                         CUserSegs       userSegs
163                 );
164
165 static int      find_ident(BFile file, char *buf, int bufSize);
166 static int      find_matching(
167                         BFile           file, 
168                         int             matchChar, 
169                         long            *matchOffPtr,
170                         CUserSegs       userSegs
171                 );
172
173 static BOOL     char_is_legal_for_ident(int iChar, BOOL firstChar);
174
175 static int      skip_comment(
176                         BFile                   file, 
177                         COMMENT_TYPE            type,
178                         MAGIC_COMMENT_TYPE      *magicCommentTypeOutPtr
179                 );
180 static int      skip_slash_star_comment(
181                         BFile                   file, 
182                         MAGIC_COMMENT_TYPE      *magicCommentTypeOutPtr
183                 );
184 static int      skip_slash_slash_comment(
185                         BFile                   file, 
186                         MAGIC_COMMENT_TYPE      *magicCommentTypeOutPtr
187                 );
188 static int      skip_slash_slash_comment_fwd(
189                         BFile                   file, 
190                         MAGIC_COMMENT_TYPE      *magicCommentTypeOutPtr
191                 );
192 static int      skip_slash_slash_comment_bwd(
193                         BFile                   file, 
194                         MAGIC_COMMENT_TYPE      *magicCommentTypeOutPtr
195                 );
196
197 static MAGIC_COMMENT_TYPE       determine_magic_comment_type(STRING cmt);
198 static int      get_char_from_c_file(
199                         BFile                   file, 
200                         MAGIC_COMMENT_TYPE      *magicCommentTypeOutPtr
201                 );
202
203 static COMMENT_TYPE     find_comment_start(BFile file, long *commentOffOut);
204 static int      reverse_string(STRING buf);
205 static int      cvt_offset_to_line(BFile file, long offset);
206 static int      set_user_seg_next_pointers(CSegArray segArray, BFile file);
207 static int      user_seg_construct(CUserSeg userSeg);
208 static BOOL     user_seg_is_valid(CUserSeg userSeg);
209
210
211 /*************************************************************************
212  *************************************************************************
213  **                                                                     **
214  **             Public Entry Points                                     **
215  **                                                                     **
216  *************************************************************************
217  *************************************************************************/
218
219 int
220 abmfP_parse_c_file(FILE *cFile, CSegArray *segmentsOutPtr)
221 {
222     int                 return_value = 0;
223     int                 rc = 0;         /* return code */       
224     int                 numSegs = 0;
225     CSegArray           segArray = NULL;
226     CSegRec             seg;
227     BFileRec            bfileRec;
228     BFile               bfile = &bfileRec;
229
230     bfile_construct(bfile, cFile);
231     segArray = cseg_array_create();
232     if (segArray == NULL)
233     {
234         return_code(ERR_NO_MEMORY);
235     }
236
237     memset(&seg, 0, sizeof(seg));
238     while ((rc = get_seg(bfile, &seg)) >= 0)
239     {
240         /*
241         if (debugging())
242         {
243             int         i = 0;
244             util_dprintf(1, "Seg: %s  lines:%d-%d length:%ld userSegs:%d\n", 
245                 seg.type == CSEG_GLOBAL? "[GLOBAL]": util_strsafe(seg.name),
246                 cvt_offset_to_line(bfile, seg.offset),
247                 cvt_offset_to_line(bfile, seg.offset + seg.length 
248                                         + (seg.length==0? 0:-1)),
249                 seg.length,
250                 seg.userSegs.numSegs);
251
252             for (i = 0; i < seg.userSegs.numSegs; ++i)
253             {
254                 STRING  string = NULL;
255                 util_dprintf(1, "    =>UserSeg: %d-%ld [%ld+%ld bytes]\n",
256                     cvt_offset_to_line(bfile, seg.userSegs.segs[i].offset),
257                     cvt_offset_to_line(bfile, seg.userSegs.segs[i].offset +
258                                 + seg.userSegs.segs[i].length
259                                 + (seg.userSegs.segs[i].length<1? 0:-1)),
260                     seg.userSegs.segs[i].offset,
261                     seg.userSegs.segs[i].length);
262                 grab_string_from_file(&string, bfile,
263                         seg.userSegs.segs[i].offset,
264                         seg.userSegs.segs[i].length);
265                 util_dprintf(1, "|%s|\n", util_strsafe(string));
266                 util_free(string);
267             }
268         }
269         */
270
271         ++numSegs;
272         segArray->segs = (CSeg)realloc(
273                                 segArray->segs, numSegs * sizeof(CSegRec));
274         if (segArray->segs == NULL)
275         {
276             cseg_array_destroy(segArray);
277             util_printf_err("Out of memory!\n");
278             return_code(-1);
279         }
280         segArray->segs[numSegs-1] = seg;
281         memset(&seg, 0, sizeof(seg));
282     }
283     segArray->numSegs = numSegs;
284
285     if ((rc < 0) && (rc != ERR_EOF))
286     {
287         /* failure occured */
288         segArray->numSegs = 0;
289         return_code(rc);
290     }
291     else
292     {
293         segArray->numSegs = numSegs;
294     }
295
296     /*
297      * Set up all user segment next pointers
298      */
299     set_user_seg_next_pointers(segArray, bfile);
300     return_value = numSegs;
301
302 epilogue:
303     *segmentsOutPtr = segArray;
304     bfile_destruct(bfile);
305     return return_value;
306 }
307
308
309 /*************************************************************************
310  **                                                                     **
311  **             PRIVATE SYMBOLS                                         **
312  **                                                                     **
313  *************************************************************************
314  *************************************************************************/
315
316 static int
317 set_user_seg_next_pointers(CSegArray segArray, BFile file)
318 {
319     CSeg        curSeg = NULL;
320     CUserSeg    curUserSeg = NULL;
321     CUserSeg    lastUserSeg = NULL;
322     int         segCount = 0;
323     int         userSegCount = 0;
324
325     for (segCount = 0; segCount < segArray->numSegs; ++segCount)
326     {
327         curSeg = &(segArray->segs[segCount]);
328         for (userSegCount = 0; userSegCount < curSeg->userSegs.numSegs; 
329             ++userSegCount)
330         {
331             curUserSeg = &(curSeg->userSegs.segs[userSegCount]);
332             if (lastUserSeg == NULL)
333             {
334                 /* first user segment */
335                 segArray->firstUserSeg = curUserSeg;
336             }
337             else
338             {
339                 lastUserSeg->next = curUserSeg;
340             }
341
342             curUserSeg->line = -1;
343             curUserSeg->line = cvt_offset_to_line(file, curUserSeg->offset);
344             lastUserSeg = curUserSeg;
345         }
346     }
347
348     return 0;
349 }
350
351
352 static BOOL
353 char_is_legal_for_ident(int iChar, BOOL firstChar)
354 {
355     return
356         (   (iChar == '_')
357          || (firstChar? isalpha(iChar):isalnum(iChar)) );
358 }
359
360
361 static int
362 find_seg(
363                 BFile           file,
364                 CSEG_TYPE       *segTypePtr,
365                 char            *namePtr,
366                 long            *segOffPtr,
367                 long            *segLenPtr,
368                 long            *bodyOffPtr,
369                 long            *bodyLenPtr,
370                 CUserSegs       userSegs
371 )
372 {
373     int         return_value = 0;
374     long        segOff = 0;
375     long        segLen = 0;
376     long        openingParenOff = 0;
377     long        openingBraceOff = 0;
378     long        closingBraceOff = 0;
379     long        identOff = 0;
380     int         iChar = -1;
381     char        ident[1024];
382     int         identLen = 0;
383     BOOL        lookForIdent = TRUE;
384     CSEG_TYPE   segType = CSEG_UNDEF;
385     MAGIC_COMMENT_TYPE  magicCommentType = MAGIC_CMT_UNDEF;
386     *ident = 0;
387
388     if (bfile_eof(file))
389     {
390         return_code(ERR_EOF);
391     }
392
393     *namePtr = 0;
394     segOff = bfile_get_off(file);       /* for global segments */
395
396     while ((segType == CSEG_UNDEF) && (!bfile_eof(file)))
397     {
398         /*
399          * Scan, looking for opening {
400          */             /* } vi hack */
401         openingBraceOff = -1;
402         while ((openingBraceOff < 0) && (!bfile_eof(file)))
403         {
404             iChar = get_char_from_c_file(file, &magicCommentType);
405
406             if (iChar == EOF)
407             {
408                 continue;
409             }
410
411             if (magicCommentType != MAGIC_CMT_UNDEF)
412             {
413                 /*
414                  * Found user seg in global segment
415                  */
416                 CUserSeg        userSeg = NULL;
417                 ++(userSegs->numSegs);
418                 userSeg = &(userSegs->segs[(userSegs->numSegs)-1]);
419                 user_seg_construct(userSeg);
420                 if (iChar != '\n')
421                 {
422                     skip_line(file);
423                 }
424                 userSeg->offset = bfile_get_off(file);
425
426                 if (find_user_seg_end(file, userSegs) < 0)
427                 {
428                     return_code(-1);
429                 }
430                 segLen = bfile_get_off(file) - segOff + 1;
431             }
432
433             if (iChar == '{') /* } vi hack */
434             {
435                 openingBraceOff = (bfile_get_off(file)-1);
436                 if (userSegs->numSegs > 0)
437                 {
438                     /* we found global segs before this object */
439                     segType = CSEG_GLOBAL;
440                     bfile_backup(file, 1);
441                     segLen = bfile_get_off(file) - segOff + 1;
442                     goto epilogue;
443                 }
444             }
445         } /* while openingBraceOff < 0 */
446         if (openingBraceOff < 0)
447         {
448             /*
449              * Global segment, or end of file
450              */
451             if (bfile_get_off(file) > segOff)
452             {
453                 /* found segment at end of file */
454                 segType = CSEG_GLOBAL;
455             }
456             else if (iChar == EOF)
457             {
458                 return_value = ERR_EOF;
459             }
460             else
461             {
462                 return_value = -1;
463             }
464             goto epilogue;
465         }
466         segOff = openingBraceOff;
467     
468         /*
469          * Look for preceding ')', or ident
470          */
471         bfile_set_off(file, openingBraceOff-1);
472         bfile_reverse(file);
473
474         openingParenOff = -1;
475         lookForIdent = TRUE;
476         identLen = 0;
477         while (lookForIdent)
478         {
479             iChar = get_char_from_c_file(file, NULL);
480             if (iChar == EOF)
481             {
482                 lookForIdent = FALSE;
483             }
484             else if (iChar == ';')
485             {
486                 if (openingParenOff >= 0)
487                 {
488                     lookForIdent = FALSE;       /* end of parse */
489                 }
490                 else
491                 {
492                     /* if a ; is seen between () and {}, it should be an
493                      * old-style parameter list declaration
494                      */
495                     identLen = 0;
496                 }
497             }
498             else if (iChar == ')')
499             {
500                 /* no ident - look for () */
501                 segType = CSEG_FUNC;
502                 if (find_matching(file, '(', &openingParenOff, NULL)
503                                 /* ) vi hack */                 >= 0)
504                 {
505                     segType = CSEG_FUNC;
506                     identLen = 0;
507                 }
508                 else
509                 {
510                     util_printf_err(
511                         "Bad function definition at or near line %d\n",
512                         cvt_offset_to_line(file, openingBraceOff-2));
513                     lookForIdent = FALSE;
514                     identLen = 0;
515                     return_code(-1);
516                 }
517             }
518             else if (iChar == ']')
519             {
520                 if (find_matching(file, '[', NULL, NULL) >= 0) /* ] vi hack */
521                 {
522                     segType = CSEG_AGGREGATE_VAR;
523                     identLen = 0;
524                 }
525                 else
526                 {
527                     util_printf_err("Unbalanced '[' at or near line %d\n",
528                         cvt_offset_to_line(file, bfile_get_off(file)));
529                         /* ] vi hack */
530                     lookForIdent = FALSE;
531                     identLen = 0;
532                     return_code(-1);
533                 }
534             }
535             else 
536             {
537                 if (char_is_legal_for_ident(iChar, FALSE))
538                 {
539                     ident[identLen++] = iChar;
540                 }
541                 else if (identLen > 0)
542                 {
543                     /* found end of ident */
544                     lookForIdent = FALSE;
545                 }
546             }
547         } /* lookForIdent */
548         ident[identLen] = 0;
549         reverse_string(ident);          /* was read backwards */
550     
551         /*
552          * If it's a function, find the function name
553          * NB: bfile is reversed
554          */
555         if (identLen < 1)
556         {
557             long        off = bfile_get_off(file);
558             *ident = 0;
559             if (find_ident(file, ident, 1024) < 0)
560             {
561                 util_printf_err("Syntax error at or near line %d\n",
562                         cvt_offset_to_line(file, off));
563                 return_code(-1);
564             }
565             else
566             {
567                 segOff = identOff = (bfile_get_off(file)+1);
568             }
569         }
570     
571         /*
572          * If undef, it should be a type definition.
573          * NB: bfile is reversed
574          */
575         if ((identLen > 0) && (segType == CSEG_UNDEF))
576         {
577             ident[identLen] = 0;
578             lookForIdent = FALSE;
579
580             if (   util_streq(ident, "struct")
581                 || util_streq(ident, "union")
582                 || util_streq(ident, "enum")
583                 || util_streq(ident, "class") )
584             {
585                 identLen = 0;
586                 segType = CSEG_AGGREGATE_TYPE;
587             }
588             else
589             {
590                 /*
591                  * This could be a variable assignment or an aggregate
592                  * type. The ident is the proper name for this one.
593                  */
594                 segType = CSEG_AGGREGATE_TYPE;
595             }
596         } /* segType == CSEG_UNDEF */
597     
598         /*
599          * file is reversed
600          * Get closing brace to find end.
601          */
602         bfile_forward(file);
603         bfile_set_off(file, openingBraceOff); 
604         bfile_get_char(file);           /* skip brace */
605         /* { vi hack */
606         if (find_matching(file, '}', &closingBraceOff, userSegs) < 0)
607         {
608             util_printf_err("Unbalanced '{' at line %d.\n", /* } vi hack */
609                 cvt_offset_to_line(file, openingBraceOff));
610             return_code(-1);
611         }
612     
613         /*
614          * If name is still undef, it should be an aggregate type, and
615          * the name should follow the closing brace.
616          *
617          * file is forward.
618          */
619         if ((identLen < 1) && (segType != CSEG_FUNC))
620         {
621             if (find_ident(file, ident, 1024) >= 0)
622             {
623                 segType = CSEG_AGGREGATE_TYPE;
624             }
625         }
626     } /* while segType */
627     
628 epilogue:
629     (*segTypePtr) = segType;
630     (*segOffPtr) = segOff;
631     (*segLenPtr) = segLen;
632     (*bodyOffPtr) = openingBraceOff;
633     (*bodyLenPtr) = (closingBraceOff - openingBraceOff) + 1;
634     util_strncpy(namePtr, ident, 1024);
635     if ((segType != CSEG_UNDEF) && (segType != CSEG_GLOBAL))
636     {
637         /* {} segment - calculate metrics by braces 
638          */
639         (*bodyOffPtr) = openingBraceOff;
640         (*bodyLenPtr) = (closingBraceOff - openingBraceOff) + 1;
641         (*segLenPtr) = closingBraceOff - segOff + 1;
642     }
643
644     if (   (return_value >= 0)
645         && ((segType == CSEG_UNDEF) || ((*segOffPtr) < 0) || ((*segLenPtr) < 0))
646        )
647     {
648         return_value = -1;
649     }
650
651     return return_value;
652 }
653
654
655 /*
656  * Finds the end of a user segment.
657  * Assumes: beginning of segment as been read.
658  * Effects: reads past entire segment
659  */
660 static int
661 find_user_seg_end(BFile file, CUserSegs userSegs)
662 {
663     int                 return_value = 0;
664     BOOL                segmentIsBad = FALSE;
665     int                 iChar = -1;
666     MAGIC_COMMENT_TYPE  magicCommentType = MAGIC_CMT_UNDEF;
667     CUserSeg            userSeg = &(userSegs->segs[(userSegs->numSegs)-1]);
668     long                segEndOff = -1;
669
670     if (userSegs->numSegs < 1)
671     {
672         return_code(ERR_CLIENT);
673     }
674
675     segEndOff = bfile_get_off(file)-1;
676     for (iChar = EOF+1;
677         (iChar != EOF) && (magicCommentType == MAGIC_CMT_UNDEF);
678         iChar = get_char_from_c_file(file, &magicCommentType) )
679     {
680         if (iChar == '\n')
681         {
682             segEndOff = file->lastNewlineOff;
683         }
684     }
685
686     if (magicCommentType != MAGIC_CMT_USER_END)
687     {
688         segmentIsBad = TRUE;
689         return_value = -1;
690     }
691     else
692     {
693         if (iChar != '\n')
694         {
695             skip_line(file);
696         }
697         /* include final newline */
698         userSeg->length = segEndOff - userSeg->offset + 1;
699         if (userSeg->length < 0)
700         {
701             userSeg->length = 0;
702         }
703     }
704
705     if (!user_seg_is_valid(userSeg))
706     {
707         segmentIsBad = TRUE;
708         --(userSegs->numSegs);
709         return_value = ERR_INTERNAL;
710     }
711
712     if (segmentIsBad)
713     {
714         util_printf_err("Bad DTB_USER segment, line %d\n", 
715                 cvt_offset_to_line(file, userSeg->offset));
716         return_code(-1);
717     }
718
719 epilogue:
720     return return_value;
721 }
722
723
724 static int
725 find_ident(
726                         BFile   file,
727                         char    *buf,
728                         int     bufSize
729 )
730 {
731     BOOL        foundIdent = FALSE;
732     int         iChar = 0;
733     int         bufLen = 0;
734
735     *buf = 0;
736     skip_white_and_comment(file);
737     while (TRUE)
738     {
739         iChar = bfile_get_char(file);
740         if ((iChar == EOF) || (!char_is_legal_for_ident(iChar, FALSE)))
741         {
742             break;
743         }
744         else if (bufLen >= (bufSize-1))
745         {
746             break;
747         }
748         else
749         {
750             buf[bufLen++] = iChar;
751         }
752     }
753     buf[bufLen] = 0;
754     foundIdent = ((*buf) != 0);
755
756     if (foundIdent && bfile_is_reverse(file))
757     {
758         reverse_string(buf);
759     }
760
761     /* if (foundIdent)
762     {
763         printf("found ident '%s'\n", buf);
764     }*/
765
766     return foundIdent? 0:-1;
767 }
768
769
770 static int
771 reverse_string(STRING buf)
772 {
773     int         bufLen = strlen(buf);
774     int         i;
775     int         tempChar;
776
777     for (i = 0; i < (bufLen/2); ++i)
778     {
779         tempChar = buf[i];
780         buf[i] = buf[bufLen-1-i];
781         buf[bufLen-1-i] = tempChar;
782     }
783     return 0;
784 }
785
786
787 /*
788  * Gets the next C segment from the file.
789  */
790
791 get_seg(BFile file, CSeg cseg)
792 {
793     int         return_value = 0;
794     int         rc = 0;         /* return code */
795     BOOL        foundSeg = FALSE;
796     CSEG_TYPE   segType = CSEG_UNDEF;
797     long        segOff = -1;
798     long        segLen = -1;
799     long        bodyOff = -1;
800     long        bodyLen = -1;
801     long        nameOff = -1;
802     long        nameLen = -1;
803     long        protoOff = -1;
804     long        protoLen = -1;
805     BOOL        abort = FALSE;
806     BOOL        err = FALSE;
807     long        off = 0;
808     char        segName[1024];
809     int         i = 0;
810     CUserSegsRec        userSegs;
811
812     userSegs.numSegs = 0;
813     cseg->type = CSEG_UNDEF;
814     rc = find_seg(file,
815                     &segType, segName, &segOff, &segLen, &bodyOff, &bodyLen,
816                     &userSegs);
817     return_if_err(rc,rc);
818
819     /*
820      * Put the info into the func structure
821      */
822     cseg->type = segType;
823     cseg->name = strdup(segName);
824     cseg->offset = segOff;
825     cseg->length = segLen;
826     cseg->text = NULL;
827     cseg->declaration = NULL;
828     cseg->userSegs = userSegs;
829     for (i = 0; i < cseg->userSegs.numSegs; ++i)
830     {
831         grab_string_from_file(&(cseg->userSegs.segs[i].text),
832                 file, 
833                 cseg->userSegs.segs[i].offset, 
834                 cseg->userSegs.segs[i].length);
835     }
836
837 epilogue:
838     return return_value;
839 }
840
841
842 static int
843 grab_string_from_file(
844                         STRING *stringPtr,
845                         BFile   file,
846                         long    stringOff,
847                         long    stringLen
848 )
849 {
850 #define string (*stringPtr)
851     int         returnValue = 0;
852
853     if (stringLen < 1)
854     {
855         string = strdup("");
856     }
857     else
858     {
859         BFileStateRec   fileState;
860
861         bfile_save_state(file, &fileState);
862         string = (STRING)util_malloc((size_t)(stringLen + 1));
863         bfile_set_off(file, stringOff);
864         fread(string, 1, (size_t)stringLen, file->stream);
865         string[stringLen]= 0;
866         bfile_restore_state(file, &fileState);
867     }
868
869     return returnValue;
870 #undef string
871 }
872
873
874 /*
875  * userSegs is ignored, if it is NULL
876  */
877 static int
878 find_matching(
879                         BFile           file, 
880                         int             matchChar, 
881                         long            *matchOffPtr,
882                         CUserSegs       userSegs
883 )
884 {
885     int         return_value = 0;
886     int         iChar = -1;
887     long        lCharOff = 0;
888     long        matchOff = -1;
889     BOOL        foundMatching = FALSE;
890     BOOL        quit = FALSE;
891     long        startOff = bfile_get_off(file);
892     MAGIC_COMMENT_TYPE  magicCommentType =  MAGIC_CMT_UNDEF;
893
894     while ((!quit) && (!bfile_eof(file)))
895     {
896         iChar = get_char_from_c_file(file, &magicCommentType);
897         lCharOff = bfile_get_off(file);
898
899         /*
900          * Process magic comments
901          */
902         if (userSegs != NULL)
903         {
904             switch (magicCommentType)
905             {
906                 case MAGIC_CMT_USER_START:
907                     if (   (userSegs->numSegs > 0) 
908                         && (!user_seg_is_valid(
909                                &(userSegs->segs[(userSegs->numSegs)-1]))))
910                     {
911                         /* last segment was not terminated */
912                         --(userSegs->numSegs);
913                     }
914                     else
915                     {
916                         CUserSeg        userSeg = NULL;
917
918                         if (iChar != '\n')
919                         {
920                             skip_line(file);
921                         }
922                         ++(userSegs->numSegs);
923                         userSegs->segs[(userSegs->numSegs)-1].offset 
924                                                     = bfile_get_off(file);
925                         userSegs->segs[(userSegs->numSegs)-1].length = -1;
926                         userSeg = &(userSegs->segs[(userSegs->numSegs)-1]);
927                         user_seg_construct(userSeg);
928                         userSeg->offset = bfile_get_off(file);
929
930                         if (find_user_seg_end(file, userSegs) < 0)
931                         {
932                             return_code(-1);
933                         }
934                     }
935                 break;
936
937                 case MAGIC_CMT_USER_END:
938                     /*
939                      * This should have been found by find_user_seg_end().
940                      */
941                     util_printf_err("Bad DTB_USER segment at line %d\n", 
942                             cvt_offset_to_line(file, bfile_get_off(file))-1);
943                     return_code(-1);
944                 break;
945             }
946         } /* userSegs != NULL */
947
948         if (iChar == matchChar)
949         {
950             quit = TRUE;
951             foundMatching = TRUE;
952         }
953         else
954         {
955             switch (iChar)
956             {
957             case EOF:
958                 quit = TRUE;
959              break;
960
961              case '"':
962                  skip_string_const(file);
963              break;
964
965              case '\'':
966                  skip_char_const(file);
967              break;
968
969              case '{':
970                  if (find_matching(file, '}', NULL, userSegs) < 0)
971                  {
972                      util_printf_err("Unbalanced '{' at line %d.\n",
973                         cvt_offset_to_line(file, lCharOff));
974                      return_code(-1);
975                  }
976              break;
977
978              case '}':
979                  if (find_matching(file, '{', NULL, userSegs) < 0)
980                  {
981                      util_printf_err("Unbalanced '}' at line %d.\n",
982                         cvt_offset_to_line(file, lCharOff));
983                      return_code(-1);
984                  }
985             break;
986
987             case '(':
988                 if (find_matching(file, ')', NULL, userSegs) < 0)
989                 {
990                     util_printf_err("Unbalanced '(' at line %d.\n",
991                         cvt_offset_to_line(file, lCharOff));
992                     return_code(-1);
993                 }
994             break;
995
996             case ')':
997                 if (find_matching(file, '(', NULL, userSegs) < 0)
998                 {
999                     util_printf_err("Unbalanced ')' at line %d.\n",
1000                         cvt_offset_to_line(file, lCharOff));
1001                     return_code(-1);
1002                 }
1003             break;
1004             } /* switch iChar */
1005         } /* ! iChar==matchChar */
1006     } /* while !quit... */
1007
1008 epilogue:
1009     if (foundMatching)
1010     {
1011         /* printf("<<match found(%c) for %ld>>\n", matchChar, startOff); */
1012         if (matchOffPtr != NULL)
1013         {
1014             matchOff = bfile_get_off(file) + (file->reverse? 1:-1);
1015             *matchOffPtr = matchOff;
1016         }
1017     }
1018     if ((return_value >= 0) && (!foundMatching))
1019     {
1020         return_value = -1;
1021     }
1022
1023     return return_value;
1024 }
1025
1026
1027 static int
1028 user_seg_construct(CUserSeg userSeg)
1029 {
1030     memset(userSeg, 0, sizeof(*userSeg));
1031     userSeg->offset = -1;
1032     userSeg->length = -1;
1033     return 0;
1034 }
1035
1036
1037 static BOOL
1038 user_seg_is_valid(CUserSeg userSeg)
1039 {
1040     return (   (userSeg->offset > -1)
1041             && (userSeg->length > -1) );
1042 }
1043
1044
1045 static int
1046 skip_line(BFile file)
1047 {
1048     int         iChar = 0;
1049     while (((iChar = bfile_get_char(file)) != EOF) && (iChar != '\n'))
1050     {
1051     }
1052     return 0;
1053 }
1054
1055
1056 /*
1057  * Assumes: opening " has been read
1058  */
1059 static int
1060 skip_string_const(BFile file)
1061 {
1062     int         iChar = 0;
1063     while (((iChar = bfile_get_char(file)) != EOF)
1064            && (iChar != '\n')
1065            && (iChar != '"') )
1066     {
1067         if (iChar == '\\')
1068         {
1069             bfile_get_char(file);
1070         }
1071     }
1072     return 0;
1073 }
1074
1075
1076 /*
1077  * Assumes: opening ' has been read
1078  */
1079 static int
1080 skip_char_const(BFile file)
1081 {
1082     int         iChar = 0;
1083     while (((iChar = bfile_get_char(file)) != EOF)
1084            && (iChar != '\n')
1085            && (iChar != '\'') )
1086     {
1087         if (iChar == '\\')
1088         {
1089             bfile_get_char(file);
1090         }
1091     }
1092     return 0;
1093 }
1094
1095
1096 static int
1097 skip_white(BFile file)
1098 {
1099     int iChar = bfile_get_char(file);
1100
1101     while ((iChar != EOF) && (isspace(iChar)))
1102     {
1103         iChar = bfile_get_char(file);
1104     }
1105     if (iChar != EOF)
1106     {
1107         bfile_backup(file, 1);
1108     }
1109     return 0;
1110 }
1111
1112
1113 static int
1114 skip_white_and_comment(BFile file)
1115 {
1116     int iChar = get_char_from_c_file(file, NULL);
1117
1118     while ((iChar != EOF) && (isspace(iChar)))
1119     {
1120         iChar = get_char_from_c_file(file, NULL);
1121     }
1122     if (iChar != EOF)
1123     {
1124         bfile_backup(file, 1);
1125     }
1126     return 0;
1127 }
1128
1129
1130 /*
1131  * Gets a char from a C source file, skipping comments
1132  */
1133 static int
1134 get_char_from_c_file(
1135                         BFile                   file,
1136                         MAGIC_COMMENT_TYPE      *magicCommentTypeOutPtr
1137 )
1138 {
1139     int         iChar = EOF;
1140     BOOL        done = FALSE;
1141
1142     if (magicCommentTypeOutPtr != NULL)
1143     {
1144         *magicCommentTypeOutPtr = MAGIC_CMT_UNDEF;
1145     }
1146
1147     while (!done)
1148     {
1149         iChar = bfile_get_char(file);
1150         switch (iChar)
1151         {
1152             case EOF:
1153                 done = TRUE;
1154             break;
1155
1156             case '\n':
1157                 if (bfile_is_forward(file))
1158                 {
1159                     done = TRUE;
1160                 }
1161                 else
1162                 {
1163                     if (skip_slash_slash_comment(file, magicCommentTypeOutPtr) < 0)
1164                     {
1165                         /* no comment */
1166                         done = TRUE;
1167                     }
1168                 }
1169             break;
1170
1171             case '/':
1172                 if (bfile_is_forward(file))
1173                 {   
1174                     iChar = bfile_get_char(file);
1175                     if (iChar == '/')
1176                     {
1177                         skip_slash_slash_comment(file, magicCommentTypeOutPtr);
1178                     }
1179                     else if (iChar == '*')
1180                     {
1181                         skip_slash_star_comment(file, magicCommentTypeOutPtr);
1182                     }
1183                     else
1184                     {
1185                         bfile_backup(file, 1);
1186                     }
1187                 }
1188                 else
1189                 {
1190                     /* reversed file */
1191                     if ((iChar = bfile_get_char(file)) == '*')
1192                     {
1193                         skip_slash_star_comment(file, magicCommentTypeOutPtr);
1194                     }
1195                     else
1196                     {
1197                         bfile_backup(file, 1);
1198                     }
1199                 }
1200             break;
1201
1202             default:
1203                 done = TRUE;
1204             break;
1205         }
1206     } /* while !done */
1207
1208     return iChar;
1209 }
1210
1211
1212 static int
1213 skip_comment(
1214                         BFile                   file,
1215                         COMMENT_TYPE            commentType, 
1216                         MAGIC_COMMENT_TYPE      *magicCommentTypeOutPtr
1217 )
1218 {
1219     int         return_value = -1;
1220
1221     if (magicCommentTypeOutPtr != NULL)
1222     {
1223         *magicCommentTypeOutPtr = MAGIC_CMT_UNDEF;
1224     }
1225
1226     switch(commentType)
1227     {
1228         case COMMENT_SLASH_STAR:
1229             return_value = skip_slash_star_comment(
1230                                 file, magicCommentTypeOutPtr);
1231         break;
1232
1233         case COMMENT_SLASH_SLASH:
1234             return_value = skip_slash_slash_comment(
1235                                 file, magicCommentTypeOutPtr);
1236         break;
1237     }
1238
1239     return return_value;
1240 }
1241
1242
1243 static int
1244 skip_slash_slash_comment(
1245                         BFile                   file,
1246                         MAGIC_COMMENT_TYPE      *magicCommentTypeOutPtr
1247 )
1248 {
1249     int         return_value = -1;
1250
1251     if (bfile_is_forward(file))
1252     {
1253         return_value = skip_slash_slash_comment_fwd(
1254                                 file, magicCommentTypeOutPtr);
1255     }
1256     else
1257     {
1258         return_value = skip_slash_slash_comment_bwd(
1259                                 file, magicCommentTypeOutPtr);
1260     }
1261     return return_value;
1262 }
1263
1264
1265 static int
1266 skip_slash_slash_comment_fwd(
1267                         BFile                   file, 
1268                         MAGIC_COMMENT_TYPE      *magicCommentTypeOutPtr
1269 )
1270 {
1271     int         iChar = 0;
1272     char        cmtBuf[MAGIC_COMMENT_MAX_SIZE];
1273     int         cmtBufLen = 0;
1274
1275     while ((iChar != EOF) && (iChar != '\n'))
1276     {
1277         iChar = bfile_get_char(file);
1278         if (   ((char_is_legal_for_ident(iChar, FALSE)) || (cmtBufLen > 0))
1279             && (cmtBufLen < MAGIC_COMMENT_MAX_LEN) )
1280         {
1281             cmtBuf[cmtBufLen++] = iChar;
1282         }
1283     }
1284     cmtBuf[cmtBufLen] = 0;
1285
1286     if (magicCommentTypeOutPtr != NULL)
1287     {
1288         *magicCommentTypeOutPtr = determine_magic_comment_type(cmtBuf);
1289     }
1290     return 0;
1291 }
1292
1293
1294 static int
1295 skip_slash_slash_comment_bwd(
1296                         BFile                   file, 
1297                         MAGIC_COMMENT_TYPE      *magicCommentTypeOutPtr
1298 )
1299 {
1300     long        startOff = bfile_get_off(file);
1301     BOOL        foundCommentStart = FALSE;
1302     BOOL        done = FALSE;
1303     int         iChar = 0;
1304
1305     if (magicCommentTypeOutPtr != NULL)
1306     {
1307         *magicCommentTypeOutPtr = MAGIC_CMT_UNDEF;
1308     }
1309     while (!done)
1310     {
1311         iChar = bfile_get_char(file);
1312         switch (iChar)
1313         {
1314             case '\n':
1315             case EOF:
1316                 done = TRUE;
1317             break;
1318
1319             case '/':
1320                 if ((iChar = bfile_get_char(file)) == '/')
1321                 {
1322                     foundCommentStart = TRUE;
1323                     done = TRUE;
1324                 }
1325                 else
1326                 {
1327                     bfile_backup(file, 1);
1328                 }
1329             break;
1330         }
1331     }
1332
1333     if (!foundCommentStart)
1334     {
1335         bfile_set_off(file, startOff);
1336     }
1337
1338     return (foundCommentStart? 0:-1);
1339 }
1340
1341
1342 static int
1343 skip_slash_star_comment(
1344                         BFile                   file, 
1345                         MAGIC_COMMENT_TYPE      *magicCommentTypeOutPtr
1346 )
1347 {
1348     int         iChar = 0;
1349     BOOL        done = FALSE;
1350     BOOL        foundCommentEnd = FALSE;
1351     char        cmtBuf[MAGIC_COMMENT_MAX_SIZE];
1352     int         cmtBufLen = 0;
1353
1354     while (!done)
1355     {
1356         iChar = bfile_get_char(file);
1357
1358         if (iChar == EOF)
1359         {
1360             done = TRUE;
1361             continue;
1362         }
1363
1364         if (   ((char_is_legal_for_ident(iChar, FALSE)) || (cmtBufLen > 0))
1365             && (cmtBufLen < MAGIC_COMMENT_MAX_LEN) )
1366         {
1367             cmtBuf[cmtBufLen++] = iChar;
1368         }
1369
1370         if (iChar == '*')
1371         {
1372             if ((iChar = bfile_get_char(file)) == '/')
1373             {
1374                 foundCommentEnd = TRUE;
1375                 done = TRUE;
1376             }
1377             else
1378             {
1379                 bfile_backup(file, 1);
1380             }
1381         }
1382     }
1383     cmtBuf[cmtBufLen] = 0;
1384     if (magicCommentTypeOutPtr != NULL)
1385     {
1386         *magicCommentTypeOutPtr = determine_magic_comment_type(cmtBuf);
1387     }
1388
1389     return (foundCommentEnd? 0:-1);
1390 }
1391
1392
1393 static MAGIC_COMMENT_TYPE
1394 determine_magic_comment_type(STRING cmt)
1395 {
1396     MAGIC_COMMENT_TYPE  magicType = MAGIC_CMT_UNDEF;
1397     static int          startLen = -1;
1398     static int          endLen = -1;
1399
1400     if (startLen < 0)
1401     {
1402         startLen = strlen(magicCommentUserStart);
1403         endLen = strlen(magicCommentUserEnd);
1404     }
1405
1406     if (strncmp(cmt, magicCommentUserStart, startLen) == 0)
1407     {
1408         magicType = MAGIC_CMT_USER_START;
1409     }
1410     else if (strncmp(cmt, magicCommentUserEnd, endLen) == 0)
1411     {
1412         magicType = MAGIC_CMT_USER_END;
1413     }
1414
1415     return magicType;
1416 }
1417
1418
1419 /*************************************************************************
1420  **                                                                     **
1421  **             BFile                                                   **
1422  **                                                                     **
1423  *************************************************************************/
1424 static BOOL bfileP_set_eof(BFile file);
1425
1426 static int
1427 bfile_construct(BFile file, FILE *stream)
1428 {
1429     file->stream = NULL;
1430     file->reverse = FALSE;
1431     file->lastNewlineOff = -1;
1432     file->lastNewlineOff2 = -1;
1433     file->eof = TRUE;
1434
1435     return bfile_set_file(file, stream);
1436 }
1437
1438
1439 static int
1440 bfile_destruct(BFile file)
1441 {
1442     return bfile_set_file(file, NULL);
1443 }
1444
1445
1446 static BOOL
1447 bfile_eof(BFile file)
1448 {
1449     return file->eof;
1450 }
1451
1452
1453 static BOOL
1454 bfile_is_forward(BFile file)
1455 {
1456     return (!(file->reverse));
1457 }
1458
1459
1460 static BOOL
1461 bfile_is_reverse(BFile file)
1462 {
1463     return file->reverse;
1464 }
1465
1466
1467 static int
1468 bfile_get_char(BFile file)
1469 {
1470     int         iChar = EOF;
1471
1472     if (file->eof)
1473     {
1474         goto epilogue;
1475     }
1476
1477     iChar = fgetc(file->stream);
1478     if (iChar == EOF)
1479     {
1480         if (file->reverse)
1481         {
1482             if (fseek(file->stream, -1, SEEK_END) == 0)
1483             {
1484                 iChar = fgetc(file->stream);
1485             }
1486             else
1487             {
1488                 goto epilogue;
1489             }
1490         }
1491         else
1492         {
1493             goto epilogue;
1494         }
1495     }
1496
1497     if (file->reverse)
1498     {
1499         if (fseek(file->stream, -2, SEEK_CUR) != 0)
1500         {
1501            file->eof = TRUE;
1502         }
1503     }
1504
1505 epilogue:
1506     if (iChar == EOF)
1507     {
1508         file->eof = TRUE;
1509     }
1510     if (iChar == '\n')
1511     {
1512         file->lastNewlineOff2 = file->lastNewlineOff;
1513         file->lastNewlineOff = (bfile_get_off(file) + (file->reverse? 1:-1));
1514     }
1515
1516     return iChar;
1517 }
1518
1519
1520 static int
1521 bfile_backup(BFile file, long numBytes)
1522 {
1523     int         returnValue = 0;
1524     long        posChange = 0;
1525
1526     if (file->reverse)
1527     {
1528         posChange = numBytes;
1529     }
1530     else
1531     {
1532         posChange = -1 * numBytes;
1533     }
1534
1535     if (fseek(file->stream, posChange, SEEK_CUR) == 0)
1536     {
1537         file->eof = FALSE;
1538     }
1539     else
1540     {
1541         file->eof = TRUE;
1542         returnValue = -1;
1543     }
1544
1545     return returnValue;
1546 }
1547
1548
1549 static int
1550 bfile_set_file(BFile file, FILE *stream)
1551 {
1552     file->stream = stream;
1553     file->reverse = FALSE;
1554     bfileP_set_eof(file);
1555     return 0;
1556 }
1557
1558
1559 static int
1560 bfile_reverse(BFile file)
1561 {
1562     file->reverse = TRUE;
1563     bfileP_set_eof(file);
1564     return 0;
1565 }
1566
1567 static int
1568 bfile_forward(BFile file)
1569 {
1570     file->reverse = FALSE;
1571     bfileP_set_eof(file);
1572     return 0;
1573 }
1574
1575
1576 static long
1577 bfile_get_off(BFile file)
1578 {
1579     long        off = -1;
1580
1581     if (file->reverse)
1582     {
1583         if (file->eof)
1584         {
1585             off = -1;
1586         }
1587         else
1588         {
1589             off = ftell(file->stream);
1590         }
1591     }
1592     else
1593     {
1594         off = ftell(file->stream);
1595     }
1596
1597     return off;
1598 }
1599
1600
1601 static int
1602 bfile_set_off(BFile file, long off)
1603 {
1604     int         returnValue = 0;
1605     if (fseek(file->stream, off, SEEK_SET) != 0)
1606     {
1607         returnValue = -1;
1608     }
1609     bfileP_set_eof(file);
1610     return returnValue;
1611 }
1612
1613
1614 static int 
1615 bfile_save_state(BFile file, BFileState state)
1616 {
1617     state->forward = bfile_is_forward(file);
1618     state->offset = bfile_get_off(file);
1619     state->lastNewlineOff = file->lastNewlineOff;
1620     state->lastNewlineOff2 = file->lastNewlineOff2;
1621     return 0;
1622 }
1623
1624
1625 static int
1626 bfile_restore_state(BFile file, BFileState state)
1627 {
1628     if (!(state->forward))
1629     {
1630         bfile_reverse(file);
1631     }
1632     else
1633     {
1634         bfile_forward(file);
1635     }
1636     bfile_set_off(file, state->offset);
1637     file->lastNewlineOff = state->lastNewlineOff;
1638     file->lastNewlineOff2 = state->lastNewlineOff2;
1639
1640     return 0;
1641 }
1642
1643
1644 /******************* PRIVATE METHODS **********************/
1645
1646 static BOOL
1647 bfileP_set_eof(BFile file)
1648 {
1649     file->eof = FALSE;
1650
1651     if (file->stream == NULL)
1652     {
1653         file->eof = TRUE;
1654         goto epilogue;
1655     }
1656
1657     /* DTB_USER_CODE_START */
1658     /* DTB_USER_CODE_END*/
1659
1660     if (file->reverse)
1661     {
1662         /* dunno... */
1663     }
1664     else
1665     {
1666         file->eof = (feof(file->stream) || ferror(file->stream));
1667     }
1668
1669     /* DTB_USER_CODE_START */
1670
1671         if (file->reverse)
1672         {
1673             /* put some goobies here */
1674         }
1675
1676     /* DTB_USER_CODE_END*/
1677
1678 epilogue:
1679     return 0;
1680 }
1681
1682
1683 CSegArray
1684 cseg_array_create()
1685 {
1686     CSegArray   newArray = (CSegArray)util_malloc(sizeof(CSegArrayRec));
1687     if (newArray != NULL)
1688     {
1689         memset(newArray, 0, sizeof(CSegArrayRec));
1690     }
1691     return newArray;
1692 }
1693
1694
1695 int
1696 cseg_arrayP_destroy_impl(CSegArray *arrayInOutPtr)
1697 {
1698     CSegArray   array = *arrayInOutPtr;
1699     if (array == NULL)
1700     {
1701         return 0;
1702     }
1703
1704     util_free(array->segs);
1705     util_free(array);
1706
1707     *arrayInOutPtr = NULL;
1708     return 0;
1709 }
1710
1711
1712 static int
1713 cvt_offset_to_line(BFile file, long offset)
1714 {
1715     static long         lastLineOff = 0;
1716     static int          lastLineNum = 1;
1717     int                 lineNum = 1;
1718     long                curOff = 0;
1719     int                 c = 0;
1720     BFileStateRec       startFileState;
1721
1722     bfile_save_state(file, &startFileState);
1723     bfile_forward(file);
1724
1725     if (offset >= lastLineOff)
1726     {
1727         curOff = lastLineOff;
1728         lineNum = lastLineNum;
1729     }
1730     else
1731     {
1732         curOff = 0;
1733         lineNum = 1;
1734     }
1735     bfile_set_off(file, curOff);
1736     while ((curOff < offset) && ((c = bfile_get_char(file)) != EOF))
1737     {
1738         ++curOff;
1739         if (c == '\n')
1740         {
1741             ++lineNum;
1742             lastLineNum = lineNum;
1743             lastLineOff = curOff;
1744         }
1745     }
1746
1747     bfile_restore_state(file, &startFileState);
1748
1749     /*
1750      * Return file to original state
1751      */
1752     return lineNum;
1753 }
1754
1755
1756 /********
1757  * This is here as a test (run this program on this file)
1758  */
1759 /*
1760 static int
1761 old_style_params(x, y, z)
1762         int     x;
1763         char    *y;
1764         CUserSegRec     *z;
1765 {
1766     x = x; y = y; z = z;        
1767     return 69;
1768 }
1769 */
1770
1771
1772 /*************************************************************************
1773  *************************************************************************
1774  **                                                                     **
1775  **             DEBUGGING SUPPORT                                       **
1776  **                                                                     **
1777  *************************************************************************
1778  *************************************************************************/
1779
1780
1781 #ifdef MAIN
1782
1783 /* Internationalization defines */
1784 nl_catd Dtb_project_catd = (nl_catd)-1;
1785
1786 /* Workaround for XPG4 API compatibility */
1787 #if !defined(NL_CAT_LOCALE)
1788 #define NL_CAT_LOCALE 0
1789 #endif
1790
1791 int 
1792 main(int argc, char *argv[])
1793 {
1794     STRING              inFilename = NULL;
1795     FILE                *inFile = NULL;
1796     CSegArray   segs = NULL;
1797     CSeg                cseg = NULL;
1798     int                 numSegs = 0;
1799     int                 segIndex = 0;
1800     int                 usegIndex = 0;
1801
1802     util_init(&argc, &argv);
1803
1804     if (argc < 2)
1805     {
1806         util_printf_err("Usage %s <filename>\n", util_get_program_name());
1807         exit(1);
1808     }
1809
1810     inFilename = argv[1];
1811     inFile = util_fopen_locked(inFilename, "r");
1812     if (inFile == NULL)
1813     {
1814         perror(inFilename);
1815         return -1;
1816     }
1817
1818     numSegs = abmfP_parse_c_file(inFile, &segs);
1819     if (numSegs < 0)
1820     {
1821         util_printf_err("Error parsing C file. Aborting\n");
1822         exit(1);
1823     }
1824     util_printf_err("Segs found in file: %d\n", numSegs);
1825     if (numSegs < 1)
1826     {
1827         exit(0);
1828     }
1829
1830     for (segIndex = 0; segIndex < numSegs; ++segIndex)
1831     {
1832         cseg = &(segs->segs[segIndex]);
1833         util_dprintf(1, "Seg: %s  offset:%ld length:%ld userSegs:%d\n", 
1834             cseg->type == CSEG_GLOBAL? "[GLOBAL]": util_strsafe(cseg->name),
1835             cseg->offset,
1836             cseg->length,
1837             cseg->userSegs.numSegs);
1838         if (cseg->text != NULL)
1839         {
1840             printf("|||%s|||\n", cseg->text);
1841         }
1842
1843         if (cseg->userSegs.numSegs < 1)
1844         {
1845             printf("[ No user segments ]\n");
1846         }
1847         else
1848         {
1849             for (usegIndex = 0; usegIndex < cseg->userSegs.numSegs; ++usegIndex)
1850             {
1851                 printf("--- user seg %d [line %ld] ---\n%s---\n", 
1852                         usegIndex, 
1853                         cseg->userSegs.segs[usegIndex].line,
1854                         util_strsafe(cseg->userSegs.segs[usegIndex].text));
1855             }
1856         }
1857     }
1858     printf("\n");
1859
1860     return 0;
1861 }
1862 #endif /* MAIN */
1863
1864 /*
1865  * Leave this user segment at the end of the file (this file can be
1866  * used to test itself).
1867  */
1868
1869 /* DTB_USER_CODE_START */
1870
1871 static int
1872 myfunc()
1873 {
1874     return 0;
1875 }
1876 /* DTB_USER_CODE_END*/