1ab1b73bf7bf256ac23f468d95482c31584cfc33
[lttv.git] / genevent / parser.c
1 /*
2
3 parser.c: Generate helper declarations and functions to trace events
4 from an event description file.
5
6 Copyright (C) 2005, Mathieu Desnoyers
7 Copyright (C) 2002, Xianxiu Yang
8 Copyright (C) 2002, Michel Dagenais
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23 /* This program reads the ".xml" event definitions input files
24 and constructs structure for each event.
25
26 The program uses a very simple tokenizer, called from a hand written
27 recursive descent parser to fill a data structure describing the events.
28 The result is a sequence of events definitions which refer to type
29 definitions.
30
31 A table of named types is maintained to allow refering to types by name
32 when the same type is used at several places. Finally a sequence of
33 all types is maintained to facilitate the freeing of all type
34 information when the processing of an ".xml" file is finished. */
35
36 #include <stdlib.h>
37 #include <string.h>
38 #include <stdio.h>
39 #include <stdarg.h>
40 #include <linux/errno.h>
41 #include <assert.h>
42 #include <ctype.h>
43
44 #include "parser.h"
45
46
47 char *intOutputTypes[] = {
48 "int8_t", "int16_t", "int32_t", "int64_t" };
49
50 char *uintOutputTypes[] = {
51 "uint8_t", "uint16_t", "uint32_t", "uint64_t" };
52
53 char *floatOutputTypes[] = {
54 "undef", "undef", "float", "double" };
55
56
57
58
59 /* helper function */
60 void strupper(char *string)
61 {
62 char *ptr = string;
63
64 while(*ptr != '\0') {
65 *ptr = toupper(*ptr);
66 ptr++;
67 }
68 }
69
70
71 int getSizeindex(unsigned int value)
72 {
73 switch(value) {
74 case 1:
75 return 0;
76 case 2:
77 return 1;
78 case 4:
79 return 2;
80 case 8:
81 return 3;
82 default:
83 printf("Error : unknown value size %d\n", value);
84 exit(-1);
85 }
86 }
87
88 /*****************************************************************************
89 *Function name
90 * getSize : translate from string to integer
91 *Input params
92 * in : input file handle
93 *Return values
94 * size
95 *****************************************************************************/
96
97 unsigned long long int getSize(parse_file_t *in)
98 {
99 char *token, *token2;
100 unsigned long long int ret;
101
102 token = getToken(in);
103
104
105 if(in->type == QUOTEDSTRING) {
106 in->type = NUMBER;
107 token2 = token;
108 do {
109 if (!isdigit(*token2)) {
110 in->type = QUOTEDSTRING;
111 break;
112 }
113 } while (*(++token2) != '\0');
114 }
115
116 if(in->type == NUMBER) {
117 ret = strtoull(token, NULL, 0);
118 } else {
119 goto error;
120 }
121
122 return ret;
123 error:
124 in->error(in,"incorrect size specification");
125 return -1;
126 }
127
128 /*****************************************************************************
129 *Function name
130 * error_callback : print out error info
131 *Input params
132 * in : input file handle
133 * msg : message to be printed
134 ****************************************************************************/
135
136 void error_callback(parse_file_t *in, char *msg)
137 {
138 if(in)
139 printf("Error in file %s, line %d: %s\n", in->name, in->lineno, msg);
140 else
141 printf("%s\n",msg);
142 assert(0);
143 exit(1);
144 }
145
146 /*****************************************************************************
147 *Function name
148 * memAlloc : allocate memory
149 *Input params
150 * size : required memory size
151 *return value
152 * void * : pointer to allocate memory or NULL
153 ****************************************************************************/
154
155 void * memAlloc(int size)
156 {
157 void * addr;
158 if(size == 0) return NULL;
159 addr = malloc(size);
160 if(!addr){
161 printf("Failed to allocate memory");
162 exit(1);
163 }
164 return addr;
165 }
166
167 /*****************************************************************************
168 *Function name
169 * allocAndCopy : allocate memory and initialize it
170 *Input params
171 * str : string to be put in memory
172 *return value
173 * char * : pointer to allocate memory or NULL
174 ****************************************************************************/
175
176 char *allocAndCopy(char *str)
177 {
178 char * addr;
179 if(str == NULL) return NULL;
180 addr = (char *)memAlloc(strlen(str)+1);
181 strcpy(addr,str);
182 return addr;
183 }
184
185 /**************************************************************************
186 * Function :
187 * getTypeAttributes
188 * Description :
189 * Read the attribute from the input file.
190 *
191 * Parameters :
192 * in , input file handle.
193 * t , the type descriptor to fill.
194 *
195 **************************************************************************/
196
197 void getTypeAttributes(parse_file_t *in, type_descriptor_t *t,
198 sequence_t * unnamed_types, table_t * named_types)
199 {
200 char * token;
201 char car;
202
203 t->fmt = NULL;
204 t->size = 0;
205 t->custom_write = 0;
206 t->network = 0;
207
208 while(1) {
209 token = getToken(in);
210 if(strcmp("/",token) == 0 || strcmp(">",token) == 0){
211 ungetToken(in);
212 break;
213 }
214
215 if(!strcmp("format",token)) {
216 getEqual(in);
217 t->fmt = allocAndCopy(getQuotedString(in));
218 //} else if(!strcmp("name",token)) {
219 // getEqual(in);
220 // car = seekNextChar(in);
221 // if(car == EOF) in->error(in,"name was expected");
222 // else if(car == '\"') t->type_name = allocAndCopy(getQuotedString(in));
223 // else t->type_name = allocAndCopy(getName(in));
224 } else if(!strcmp("size",token)) {
225 getEqual(in);
226 t->size = getSize(in);
227 } else if(!strcmp("custom_write", token)) {
228 t->custom_write = 1;
229 } else if(!strcmp("byte_order",token)) {
230 getEqual(in);
231 car = seekNextChar(in);
232 if(car == EOF) in->error(in,"byte order was expected (network?)");
233 else if(car == '\"') token = getQuotedString(in);
234 else token = getName(in);
235 if(!strcmp("network", token)) {
236 t->network = 1;
237 }
238 } else if(!strcmp("write",token)) {
239 getEqual(in);
240 car = seekNextChar(in);
241 if(car == EOF) in->error(in,"write type was expected (custom?)");
242 else if(car == '\"') token = getQuotedString(in);
243 else token = getName(in);
244 if(!strcmp("custom", token)) {
245 t->custom_write = 1;
246 }
247 }
248 }
249 }
250
251 /**************************************************************************
252 * Function :
253 * getEventAttributes
254 * Description :
255 * Read the attribute from the input file.
256 *
257 * Parameters :
258 * in , input file handle.
259 * ev , the event to fill.
260 *
261 **************************************************************************/
262
263 void getEventAttributes(parse_file_t *in, event_t *ev)
264 {
265 char * token;
266 char car;
267
268 ev->name = NULL;
269 ev->per_trace = 0;
270 ev->per_tracefile = 0;
271 ev->param_buffer = 0;
272 ev->no_instrument_function = 0;
273
274 while(1) {
275 token = getToken(in);
276 if(strcmp("/",token) == 0 || strcmp(">",token) == 0){
277 ungetToken(in);
278 break;
279 }
280
281 if(!strcmp("name",token)) {
282 getEqual(in);
283 car = seekNextChar(in);
284 if(car == EOF) in->error(in,"name was expected");
285 else if(car == '\"') ev->name = allocAndCopy(getQuotedString(in));
286 else ev->name = allocAndCopy(getName(in));
287 } else if(!strcmp("scope", token)) {
288 getEqual(in);
289 car = seekNextChar(in);
290 if(car == EOF) in->error(in,"scope was expected");
291 else if(car == '\"') token = getQuotedString(in);
292 else token = getName(in);
293 if(!strcmp(token, "trace")) ev->per_trace = 1;
294 else if(!strcmp(token, "tracefile")) ev->per_tracefile = 1;
295 } else if(!strcmp("param", token)) {
296 getEqual(in);
297 car = seekNextChar(in);
298 if(car == EOF) in->error(in,"parameter type was expected");
299 else if(car == '\"') token = getQuotedString(in);
300 else token = getName(in);
301 if(!strcmp(token, "buffer")) ev->param_buffer = 1;
302 } else if(!strcmp("attribute", token)) {
303 getEqual(in);
304 car = seekNextChar(in);
305 if(car == EOF) in->error(in,"attribute was expected");
306 else if(car == '\"') token = getQuotedString(in);
307 else token = getName(in);
308 if(!strcmp(token, "no_instrument_function"))
309 ev->no_instrument_function = 1;
310 }
311 }
312 }
313
314 /**************************************************************************
315 * Function :
316 * getFacilityAttributes
317 * Description :
318 * Read the attribute from the input file.
319 *
320 * Parameters :
321 * in , input file handle.
322 * fac , the facility to fill.
323 *
324 **************************************************************************/
325
326 void getFacilityAttributes(parse_file_t *in, facility_t *fac)
327 {
328 char * token;
329 char car;
330
331 fac->name = NULL;
332 fac->arch = NULL;
333 fac->user = 0;
334
335 while(1) {
336 token = getToken(in);
337 if(strcmp("/",token) == 0 || strcmp(">",token) == 0){
338 ungetToken(in);
339 break;
340 }
341
342 if(!strcmp("name",token)) {
343 getEqual(in);
344 car = seekNextChar(in);
345 if(car == EOF) in->error(in,"name was expected");
346 else if(car == '\"') fac->name = allocAndCopy(getQuotedString(in));
347 else fac->name = allocAndCopy(getName(in));
348 if(!strncmp(fac->name, "user_", sizeof("user_")-1))
349 fac->user = 1;
350 } else if(!strcmp("arch", token)) {
351 getEqual(in);
352 car = seekNextChar(in);
353 if(car == '\"') fac->arch = allocAndCopy(getQuotedString(in));
354 else fac->arch = allocAndCopy(getName(in));
355 }
356 }
357 }
358
359 /**************************************************************************
360 * Function :
361 * getFieldAttributes
362 * Description :
363 * Read the attribute from the input file.
364 *
365 * Parameters :
366 * in , input file handle.
367 * f , the field to fill.
368 *
369 **************************************************************************/
370
371 void getFieldAttributes(parse_file_t *in, field_t *f)
372 {
373 char * token;
374 char car;
375
376 f->name = NULL;
377
378 while(1) {
379 token = getToken(in);
380 if(strcmp("/",token) == 0 || strcmp(">",token) == 0){
381 ungetToken(in);
382 break;
383 }
384
385 if(!strcmp("name",token)) {
386 getEqual(in);
387 car = seekNextChar(in);
388 if(car == EOF) in->error(in,"name was expected");
389 else if(car == '\"') f->name = allocAndCopy(getQuotedString(in));
390 else f->name = allocAndCopy(getName(in));
391 }
392 }
393 }
394
395 char *getNameAttribute(parse_file_t *in)
396 {
397 char * token;
398 char *name = NULL;
399 char car;
400
401 while(1) {
402 token = getToken(in);
403 if(!strcmp("name",token)) {
404 getEqual(in);
405 car = seekNextChar(in);
406 if(car == EOF) in->error(in,"name was expected");
407 else if(car == '\"') name = allocAndCopy(getQuotedString(in));
408 else name = allocAndCopy(getName(in));
409 } else {
410 ungetToken(in);
411 break;
412 }
413
414 }
415 if(name == NULL) in->error(in, "Name was expected");
416 return name;
417 }
418
419
420
421 //for <label name=label_name value=n format="...">, value is an option
422 //Return value : 0 : no value, 1 : has a value
423 int getValueAttribute(parse_file_t *in, long long *value)
424 {
425 char * token, *token2;
426
427 token = getToken(in);
428
429 if(strcmp("/",token) == 0 || strcmp(">", token) == 0){
430 ungetToken(in);
431 return 0;
432 }
433 if(strcmp("value",token))in->error(in,"value was expected");
434
435 getEqual(in);
436 token = getToken(in);
437
438 if(in->type == QUOTEDSTRING) {
439 in->type = NUMBER;
440 token2 = token;
441 do {
442 if (!isdigit(*token2)) {
443 in->type = QUOTEDSTRING;
444 break;
445 }
446 } while (*(++token2) != '\0');
447 }
448
449 if(in->type == NUMBER)
450 *value = strtoll(token, NULL, 0);
451 else
452 goto error;
453 return 1;
454 error:
455 in->error(in,"incorrect size specification");
456 return 0;
457 }
458
459 char * getDescription(parse_file_t *in)
460 {
461 long int pos;
462 char * token, car, *str;
463
464 pos = ftell(in->fp);
465
466 getLAnglebracket(in);
467 token = getName(in);
468 if(strcmp("description",token)){
469 fseek(in->fp, pos, SEEK_SET);
470 return NULL;
471 }
472
473 getRAnglebracket(in);
474
475 pos = 0;
476 while((car = getc(in->fp)) != EOF) {
477 if(car == '<') break;
478 if(car == '\0') continue;
479 in->buffer[pos] = car;
480 pos++;
481 }
482 if(car == EOF)in->error(in,"not a valid description");
483 in->buffer[pos] = '\0';
484
485 str = allocAndCopy(in->buffer);
486
487 getForwardslash(in);
488 token = getName(in);
489 if(strcmp("description", token))in->error(in,"not a valid description");
490 getRAnglebracket(in);
491
492 return str;
493 }
494
495 /*****************************************************************************
496 *Function name
497 * parseFacility : generate event list
498 *Input params
499 * in : input file handle
500 * fac : empty facility
501 *Output params
502 * fac : facility filled with event list
503 ****************************************************************************/
504
505 void parseFacility(parse_file_t *in, facility_t * fac)
506 {
507 char * token;
508 event_t *ev;
509
510 getFacilityAttributes(in, fac);
511 if(fac->name == NULL) in->error(in, "Attribute not named");
512
513 fac->capname = allocAndCopy(fac->name);
514 strupper(fac->capname);
515 getRAnglebracket(in);
516
517 fac->description = getDescription(in);
518
519 while(1){
520 getLAnglebracket(in);
521
522 token = getToken(in);
523 if(in->type == ENDFILE)
524 in->error(in,"the definition of the facility is not finished");
525
526 if(strcmp("event",token) == 0){
527 ev = (event_t*) memAlloc(sizeof(event_t));
528 sequence_push(&(fac->events),ev);
529 parseEvent(in,ev, &(fac->unnamed_types), &(fac->named_types));
530 }else if(strcmp("type",token) == 0){
531 parseTypeDefinition(in, &(fac->unnamed_types), &(fac->named_types));
532 }else if(in->type == FORWARDSLASH){
533 break;
534 }else in->error(in,"event or type token expected\n");
535 }
536
537 token = getName(in);
538 if(strcmp("facility",token)) in->error(in,"not the end of the facility");
539 getRAnglebracket(in); //</facility>
540 }
541
542 /*****************************************************************************
543 *Function name
544 * parseEvent : generate event from event definition
545 *Input params
546 * in : input file handle
547 * ev : new event
548 * unnamed_types : array of unamed types
549 * named_types : array of named types
550 *Output params
551 * ev : new event (parameters are passed to it)
552 ****************************************************************************/
553
554 void parseEvent(parse_file_t *in, event_t * ev, sequence_t * unnamed_types,
555 table_t * named_types)
556 {
557 char *token;
558 field_t *f;
559
560 sequence_init(&(ev->fields));
561 //<event name=eventtype_name>
562 getEventAttributes(in, ev);
563 if(ev->name == NULL) in->error(in, "Event not named");
564 getRAnglebracket(in);
565
566 //<description>...</description>
567 ev->description = getDescription(in);
568
569 int got_end = 0;
570 /* Events can have multiple fields. each field form at least a function
571 * parameter of the logging function. */
572 while(!got_end) {
573 getLAnglebracket(in);
574 token = getToken(in);
575
576 switch(in->type) {
577 case FORWARDSLASH: /* </event> */
578 token = getName(in);
579 if(strcmp("event",token))in->error(in,"not an event definition");
580 getRAnglebracket(in); //</event>
581 got_end = 1;
582 break;
583 case NAME: /* a field */
584 if(strcmp("field",token))in->error(in,"expecting a field");
585 f = (field_t *)memAlloc(sizeof(field_t));
586 sequence_push(&(ev->fields),f);
587 parseFields(in, f, unnamed_types, named_types, 1);
588 break;
589 default:
590 in->error(in, "expecting </event> or <field >");
591 break;
592 }
593 }
594 #if 0
595 if(in->type == FORWARDSLASH){ //</event> NOTHING
596 ev->type = NULL;
597 }else if(in->type == NAME){
598 if(strcmp("struct",token)==0 || strcmp("typeref",token)==0){
599 ungetToken(in);
600 ev->type = parseType(in,NULL, unnamed_types, named_types);
601 if(ev->type->type != STRUCT && ev->type->type != NONE)
602 in->error(in,"type must be a struct");
603 }else in->error(in, "not a valid type");
604
605 getLAnglebracket(in);
606 getForwardslash(in);
607 }else in->error(in,"not a struct type");
608 getLAnglebracket(in);
609 getForwardslash(in);
610 token = getName(in);
611 if(strcmp("event",token))in->error(in,"not an event definition");
612 getRAnglebracket(in); //</event>
613 #endif //0
614 }
615
616 /*****************************************************************************
617 *Function name
618 * parseField : get field infomation from buffer
619 *Input params
620 * in : input file handle
621 * f : field
622 * unnamed_types : array of unamed types
623 * named_types : array of named types
624 * tag : is field surrounded by a <field> </field> tag ?
625 ****************************************************************************/
626
627 void parseFields(parse_file_t *in, field_t *f,
628 sequence_t * unnamed_types,
629 table_t * named_types,
630 int tag)
631 {
632 char * token;
633 if(tag) {
634 //<field name=field_name> <description> <type> </field>
635 getFieldAttributes(in, f);
636 if(f->name == NULL) in->error(in, "Field not named");
637 getRAnglebracket(in);
638
639 f->description = getDescription(in);
640 } else {
641 f->description = NULL;
642 }
643
644 //<int size=...>
645 getLAnglebracket(in);
646 f->type = parseType(in,NULL, unnamed_types, named_types);
647
648 if(tag) {
649 getLAnglebracket(in);
650 getForwardslash(in);
651 token = getName(in);
652 if(strcmp("field",token))in->error(in,"not a valid field definition");
653 getRAnglebracket(in); //</field>
654 }
655 }
656
657
658 /*****************************************************************************
659 *Function name
660 * parseType : get type information, type can be :
661 * Primitive:
662 * int(size,fmt); uint(size,fmt); float(size,fmt);
663 * string(fmt); enum(size,fmt,(label1,label2...))
664 * Compound:
665 * array(arraySize, type); sequence(lengthSize,type)
666 * struct(field(name,type,description)...)
667 * type name:
668 * type(name,type)
669 *Input params
670 * in : input file handle
671 * inType : a type descriptor
672 * unnamed_types : array of unamed types
673 * named_types : array of named types
674 *Return values
675 * type_descriptor* : a type descriptor
676 ****************************************************************************/
677
678 type_descriptor_t *parseType(parse_file_t *in, type_descriptor_t *inType,
679 sequence_t * unnamed_types, table_t * named_types)
680 {
681 char *token;
682 type_descriptor_t *t;
683 field_t *f;
684
685 if(inType == NULL) {
686 t = (type_descriptor_t *) memAlloc(sizeof(type_descriptor_t));
687 t->type_name = NULL;
688 t->type = NONE;
689 t->fmt = NULL;
690 sequence_push(unnamed_types,t);
691 }
692 else t = inType;
693
694 token = getName(in);
695
696 if(strcmp(token,"struct") == 0) {
697 t->type = STRUCT;
698 getTypeAttributes(in, t, unnamed_types, named_types);
699 getRAnglebracket(in); //<struct>
700 getLAnglebracket(in); //<field name=..>
701 token = getToken(in);
702 sequence_init(&(t->fields));
703 while(strcmp("field",token) == 0){
704 f = (field_t *)memAlloc(sizeof(field_t));
705 sequence_push(&(t->fields),f);
706
707 parseFields(in, f, unnamed_types, named_types, 1);
708
709 //next field
710 getLAnglebracket(in);
711 token = getToken(in);
712 }
713 if(strcmp("/",token))in->error(in,"not a valid structure definition");
714 token = getName(in);
715 if(strcmp("struct",token)!=0)
716 in->error(in,"not a valid structure definition");
717 getRAnglebracket(in); //</struct>
718 }
719 else if(strcmp(token,"union") == 0) {
720 t->type = UNION;
721 getTypeAttributes(in, t, unnamed_types, named_types);
722 getRAnglebracket(in); //<union>
723
724 getLAnglebracket(in); //<field name=..>
725 token = getToken(in);
726 sequence_init(&(t->fields));
727 while(strcmp("field",token) == 0){
728 f = (field_t *)memAlloc(sizeof(field_t));
729 sequence_push(&(t->fields),f);
730 parseFields(in, f, unnamed_types, named_types, 1);
731
732 //next field
733 getLAnglebracket(in);
734 token = getToken(in);
735 }
736 if(strcmp("/",token))in->error(in,"not a valid union definition");
737 token = getName(in);
738 if(strcmp("union",token)!=0)
739 in->error(in,"not a valid union definition");
740 getRAnglebracket(in); //</union>
741 }
742 else if(strcmp(token,"array") == 0) {
743 t->type = ARRAY;
744 sequence_init(&(t->fields));
745 getTypeAttributes(in, t, unnamed_types, named_types);
746 if(t->size == 0) in->error(in, "Array has empty size");
747 getForwardslash(in);
748 getRAnglebracket(in); //<array size=n>
749
750 //getLAnglebracket(in); //<subtype>
751 /* subfield */
752 f = (field_t *)memAlloc(sizeof(field_t));
753 sequence_push(&(t->fields),f);
754 parseFields(in, f, unnamed_types, named_types, 0);
755
756 //getLAnglebracket(in); //<type struct>
757 //t->nested_type = parseType(in, NULL, unnamed_types, named_types);
758
759 getLAnglebracket(in); //</array>
760 getForwardslash(in);
761 token = getName(in);
762 if(strcmp("array",token))in->error(in,"not a valid array definition");
763 getRAnglebracket(in); //</array>
764 }
765 else if(strcmp(token,"sequence") == 0) {
766 t->type = SEQUENCE;
767 sequence_init(&(t->fields));
768 getTypeAttributes(in, t, unnamed_types, named_types);
769 getForwardslash(in);
770 getRAnglebracket(in); //<sequence>
771
772 //getLAnglebracket(in); //<sequence size type>
773 /* subfield */
774 f = (field_t *)memAlloc(sizeof(field_t));
775 sequence_push(&(t->fields),f);
776 parseFields(in, f, unnamed_types, named_types, 0);
777
778 //getLAnglebracket(in); //<subtype>
779 /* subfield */
780 f = (field_t *)memAlloc(sizeof(field_t));
781 sequence_push(&(t->fields),f);
782 parseFields(in, f, unnamed_types, named_types, 0);
783
784 //getLAnglebracket(in); //<type sequence>
785 //t->length_type = parseType(in, NULL, unnamed_types, named_types);
786
787 //getLAnglebracket(in); //<type sequence>
788
789 //t->nested_type = parseType(in, NULL, unnamed_types, named_types);
790
791 if(t->fields.position < 1) in->error(in, "Sequence has no length type");
792 if(t->fields.position < 2) in->error(in, "Sequence has no subtype");
793 switch(((field_t*)t->fields.array[0])->type->type) {
794 case UINT_FIXED :
795 case UCHAR :
796 case USHORT :
797 case UINT :
798 case ULONG :
799 case SIZE_T :
800 case OFF_T :
801 break;
802 default:
803 in->error(in, "Wrong length type for sequence");
804 }
805
806 getLAnglebracket(in); //</sequence>
807 getForwardslash(in);
808 token = getName(in);
809 if(strcmp("sequence",token))in->error(in,"not a valid sequence definition");
810 getRAnglebracket(in); //</sequence>
811 }
812 else if(strcmp(token,"enum") == 0) {
813 char * str;
814 long long value = -1;
815
816 t->type = ENUM;
817 sequence_init(&(t->labels));
818 sequence_init(&(t->labels_values));
819 sequence_init(&(t->labels_description));
820 t->already_printed = 0;
821 getTypeAttributes(in, t, unnamed_types, named_types);
822 //if(t->size == 0) in->error(in, "Sequence has empty size");
823 //Mathieu : we fix enum size to target int size. GCC is always like this.
824 //fox copy optimisation.
825 if(t->size != 0) in->error(in, "Enum has fixed size of target int.");
826 t->size = 0;
827 getRAnglebracket(in);
828
829 //<label name=label1 value=n/>
830 getLAnglebracket(in);
831 token = getToken(in); //"label" or "/"
832 while(strcmp("label",token) == 0){
833 int *label_value = malloc(sizeof(int));
834 int has_value = 0;
835 long long loc_value;
836
837 str = allocAndCopy(getNameAttribute(in));
838 has_value = getValueAttribute(in, &loc_value);
839
840 sequence_push(&(t->labels),str);
841
842 if(has_value) value = loc_value;
843 else value++;
844
845 *label_value = value;
846 sequence_push(&(t->labels_values), label_value);
847
848 getForwardslash(in);
849 getRAnglebracket(in);
850
851 //read description if any. May be NULL.
852 str = allocAndCopy(getDescription(in));
853 sequence_push(&(t->labels_description),str);
854
855 //next label definition
856 getLAnglebracket(in);
857 token = getToken(in); //"label" or "/"
858 }
859 if(strcmp("/",token))in->error(in, "not a valid enum definition");
860 token = getName(in);
861 if(strcmp("enum",token))in->error(in, "not a valid enum definition");
862 getRAnglebracket(in); //</label>
863 }
864 else if(strcmp(token,"int_fixed") == 0) {
865 t->type = INT_FIXED;
866 getTypeAttributes(in, t, unnamed_types, named_types);
867 if(t->size == 0) in->error(in, "int has empty size");
868 getForwardslash(in);
869 getRAnglebracket(in);
870 }
871 else if(strcmp(token,"uint_fixed") == 0) {
872 t->type = UINT_FIXED;
873 getTypeAttributes(in, t, unnamed_types, named_types);
874 if(t->size == 0) in->error(in, "uint has empty size");
875 getForwardslash(in);
876 getRAnglebracket(in);
877 }
878 else if(strcmp(token,"char") == 0) {
879 t->type = CHAR;
880 getTypeAttributes(in, t, unnamed_types, named_types);
881 t->size = 1;
882 getForwardslash(in);
883 getRAnglebracket(in);
884 }
885 else if(strcmp(token,"uchar") == 0) {
886 t->type = UCHAR;
887 getTypeAttributes(in, t, unnamed_types, named_types);
888 t->size = 1;
889 getForwardslash(in);
890 getRAnglebracket(in);
891 }
892 else if(strcmp(token,"short") == 0) {
893 t->type = SHORT;
894 getTypeAttributes(in, t, unnamed_types, named_types);
895 t->size = 2;
896 getForwardslash(in);
897 getRAnglebracket(in);
898 }
899 else if(strcmp(token,"ushort") == 0) {
900 t->type = USHORT;
901 getTypeAttributes(in, t, unnamed_types, named_types);
902 t->size = 2;
903 getForwardslash(in);
904 getRAnglebracket(in);
905 }
906 else if(strcmp(token,"int") == 0) {
907 t->type = INT;
908 getTypeAttributes(in, t, unnamed_types, named_types);
909 getForwardslash(in);
910 getRAnglebracket(in);
911 }
912 else if(strcmp(token,"uint") == 0) {
913 t->type = UINT;
914 getTypeAttributes(in, t, unnamed_types, named_types);
915 getForwardslash(in);
916 getRAnglebracket(in);
917 }
918
919 else if(strcmp(token,"pointer") == 0) {
920 t->type = POINTER;
921 getTypeAttributes(in, t, unnamed_types, named_types);
922 getForwardslash(in);
923 getRAnglebracket(in);
924 }
925 else if(strcmp(token,"long") == 0) {
926 t->type = LONG;
927 getTypeAttributes(in, t, unnamed_types, named_types);
928 getForwardslash(in);
929 getRAnglebracket(in);
930 }
931 else if(strcmp(token,"ulong") == 0) {
932 t->type = ULONG;
933 getTypeAttributes(in, t, unnamed_types, named_types);
934 getForwardslash(in);
935 getRAnglebracket(in);
936 }
937 else if(strcmp(token,"size_t") == 0) {
938 t->type = SIZE_T;
939 getTypeAttributes(in, t, unnamed_types, named_types);
940 getForwardslash(in);
941 getRAnglebracket(in);
942 }
943 else if(strcmp(token,"ssize_t") == 0) {
944 t->type = SSIZE_T;
945 getTypeAttributes(in, t, unnamed_types, named_types);
946 getForwardslash(in);
947 getRAnglebracket(in);
948 }
949 else if(strcmp(token,"off_t") == 0) {
950 t->type = OFF_T;
951 getTypeAttributes(in, t, unnamed_types, named_types);
952 getForwardslash(in);
953 getRAnglebracket(in);
954 }
955 else if(strcmp(token,"float") == 0) {
956 t->type = FLOAT;
957 getTypeAttributes(in, t, unnamed_types, named_types);
958 getForwardslash(in);
959 getRAnglebracket(in);
960 }
961 else if(strcmp(token,"string") == 0) {
962 t->type = STRING;
963 getTypeAttributes(in, t, unnamed_types, named_types);
964 getForwardslash(in);
965 getRAnglebracket(in);
966 }
967 else if(strcmp(token,"typeref") == 0){
968 // Must be a named type
969 free(t);
970 sequence_pop(unnamed_types);
971 token = getNameAttribute(in);
972 t = find_named_type(token, named_types);
973 if(t == NULL) in->error(in,"Named referred to must be pre-declared.");
974 getForwardslash(in); //<typeref name=type_name/>
975 getRAnglebracket(in);
976 return t;
977 }else in->error(in,"not a valid type");
978
979 return t;
980 }
981
982 /*****************************************************************************
983 *Function name
984 * find_named_type : find a named type from hash table
985 *Input params
986 * name : type name
987 * named_types : array of named types
988 *Return values
989 * type_descriptor * : a type descriptor
990 *****************************************************************************/
991
992 type_descriptor_t * find_named_type(char *name, table_t * named_types)
993 {
994 type_descriptor_t *t;
995
996 t = table_find(named_types,name);
997
998 return t;
999 }
1000
1001 type_descriptor_t * create_named_type(char *name, table_t * named_types)
1002 {
1003 type_descriptor_t *t;
1004
1005 t = (type_descriptor_t *)memAlloc(sizeof(type_descriptor_t));
1006 t->type_name = allocAndCopy(name);
1007 t->type = NONE;
1008 t->fmt = NULL;
1009 table_insert(named_types,t->type_name,t);
1010 // table_insert(named_types,allocAndCopy(name),t);
1011 return t;
1012 }
1013
1014 /*****************************************************************************
1015 *Function name
1016 * parseTypeDefinition : get type information from type definition
1017 *Input params
1018 * in : input file handle
1019 * unnamed_types : array of unamed types
1020 * named_types : array of named types
1021 *****************************************************************************/
1022
1023 void parseTypeDefinition(parse_file_t * in, sequence_t * unnamed_types,
1024 table_t * named_types)
1025 {
1026 char *token;
1027 type_descriptor_t *t;
1028
1029 token = getNameAttribute(in);
1030 if(token == NULL) in->error(in, "Type has empty name");
1031 t = create_named_type(token, named_types);
1032
1033 if(t->type != NONE) in->error(in,"redefinition of named type");
1034 getRAnglebracket(in); //<type name=type_name>
1035 getLAnglebracket(in); //<
1036 token = getName(in);
1037 //MD ??if(strcmp("struct",token))in->error(in,"not a valid type definition");
1038 ungetToken(in);
1039 parseType(in,t, unnamed_types, named_types);
1040
1041 //</type>
1042 getLAnglebracket(in);
1043 getForwardslash(in);
1044 token = getName(in);
1045 if(strcmp("type",token))in->error(in,"not a valid type definition");
1046 getRAnglebracket(in); //</type>
1047 }
1048
1049 /**************************************************************************
1050 * Function :
1051 * getComa, getName, getNumber, getEqual
1052 * Description :
1053 * Read a token from the input file, check its type, return it scontent.
1054 *
1055 * Parameters :
1056 * in , input file handle.
1057 *
1058 * Return values :
1059 * address of token content.
1060 *
1061 **************************************************************************/
1062
1063 char *getName(parse_file_t * in)
1064 {
1065 char *token;
1066
1067 token = getToken(in);
1068 // Optional descriptions
1069 // if(in->type != NAME) in->error(in,"Name token was expected");
1070 return token;
1071 }
1072
1073 int getNumber(parse_file_t * in)
1074 {
1075 char *token;
1076
1077 token = getToken(in);
1078 if(in->type != NUMBER) in->error(in, "Number token was expected");
1079 return atoi(token);
1080 }
1081
1082 char *getForwardslash(parse_file_t * in)
1083 {
1084 char *token;
1085
1086 token = getToken(in);
1087 //if(in->type != FORWARDSLASH) in->error(in, "forward slash token was expected");
1088 /* Mathieu : final / is optional now. */
1089 if(in->type != FORWARDSLASH) ungetToken(in);
1090
1091 return token;
1092 }
1093
1094 char *getLAnglebracket(parse_file_t * in)
1095 {
1096 char *token;
1097
1098 token = getToken(in);
1099 if(in->type != LANGLEBRACKET) in->error(in, "Left angle bracket was expected");
1100 return token;
1101 }
1102
1103 char *getRAnglebracket(parse_file_t * in)
1104 {
1105 char *token;
1106
1107 token = getToken(in);
1108 if(in->type != RANGLEBRACKET) in->error(in, "Right angle bracket was expected");
1109 return token;
1110 }
1111
1112 char *getQuotedString(parse_file_t * in)
1113 {
1114 char *token;
1115
1116 token = getToken(in);
1117 if(in->type != QUOTEDSTRING) in->error(in, "quoted string was expected");
1118 return token;
1119 }
1120
1121 char * getEqual(parse_file_t *in)
1122 {
1123 char *token;
1124
1125 token = getToken(in);
1126 if(in->type != EQUAL) in->error(in, "equal was expected");
1127 return token;
1128 }
1129
1130 char seekNextChar(parse_file_t *in)
1131 {
1132 char car;
1133 while((car = getc(in->fp)) != EOF) {
1134 if(!isspace(car)){
1135 ungetc(car,in->fp);
1136 return car;
1137 }
1138 }
1139 return EOF;
1140 }
1141
1142 /******************************************************************
1143 * Function :
1144 * getToken, ungetToken
1145 * Description :
1146 * Read a token from the input file and return its type and content.
1147 * Line numbers are accounted for and whitespace/comments are skipped.
1148 *
1149 * Parameters :
1150 * in, input file handle.
1151 *
1152 * Return values :
1153 * address of token content.
1154 *
1155 ******************************************************************/
1156
1157 void ungetToken(parse_file_t * in)
1158 {
1159 in->unget = 1;
1160 }
1161
1162 char *getToken(parse_file_t * in)
1163 {
1164 FILE *fp = in->fp;
1165 char car, car1;
1166 int pos = 0, escaped;
1167
1168 if(in->unget == 1) {
1169 in->unget = 0;
1170 return in->buffer;
1171 }
1172
1173 /* skip whitespace and comments */
1174
1175 while((car = getc(fp)) != EOF) {
1176 if(car == '/') {
1177 car1 = getc(fp);
1178 if(car1 == '*') skipComment(in);
1179 else if(car1 == '/') skipEOL(in);
1180 else {
1181 car1 = ungetc(car1,fp);
1182 break;
1183 }
1184 }
1185 else if(car == '\n') in->lineno++;
1186 else if(!isspace(car)) break;
1187 }
1188
1189 switch(car) {
1190 case EOF:
1191 in->type = ENDFILE;
1192 break;
1193 case '/':
1194 in->type = FORWARDSLASH;
1195 in->buffer[pos] = car;
1196 pos++;
1197 break;
1198 case '<':
1199 in->type = LANGLEBRACKET;
1200 in->buffer[pos] = car;
1201 pos++;
1202 break;
1203 case '>':
1204 in->type = RANGLEBRACKET;
1205 in->buffer[pos] = car;
1206 pos++;
1207 break;
1208 case '=':
1209 in->type = EQUAL;
1210 in->buffer[pos] = car;
1211 pos++;
1212 break;
1213 case '"':
1214 escaped = 0;
1215 while((car = getc(fp)) != EOF && pos < BUFFER_SIZE) {
1216 if(car == '\\' && escaped == 0) {
1217 in->buffer[pos] = car;
1218 pos++;
1219 escaped = 1;
1220 continue;
1221 }
1222 if(car == '"' && escaped == 0) break;
1223 if(car == '\n' && escaped == 0) {
1224 in->error(in, "non escaped newline inside quoted string");
1225 }
1226 if(car == '\n') in->lineno++;
1227 in->buffer[pos] = car;
1228 pos++;
1229 escaped = 0;
1230 }
1231 if(car == EOF) in->error(in,"no ending quotemark");
1232 if(pos == BUFFER_SIZE) in->error(in, "quoted string token too large");
1233 in->type = QUOTEDSTRING;
1234 break;
1235 default:
1236 if(isdigit(car)) {
1237 in->buffer[pos] = car;
1238 pos++;
1239 while((car = getc(fp)) != EOF && pos < BUFFER_SIZE) {
1240 if(!isdigit(car)) {
1241 ungetc(car,fp);
1242 break;
1243 }
1244 in->buffer[pos] = car;
1245 pos++;
1246 }
1247 if(car == EOF) ungetc(car,fp);
1248 if(pos == BUFFER_SIZE) in->error(in, "number token too large");
1249 in->type = NUMBER;
1250 }
1251 else if(isalnum(car) || car == '_' || car == '-') {
1252 in->buffer[0] = car;
1253 pos = 1;
1254 while((car = getc(fp)) != EOF && pos < BUFFER_SIZE) {
1255 if(!(isalnum(car) || car == '_' || car == '-')) {
1256 ungetc(car,fp);
1257 break;
1258 }
1259 in->buffer[pos] = car;
1260 pos++;
1261 }
1262 if(car == EOF) ungetc(car,fp);
1263 if(pos == BUFFER_SIZE) in->error(in, "name token too large");
1264 in->type = NAME;
1265 } else if(car == '?') {
1266 in->buffer[0] = car;
1267 pos++;
1268 }
1269 else in->error(in, "invalid character, unrecognized token");
1270 }
1271 in->buffer[pos] = 0;
1272 return in->buffer;
1273 }
1274
1275 void skipComment(parse_file_t * in)
1276 {
1277 char car;
1278 while((car = getc(in->fp)) != EOF) {
1279 if(car == '\n') in->lineno++;
1280 else if(car == '*') {
1281 car = getc(in->fp);
1282 if(car ==EOF) break;
1283 if(car == '/') return;
1284 ungetc(car,in->fp);
1285 }
1286 }
1287 if(car == EOF) in->error(in,"comment begining with '/*' has no ending '*/'");
1288 }
1289
1290 void skipEOL(parse_file_t * in)
1291 {
1292 char car;
1293 while((car = getc(in->fp)) != EOF) {
1294 if(car == '\n') {
1295 ungetc(car,in->fp);
1296 break;
1297 }
1298 }
1299 if(car == EOF)ungetc(car, in->fp);
1300 }
1301
1302 /*****************************************************************************
1303 *Function name
1304 * checkNamedTypesImplemented : check if all named types have definition
1305 ****************************************************************************/
1306
1307 void checkNamedTypesImplemented(table_t * named_types)
1308 {
1309 type_descriptor_t *t;
1310 int pos;
1311 char str[256];
1312
1313 for(pos = 0 ; pos < named_types->values.position; pos++) {
1314 t = (type_descriptor_t *) named_types->values.array[pos];
1315 if(t->type == NONE){
1316 sprintf(str,"named type '%s' has no definition",
1317 (char*)named_types->keys.array[pos]);
1318 error_callback(NULL,str);
1319 }
1320 }
1321 }
1322
1323
1324 /*****************************************************************************
1325 *Function name
1326 * generateChecksum : generate checksum for the facility
1327 *Input Params
1328 * facName : name of facility
1329 *Output Params
1330 * checksum : checksum for the facility
1331 ****************************************************************************/
1332
1333 void generateChecksum(char* facName,
1334 unsigned int * checksum, sequence_t * events)
1335 {
1336 unsigned long crc ;
1337 int pos;
1338 event_t * ev;
1339 unsigned int i;
1340
1341 crc = crc32(facName);
1342 for(pos = 0; pos < events->position; pos++){
1343 ev = (event_t *)(events->array[pos]);
1344 crc = partial_crc32(ev->name, crc);
1345 for(i = 0; i < ev->fields.position; i++) {
1346 field_t *f = (field_t*)ev->fields.array[i];
1347 crc = partial_crc32(f->name, crc);
1348 crc = getTypeChecksum(crc, f->type);
1349 }
1350 }
1351 *checksum = crc;
1352 }
1353
1354 /*****************************************************************************
1355 *Function name
1356 * getTypeChecksum : generate checksum by type info
1357 *Input Params
1358 * crc : checksum generated so far
1359 * type : type descriptor containing type info
1360 *Return value
1361 * unsigned long : checksum
1362 *****************************************************************************/
1363
1364 unsigned long getTypeChecksum(unsigned long aCrc, type_descriptor_t * type)
1365 {
1366 unsigned long crc = aCrc;
1367 char * str = NULL, buf[16];
1368 int flag = 0, pos;
1369 field_t * fld;
1370
1371 switch(type->type){
1372 case INT_FIXED:
1373 str = intOutputTypes[getSizeindex(type->size)];
1374 break;
1375 case UINT_FIXED:
1376 str = uintOutputTypes[getSizeindex(type->size)];
1377 break;
1378 case POINTER:
1379 str = allocAndCopy("void *");
1380 flag = 1;
1381 break;
1382 case CHAR:
1383 str = allocAndCopy("signed char");
1384 flag = 1;
1385 break;
1386 case UCHAR:
1387 str = allocAndCopy("unsigned char");
1388 flag = 1;
1389 break;
1390 case SHORT:
1391 str = allocAndCopy("short");
1392 flag = 1;
1393 break;
1394 case USHORT:
1395 str = allocAndCopy("unsigned short");
1396 flag = 1;
1397 break;
1398 case INT:
1399 str = allocAndCopy("int");
1400 flag = 1;
1401 break;
1402 case UINT:
1403 str = allocAndCopy("uint");
1404 flag = 1;
1405 break;
1406 case LONG:
1407 str = allocAndCopy("long");
1408 flag = 1;
1409 break;
1410 case ULONG:
1411 str = allocAndCopy("unsigned long");
1412 flag = 1;
1413 break;
1414 case SIZE_T:
1415 str = allocAndCopy("size_t");
1416 flag = 1;
1417 break;
1418 case SSIZE_T:
1419 str = allocAndCopy("ssize_t");
1420 flag = 1;
1421 break;
1422 case OFF_T:
1423 str = allocAndCopy("off_t");
1424 flag = 1;
1425 break;
1426 case FLOAT:
1427 str = floatOutputTypes[getSizeindex(type->size)];
1428 break;
1429 case STRING:
1430 str = allocAndCopy("string");
1431 flag = 1;
1432 break;
1433 case ENUM:
1434 //str = appendString("enum ", uintOutputTypes[getSizeindex(type->size)]);
1435 str = allocAndCopy("enum");
1436 flag = 1;
1437 break;
1438 case ARRAY:
1439 sprintf(buf,"%zu", type->size);
1440 str = appendString("array ",buf);
1441 flag = 1;
1442 break;
1443 case SEQUENCE:
1444 str = allocAndCopy("sequence ");
1445 flag = 1;
1446 break;
1447 case STRUCT:
1448 str = allocAndCopy("struct");
1449 flag = 1;
1450 break;
1451 case UNION:
1452 str = allocAndCopy("union");
1453 flag = 1;
1454 break;
1455 default:
1456 error_callback(NULL, "named type has no definition");
1457 break;
1458 }
1459
1460 crc = partial_crc32(str,crc);
1461 if(flag) free(str);
1462
1463 if(type->fmt) crc = partial_crc32(type->fmt,crc);
1464
1465 if(type->type == ARRAY){
1466 crc = getTypeChecksum(crc,((field_t*)type->fields.array[0])->type);
1467 } else if(type->type ==SEQUENCE) {
1468 crc = getTypeChecksum(crc,((field_t*)type->fields.array[0])->type);
1469 crc = getTypeChecksum(crc,((field_t*)type->fields.array[1])->type);
1470 } else if(type->type == STRUCT || type->type == UNION){
1471 for(pos =0; pos < type->fields.position; pos++){
1472 fld = (field_t *) type->fields.array[pos];
1473 crc = partial_crc32(fld->name,crc);
1474 crc = getTypeChecksum(crc, fld->type);
1475 }
1476 }else if(type->type == ENUM){
1477 for(pos = 0; pos < type->labels.position; pos++)
1478 crc = partial_crc32((char*)type->labels.array[pos],crc);
1479 }
1480
1481 return crc;
1482 }
1483
1484
1485 /* Event type descriptors */
1486 void freeType(type_descriptor_t * tp)
1487 {
1488 int pos2;
1489 field_t *f;
1490
1491 if(tp->fmt != NULL) free(tp->fmt);
1492 if(tp->type == ENUM) {
1493 for(pos2 = 0; pos2 < tp->labels.position; pos2++) {
1494 free(tp->labels.array[pos2]);
1495 }
1496 sequence_dispose(&(tp->labels));
1497 for(pos2 = 0; pos2 < tp->labels_values.position; pos2++) {
1498 free(tp->labels_values.array[pos2]);
1499 }
1500 sequence_dispose(&(tp->labels_values));
1501 }
1502 if(tp->type == STRUCT) {
1503 for(pos2 = 0; pos2 < tp->fields.position; pos2++) {
1504 f = (field_t *) tp->fields.array[pos2];
1505 free(f->name);
1506 free(f->description);
1507 free(f);
1508 }
1509 sequence_dispose(&(tp->fields));
1510 }
1511 }
1512
1513 void freeNamedType(table_t * t)
1514 {
1515 int pos;
1516 type_descriptor_t * td;
1517
1518 for(pos = 0 ; pos < t->keys.position; pos++) {
1519 free((char *)t->keys.array[pos]);
1520 td = (type_descriptor_t*)t->values.array[pos];
1521 freeType(td);
1522 free(td);
1523 }
1524 }
1525
1526 void freeTypes(sequence_t *t)
1527 {
1528 int pos;
1529 type_descriptor_t *tp;
1530
1531 for(pos = 0 ; pos < t->position; pos++) {
1532 tp = (type_descriptor_t *)t->array[pos];
1533 freeType(tp);
1534 free(tp);
1535 }
1536 }
1537
1538 void freeEvents(sequence_t *t)
1539 {
1540 int pos;
1541 event_t *ev;
1542
1543 for(pos = 0 ; pos < t->position; pos++) {
1544 ev = (event_t *) t->array[pos];
1545 free(ev->name);
1546 free(ev->description);
1547 sequence_dispose(&ev->fields);
1548 free(ev);
1549 }
1550
1551 }
1552
1553
1554 /* Extensible array */
1555
1556 void sequence_init(sequence_t *t)
1557 {
1558 t->size = 10;
1559 t->position = 0;
1560 t->array = (void **)memAlloc(t->size * sizeof(void *));
1561 }
1562
1563 void sequence_dispose(sequence_t *t)
1564 {
1565 t->size = 0;
1566 free(t->array);
1567 t->array = NULL;
1568 }
1569
1570 void sequence_push(sequence_t *t, void *elem)
1571 {
1572 void **tmp;
1573
1574 if(t->position >= t->size) {
1575 tmp = t->array;
1576 t->array = (void **)memAlloc(t->size * 2 * sizeof(void *));
1577 memcpy(t->array, tmp, t->size * sizeof(void *));
1578 t->size = t->size * 2;
1579 free(tmp);
1580 }
1581 t->array[t->position] = elem;
1582 t->position++;
1583 }
1584
1585 void *sequence_pop(sequence_t *t)
1586 {
1587 if(t->position == 0) printf("Error : trying to pop an empty sequence");
1588 return t->array[--t->position];
1589 }
1590
1591
1592 /* Hash table API, implementation is just linear search for now */
1593
1594 void table_init(table_t *t)
1595 {
1596 sequence_init(&(t->keys));
1597 sequence_init(&(t->values));
1598 }
1599
1600 void table_dispose(table_t *t)
1601 {
1602 sequence_dispose(&(t->keys));
1603 sequence_dispose(&(t->values));
1604 }
1605
1606 void table_insert(table_t *t, char *key, void *value)
1607 {
1608 sequence_push(&(t->keys),key);
1609 sequence_push(&(t->values),value);
1610 }
1611
1612 void *table_find(table_t *t, char *key)
1613 {
1614 int pos;
1615 for(pos = 0 ; pos < t->keys.position; pos++) {
1616 if(strcmp((char *)key,(char *)t->keys.array[pos]) == 0)
1617 return(t->values.array[pos]);
1618 }
1619 return NULL;
1620 }
1621
1622 void table_insert_int(table_t *t, int *key, void *value)
1623 {
1624 sequence_push(&(t->keys),key);
1625 sequence_push(&(t->values),value);
1626 }
1627
1628 void *table_find_int(table_t *t, int *key)
1629 {
1630 int pos;
1631 for(pos = 0 ; pos < t->keys.position; pos++) {
1632 if(*key == *(int *)t->keys.array[pos])
1633 return(t->values.array[pos]);
1634 }
1635 return NULL;
1636 }
1637
1638
1639 /* Concatenate strings */
1640
1641 char *appendString(char *s, char *suffix)
1642 {
1643 char *tmp;
1644 if(suffix == NULL) return s;
1645
1646 tmp = (char *)memAlloc(strlen(s) + strlen(suffix) + 1);
1647 strcpy(tmp,s);
1648 strcat(tmp,suffix);
1649 return tmp;
1650 }
This page took 0.063792 seconds and 3 git commands to generate.