aboutsummaryrefslogblamecommitdiffstats
path: root/lib/megaco/src/flex/megaco_flex_scanner_drv.flex.src
blob: 90d5c2aae6aa88c401b7ae4104e7216feeb68931 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746


                     
                                                          





                                                                        
    



                                                                           
    













































                                                                           


                                                                     

      










                                                   
                            

















                                           






                                                                         


























































































































































































































                                                                               

                                                              
                                                   

                                                                       






















                                                                                         



                                                                          

                                                                              




































































































































































































































































































































































































                                                                                                                        
                          







































































































                                                                                         
                                                                             

                                    



                                                                    



                                                                  


                                                          


























































































                                                                             


                                            










































































































































































































































































































                                                                                              
                                                       































































































































































































































































                                                                                     
                                                       




















































































































































































                                                                                          
                                                       





                                                                    
                                                           
                                                   

                                                               



































                                                                      
                                                           


















































































































                                                                                          



                                                 





















































































                                                               
  /*
   * %CopyrightBegin%
   * 
   * Copyright Ericsson AB 2001-2013. All Rights Reserved.
   * 
   * The contents of this file are subject to the Erlang Public License,
   * Version 1.1, (the "License"); you may not use this file except in
   * compliance with the License. You should have received a copy of the
   * Erlang Public License along with this software. If not, it can be
   * retrieved online at http://www.erlang.org/.
   *
   * Software distributed under the License is distributed on an "AS IS"
   * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
   * the License for the specific language governing rights and limitations
   * under the License.
   *
   * %CopyrightEnd%
   * 
   * ----------------------------------------------------------------------
   *  Purpose : Scanner for text encoded Megaco/H.248 messages
   * ----------------------------------------------------------------------
   * 
   * Throughout this file the prefix mfs is used for megaco_flex_scanner.
   * The reason is to get shorter function and variable names.
   */

%option case-insensitive

  /* MEGACO_YY_LINENO_OPTION
   * Note that this construction is intended to make it
   * possible to generate flex files that either reports
   * line-number or one that don't.
   * See MEGACO_DUMMY_DECL_YY_LINENO and
   *     MEGACO_LINENO_OR_TOKENCOUNTER below.
   */
%MEGACO_YY_LINENO_OPTION%

%MEGACO_YY_REENTRANT_OPTION%
%option noyywrap
%option noinput
%option nounput 
%{

#define HAVE_UIO_H
#include "erl_driver.h"
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define TRUE       1
#define FALSE      0
#define SP         0x20
#define HTAB       0x09
#define CR         0x0d
#define LF         0x0a
#define SEMI_COLON 0x3b
#define BACKSLASH  0x5c
#define RBRKT      0x7b
#define NUL        0x0

#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
#  define MEGACO_DRIVER_FLAGS           ERL_DRV_FLAG_USE_PORT_LOCKING
#else 
#  define MEGACO_DRIVER_FLAGS           0
#endif

#define FREE(bufP)        driver_free(bufP)
#define ALLOC(sz)         driver_alloc(sz)
#define REALLOC(bufP, sz) driver_realloc(bufP, sz)

#define YY_MAIN false

// #define YY_FATAL_ERROR(msg) mfs_fatal_error(msg)


typedef struct {
    ErlDrvPort      port;
    ErlDrvTermData  port_id;
    char*           digit_map_name_ptr;
    int             digit_map_name_len;
    char*           digit_map_value_ptr;
    int             digit_map_value_len;
    char*           digit_map_start_ptr;
    char*           digit_map_short_ptr;
    char*           digit_map_long_ptr;
    char*           digit_map_duration_ptr;
    int             error;
    char            error_msg[512];
    char*           text_buf;
    char*           text_ptr;
    ErlDrvTermData* term_spec;
    int             term_spec_size;
    int             term_spec_index;
    int             token_counter;
} MfsErlDrvData;

/* IBL = In Buffer Length - the raw (un-decoded) message buffer length */
#define TERM_SPEC_SIZE_INITIAL(IBL) (1024 + 2*(IBL))

/* CTSS = Current term spec size - the current term spec length */
/* S    = Size - how many positions we need */
#define TERM_SPEC_SIZE_NEXT(CTSS,S)   ((CTSS) + 1024 + (S))

#if !defined(MEGACO_REENTRANT_FLEX_SCANNER)
static MfsErlDrvData mfs_drv_data;
#endif

char flex_version[] = "%FLEX_VERSION%";

static ErlDrvTermData mfs_AddToken = 0;
static ErlDrvTermData mfs_AndAUDITSelectToken = 0;          /* v3 */
static ErlDrvTermData mfs_AuditCapToken = 0;
static ErlDrvTermData mfs_AuditToken = 0;
static ErlDrvTermData mfs_AuditValueToken = 0;
static ErlDrvTermData mfs_AuthToken = 0;
static ErlDrvTermData mfs_BothToken = 0;                    /* v3 */
static ErlDrvTermData mfs_BothwayToken = 0;
static ErlDrvTermData mfs_BriefToken = 0;
static ErlDrvTermData mfs_BufferToken = 0;
static ErlDrvTermData mfs_COLON = 0;
static ErlDrvTermData mfs_COMMA = 0;
static ErlDrvTermData mfs_ContextAttrToken = 0;             /* v3 */
static ErlDrvTermData mfs_ContextAuditToken = 0;
static ErlDrvTermData mfs_ContextListToken = 0;             /* v3 */
static ErlDrvTermData mfs_CtxToken = 0;
static ErlDrvTermData mfs_DelayToken = 0;
static ErlDrvTermData mfs_DeleteToken = 0;
static ErlDrvTermData mfs_DigitMapDescriptor = 0;
static ErlDrvTermData mfs_DigitMapDescriptorToken = 0;
static ErlDrvTermData mfs_DigitMapToken = 0;
static ErlDrvTermData mfs_DigitMapValue = 0;
static ErlDrvTermData mfs_DirectionToken = 0;               /* v3 */
static ErlDrvTermData mfs_DiscardToken = 0;
static ErlDrvTermData mfs_DisconnectedToken = 0;
static ErlDrvTermData mfs_DurationToken = 0;
static ErlDrvTermData mfs_EQUAL = 0;
static ErlDrvTermData mfs_EmbedToken = 0;
static ErlDrvTermData mfs_EmergencyToken = 0;
static ErlDrvTermData mfs_EmergencyOffToken = 0;            /* v3 */
static ErlDrvTermData mfs_EmergencyValueToken = 0;          /* v3 */
static ErlDrvTermData mfs_ErrorToken = 0;
static ErlDrvTermData mfs_EventBufferToken = 0;
static ErlDrvTermData mfs_EventsToken = 0;
static ErlDrvTermData mfs_ExternalToken = 0;                /* v3 */
static ErlDrvTermData mfs_FailoverToken = 0;
static ErlDrvTermData mfs_ForcedToken = 0;
static ErlDrvTermData mfs_GREATER = 0;
static ErlDrvTermData mfs_GracefulToken = 0;
static ErlDrvTermData mfs_H221Token = 0;
static ErlDrvTermData mfs_H223Token = 0;
static ErlDrvTermData mfs_H226Token = 0;
static ErlDrvTermData mfs_HandOffToken = 0;
static ErlDrvTermData mfs_IEPSToken = 0;                    /* v3 */
static ErlDrvTermData mfs_IllegalChar = 0;
static ErlDrvTermData mfs_ImmAckRequiredToken = 0;
static ErlDrvTermData mfs_InactiveToken = 0;
static ErlDrvTermData mfs_InSvcToken = 0;
static ErlDrvTermData mfs_IntsigDelayToken = 0;             /* v3 */
static ErlDrvTermData mfs_InternalToken = 0;                /* v3 */
static ErlDrvTermData mfs_InterruptByEventToken = 0;
static ErlDrvTermData mfs_InterruptByNewSignalsDescrToken = 0;
static ErlDrvTermData mfs_IsolateToken = 0;
static ErlDrvTermData mfs_IterationToken = 0;               /* v3 */
static ErlDrvTermData mfs_KeepActiveToken = 0;
static ErlDrvTermData mfs_LBRKT = 0;
static ErlDrvTermData mfs_LESSER = 0;
static ErlDrvTermData mfs_LSBRKT = 0;
static ErlDrvTermData mfs_LocalControlToken = 0;
static ErlDrvTermData mfs_LocalDescriptorToken = 0;
static ErlDrvTermData mfs_LocalToken = 0;
static ErlDrvTermData mfs_LockStepToken = 0;
static ErlDrvTermData mfs_LoopbackToken = 0;
static ErlDrvTermData mfs_MediaToken = 0;
static ErlDrvTermData mfs_MegacopToken = 0;
static ErlDrvTermData mfs_MethodToken = 0;
static ErlDrvTermData mfs_MessageSegmentToken = 0;
static ErlDrvTermData mfs_MgcIdToken = 0;
static ErlDrvTermData mfs_ModeToken = 0;
static ErlDrvTermData mfs_ModemToken = 0;
static ErlDrvTermData mfs_ModifyToken = 0;
static ErlDrvTermData mfs_MoveToken = 0;
static ErlDrvTermData mfs_MtpAddressToken = 0;
static ErlDrvTermData mfs_MuxToken = 0;
static ErlDrvTermData mfs_NEQUAL = 0;
static ErlDrvTermData mfs_NeverNotifyToken = 0;             /* v3 */
static ErlDrvTermData mfs_NotifyCompletionToken = 0;
static ErlDrvTermData mfs_NotifyImmediateToken = 0;         /* v3 */
static ErlDrvTermData mfs_NotifyRegulatedToken = 0;         /* v3 */
static ErlDrvTermData mfs_NotifyToken = 0;
static ErlDrvTermData mfs_Nx64kToken = 0;
static ErlDrvTermData mfs_ObservedEventsToken = 0;
static ErlDrvTermData mfs_OffToken = 0;
static ErlDrvTermData mfs_OnOffToken = 0;
static ErlDrvTermData mfs_OnToken = 0;
static ErlDrvTermData mfs_OnewayToken = 0;
static ErlDrvTermData mfs_OnewayBothToken = 0;              /* v3 */
static ErlDrvTermData mfs_OnewayExternalToken = 0;          /* v3 */
static ErlDrvTermData mfs_OrAUDITselectToken = 0;           /* v3 */
static ErlDrvTermData mfs_OtherReasonToken = 0;
static ErlDrvTermData mfs_OutOfSvcToken = 0;
static ErlDrvTermData mfs_PackagesToken = 0;
static ErlDrvTermData mfs_PendingToken = 0;
static ErlDrvTermData mfs_PriorityToken = 0;
static ErlDrvTermData mfs_ProfileToken = 0;
static ErlDrvTermData mfs_QuotedChars = 0;
static ErlDrvTermData mfs_RBRKT = 0;
static ErlDrvTermData mfs_RSBRKT = 0;
static ErlDrvTermData mfs_ReasonToken = 0;
static ErlDrvTermData mfs_RecvonlyToken = 0;
static ErlDrvTermData mfs_RemoteDescriptorToken = 0;
static ErlDrvTermData mfs_RemoteToken = 0;
static ErlDrvTermData mfs_RequestIDToken = 0;               /* v3 */
static ErlDrvTermData mfs_ReplyToken = 0;
static ErlDrvTermData mfs_ReservedGroupToken = 0;
static ErlDrvTermData mfs_ReservedValueToken = 0;
static ErlDrvTermData mfs_ResetEventsDescriptorToken = 0;   /* v3 */
static ErlDrvTermData mfs_ResponseAckToken = 0;
static ErlDrvTermData mfs_RestartToken = 0;
static ErlDrvTermData mfs_SEP = 0;
static ErlDrvTermData mfs_SafeChars = 0;
static ErlDrvTermData mfs_SegmentationCompleteToken = 0;    /* v3 */
static ErlDrvTermData mfs_SendonlyToken = 0;
static ErlDrvTermData mfs_SendrecvToken = 0;
static ErlDrvTermData mfs_ServiceChangeAddressToken = 0;
static ErlDrvTermData mfs_ServiceChangeIncompleteToken = 0; /* v3 */
static ErlDrvTermData mfs_ServiceChangeToken = 0;
static ErlDrvTermData mfs_ServiceStatesToken = 0;
static ErlDrvTermData mfs_ServicesToken = 0;
static ErlDrvTermData mfs_SignalListToken = 0;
static ErlDrvTermData mfs_SignalTypeToken = 0;
static ErlDrvTermData mfs_SignalsToken = 0;
static ErlDrvTermData mfs_StatsToken = 0;
static ErlDrvTermData mfs_StreamToken = 0;
static ErlDrvTermData mfs_SubtractToken = 0;
static ErlDrvTermData mfs_SynchISDNToken = 0;
static ErlDrvTermData mfs_TerminationStateToken = 0;
static ErlDrvTermData mfs_TestToken = 0;
static ErlDrvTermData mfs_TimeOutToken = 0;
static ErlDrvTermData mfs_TimeStampToken = 0; /* OTP-5042 */
static ErlDrvTermData mfs_TopologyToken = 0;
static ErlDrvTermData mfs_TransToken = 0;
static ErlDrvTermData mfs_V18Token = 0;
static ErlDrvTermData mfs_V22Token = 0;
static ErlDrvTermData mfs_V22bisToken = 0;
static ErlDrvTermData mfs_V32Token = 0;
static ErlDrvTermData mfs_V32bisToken = 0;
static ErlDrvTermData mfs_V34Token = 0;
static ErlDrvTermData mfs_V76Token = 0;
static ErlDrvTermData mfs_V90Token = 0;
static ErlDrvTermData mfs_V91Token = 0;
static ErlDrvTermData mfs_VersionToken = 0;
static ErlDrvTermData mfs_asn1_NOVALUE = 0;
static ErlDrvTermData mfs_endOfMessage = 0;
static ErlDrvTermData mfs_PropertyParm = 0;
static ErlDrvTermData mfs_ErrorDescriptor = 0;

/* MEGACO_DUMMY_DECL_YY_LINENO
 * Note that this construction is intended to make it
 * possible to generate flex files that either reports
 * line-number or one that don't.
 * See MEGACO_YY_LINENO_OPTION above and
 *     MEGACO_LINENO_OR_TOKENCOUNTER below.
 */
#if !defined(MEGACO_REENTRANT_FLEX_SCANNER)
%MEGACO_DUMMY_DECL_YY_LINENO%
#endif

/*
static ErlDrvPort      mfs_port                = 0;
static char* 	       mfs_digit_map_name_ptr  = 0;
static int 	       mfs_digit_map_name_len  = 0;
static char* 	       mfs_digit_map_value_ptr = 0;
static int 	       mfs_digit_map_value_len = 0;
static char* 	       mfs_digit_map_start_ptr = 0;
static char* 	       mfs_digit_map_short_ptr = 0;
static char* 	       mfs_digit_map_long_ptr  = 0;
static char* 	       mfs_digit_map_duration_ptr = 0;
static int 	       mfs_error               = FALSE;
static char 	       mfs_error_msg[512];
static char* 	       mfs_text_buf            = 0;
static char* 	       mfs_text_ptr            = 0;
static ErlDrvTermData* mfs_term_spec           = 0;
static int   	       mfs_term_spec_size      = 0;
static int   	       mfs_term_spec_index     = 0;
static int   	       mfs_token_counter       = 0;
*/


static void mfs_alloc_failed(MfsErlDrvData* dataP, char* msg, int sz);
static void mfs_fatal_error(MfsErlDrvData* dataP, char* msg); 
static void mfs_ensure_term_spec(MfsErlDrvData* dataP, int size);

#if defined(MEGACO_REENTRANT_FLEX_SCANNER)

static void mfs_short_load_token(ErlDrvTermData token_tag, 
                                 yyscan_t yyscanner);
static void mfs_lower_load_token(ErlDrvTermData token_tag, int is_empty, 
                                 yyscan_t yyscanner);
static void mfs_octet_load_token(ErlDrvTermData token_tag, int is_empty, 
                                 yyscan_t yyscanner);
static void mfs_load_property_groups(MfsErlDrvData* dataP, yyscan_t yyscanner);
static void mfs_load_map_name(yyscan_t yyscanner);
static void mfs_load_map_value(yyscan_t yyscanner);
static void mfs_load_map_timer(yyscan_t yyscanner);
static void mfs_load_map_token(yyscan_t yyscanner);

#else

static void mfs_short_load_token(ErlDrvTermData token_tag);
static void mfs_lower_load_token(ErlDrvTermData token_tag, int is_empty);
static void mfs_octet_load_token(ErlDrvTermData token_tag, int is_empty);
static void mfs_load_property_groups(MfsErlDrvData* dataP);
static void mfs_load_map_name();
static void mfs_load_map_value();
static void mfs_load_map_timer();
static void mfs_load_map_token();

#endif

static ErlDrvData mfs_start(ErlDrvPort port, char *buf);
static void 	  mfs_stop(ErlDrvData handle);
static void 	  mfs_command(ErlDrvData handle, 
                              char *buf, ErlDrvSizeT buf_len);
static ErlDrvSSizeT mfs_control(ErlDrvData handle,
                              unsigned int command,
                              char *buf, ErlDrvSizeT buf_len, 
      			      char **res_buf, ErlDrvSizeT res_buf_len);
static void 	  mfs_finish(void);

/* 
 * The driver entry 
 */

static ErlDrvEntry mfs_entry = {
    NULL,              /* init, always NULL for dynamic drivers */
    mfs_start,         /* start, called when port is opened */
    mfs_stop,          /* stop, called when port is closed */
    mfs_command,       /* output, called when erlang has sent */
    NULL,              /* ready_input, called when input descriptor ready */
    NULL,              /* ready_output, called when output descriptor ready */
    MEGACO_DRV_NAME,   /* char *driver_name, the arg to open_port */
    mfs_finish,        /* finish, called when unloaded */
    NULL,              /* void * that is not used (BC) */
    mfs_control,       /* control, port_control callback */
    NULL,              /* timeout, called on timeouts */
    NULL,              /* outputv, vector output interface */
    NULL,              /* ready_async, called after an asynchronous call has completed */
    NULL,              /* flush, port is about to be closed */
    NULL,              /* call, a syncronous call into the driver */
    NULL,              /* event, event selected by driver_event() has occurred */
    ERL_DRV_EXTENDED_MARKER,
    ERL_DRV_EXTENDED_MAJOR_VERSION,
    ERL_DRV_EXTENDED_MINOR_VERSION,
    MEGACO_DRIVER_FLAGS, /* driver_flags, used for port lock indication */
    NULL,              /* handle2, emulator internal use */
    NULL               /* process_exit, Called when a process monitor fires */
};    


#if defined(MEGACO_REENTRANT_FLEX_SCANNER)

#define LOAD_TOKEN(TokenTag)             mfs_lower_load_token(TokenTag, FALSE, yyscanner)
#define LOAD_EMPTY_TOKEN(TokenTag)       mfs_lower_load_token(TokenTag, TRUE, yyscanner)
#define LOAD_SHORT_TOKEN(TokenTag)       mfs_short_load_token(TokenTag, yyscanner)
#define LOAD_OCTET_TOKEN(TokenTag)       mfs_octet_load_token(TokenTag, FALSE, yyscanner)
#define LOAD_EMPTY_OCTET_TOKEN(TokenTag) mfs_octet_load_token(TokenTag, TRUE, yyscanner)
#define LOAD_MAP_NAME()                  mfs_load_map_name(yyscanner)
#define LOAD_MAP_TIMER()                 mfs_load_map_timer(yyscanner)
#define LOAD_MAP_TOKEN()                 mfs_load_map_token(yyscanner)
#define LOAD_MAP_VALUE()                 mfs_load_map_value(yyscanner)
#define LOAD_PROP_GRPS(dataP)            mfs_load_property_groups(dataP, yyscanner)

#else

#define LOAD_TOKEN(TokenTag)             mfs_lower_load_token(TokenTag, FALSE)
#define LOAD_EMPTY_TOKEN(TokenTag)       mfs_lower_load_token(TokenTag, TRUE)
#define LOAD_SHORT_TOKEN(TokenTag)       mfs_short_load_token(TokenTag)
#define LOAD_OCTET_TOKEN(TokenTag)       mfs_octet_load_token(TokenTag, FALSE)
#define LOAD_EMPTY_OCTET_TOKEN(TokenTag) mfs_octet_load_token(TokenTag, TRUE)
#define LOAD_MAP_NAME()                  mfs_load_map_name()
#define LOAD_MAP_TIMER()                 mfs_load_map_timer()
#define LOAD_MAP_TOKEN()                 mfs_load_map_token()
#define LOAD_MAP_VALUE()                 mfs_load_map_value()
#define LOAD_PROP_GRPS(dataP)            mfs_load_property_groups(dataP)

#endif

/* OTP-4236 */
#define ASSIGN_TERM_SPEC(dataP, what)                   \
{                                                       \
   if (dataP->term_spec != NULL) {                      \
     dataP->term_spec[dataP->term_spec_index++] = what; \
   }                                                    \
}

%}

%x SKIP_RBRKT MTP_HEXDIG LOCAL_OCTETS REMOTE_OCTETS 
%x MAP_NAME MAP_OPT_LBRKT MAP_VALUE MAP_SKIP_COMMA MAP_BODY
%x QUOTED_CHARS SKIP_DQUOTE

digit       ([0-9])
alpha       ([a-zA-Z])
hexdig      ([0-9a-fA-F])
sp          (\x20)
htab        (\x09)
cr          (\x0D)
lf          (\x0A)
slash       (\/)
dquote      (\")
colon       (\:)
dot         (\.)
wsp         ({sp}|{htab})
eol         ({cr}|({cr}{lf})|{lf})
safechar    ({digit}|{alpha}|[\+\-\&\!\_\/\'\?\@\^\`\~\*\$\\\(\)\%\|\.])
restchar    ([\;\[\]\{\}\:\,\#\<\>\=])
octet       ((\\\})|[\x01-\x7C\x7E-\xFF])
            
comment     (\;({safechar}|{restchar}|{wsp}|\x22)*{eol})
lwsp        ({wsp}|{comment}|{eol})*
            
equal       ({lwsp}\={lwsp})
nequal      ({lwsp}\#{lwsp})
lesser      ({lwsp}\<{lwsp})
greater     ({lwsp}\>{lwsp})
lbrkt       ({lwsp}\{{lwsp})
rbrkt       ({lwsp}\}{lwsp})
lsbrkt      ({lwsp}\[{lwsp})
rsbrkt      ({lwsp}\]{lwsp})
lpar        ({lwsp}\({lwsp})
rpar        ({lwsp}\){lwsp})
vbar        ({lwsp}\|{lwsp})
comma       ({lwsp}\,{lwsp})
sep         (({wsp}|{eol}|{comment}){lwsp})+
opt         ((o\-)?)
wild        ((w\-)?)

%%

<SKIP_RBRKT>{rbrkt}                     BEGIN(INITIAL);
                           
{digit}{8,8}t{digit}{8,8}               LOAD_TOKEN(mfs_TimeStampToken); /* OTP-5042 */
                                        
(MTP){lbrkt}                            BEGIN(MTP_HEXDIG);
<MTP_HEXDIG>{hexdig}{4,8}               {LOAD_TOKEN(mfs_MtpAddressToken); BEGIN(SKIP_RBRKT);}
                                        
((Local)|L){lbrkt}                      BEGIN(LOCAL_OCTETS);
<LOCAL_OCTETS>{rbrkt}                   {LOAD_EMPTY_OCTET_TOKEN(mfs_LocalDescriptorToken); BEGIN(INITIAL);}
<LOCAL_OCTETS>{octet}+                  {LOAD_OCTET_TOKEN(mfs_LocalDescriptorToken); BEGIN(SKIP_RBRKT);}
                          
((Remote)|R){lbrkt}                     BEGIN(REMOTE_OCTETS);
<REMOTE_OCTETS>{rbrkt}                  {LOAD_EMPTY_OCTET_TOKEN(mfs_RemoteDescriptorToken); BEGIN(INITIAL);}
<REMOTE_OCTETS>{octet}+                 {LOAD_OCTET_TOKEN(mfs_RemoteDescriptorToken); BEGIN(SKIP_RBRKT);}
                                        
((DigitMap)|DM)                         LOAD_TOKEN(mfs_DigitMapToken);
((DigitMap)|DM){equal}                  BEGIN(MAP_NAME);
((DigitMap)|DM){equal}{lbrkt}           BEGIN(MAP_VALUE);
((DigitMap)|DM){lbrkt}                  BEGIN(MAP_VALUE);

<MAP_NAME>{safechar}+                   {LOAD_MAP_NAME(); BEGIN(MAP_OPT_LBRKT);}

<MAP_OPT_LBRKT>{lbrkt}                  BEGIN(MAP_VALUE);
<MAP_OPT_LBRKT><<EOF>>                  {LOAD_MAP_TOKEN(); LOAD_TOKEN(mfs_endOfMessage); BEGIN(INITIAL); yyterminate();}
<MAP_OPT_LBRKT>.|\n                     {LOAD_MAP_TOKEN(); yyless(0); BEGIN(INITIAL);}

<MAP_VALUE>t{colon}{digit}{1,2}         {LOAD_MAP_TIMER(); BEGIN(MAP_SKIP_COMMA);}
<MAP_VALUE>s{colon}{digit}{1,2}         {LOAD_MAP_TIMER(); BEGIN(MAP_SKIP_COMMA);}
<MAP_VALUE>l{colon}{digit}{1,2}         {LOAD_MAP_TIMER(); BEGIN(MAP_SKIP_COMMA);}
<MAP_VALUE>z{colon}{digit}{1,2}         {LOAD_MAP_TIMER(); BEGIN(MAP_SKIP_COMMA);}
<MAP_VALUE>.|\n                         {yyless(0); BEGIN(MAP_BODY);}

<MAP_SKIP_COMMA>{comma}                 BEGIN(MAP_VALUE);

<MAP_BODY>{octet}+                      {LOAD_MAP_VALUE(); LOAD_MAP_TOKEN(); BEGIN(SKIP_RBRKT);}

{equal}                                 LOAD_SHORT_TOKEN(mfs_EQUAL);
{colon}                                 LOAD_SHORT_TOKEN(mfs_COLON);
{lbrkt}                                 LOAD_SHORT_TOKEN(mfs_LBRKT);
{rbrkt}                                 LOAD_SHORT_TOKEN(mfs_RBRKT);
{lsbrkt}                                LOAD_SHORT_TOKEN(mfs_LSBRKT);
{rsbrkt}                                LOAD_SHORT_TOKEN(mfs_RSBRKT);
{comma}                                 LOAD_SHORT_TOKEN(mfs_COMMA);
{nequal}                                LOAD_SHORT_TOKEN(mfs_NEQUAL);
{lesser}                                LOAD_SHORT_TOKEN(mfs_LESSER);
{greater}                               LOAD_SHORT_TOKEN(mfs_GREATER);
{sep}                                   LOAD_SHORT_TOKEN(mfs_SEP);

{dquote}                                BEGIN(QUOTED_CHARS);

<QUOTED_CHARS>{dquote}                  {LOAD_EMPTY_TOKEN(mfs_QuotedChars); BEGIN(INITIAL);}
<QUOTED_CHARS>({safechar}|{restchar}|{wsp})+ {LOAD_TOKEN(mfs_QuotedChars); BEGIN(SKIP_DQUOTE);}

<SKIP_DQUOTE>{dquote}                   BEGIN(INITIAL);
                                        
{opt}{wild}add                          LOAD_TOKEN(mfs_AddToken);
{opt}{wild}a                            LOAD_TOKEN(mfs_AddToken);
andlgc                                  LOAD_TOKEN(mfs_AndAUDITSelectToken);
audit                                   LOAD_TOKEN(mfs_AuditToken);
at                                      LOAD_TOKEN(mfs_AuditToken);
{opt}{wild}auditcapability              LOAD_TOKEN(mfs_AuditCapToken);
{opt}{wild}ac                           LOAD_TOKEN(mfs_AuditCapToken);
{opt}{wild}auditvalue                   LOAD_TOKEN(mfs_AuditValueToken);
{opt}{wild}av                           LOAD_TOKEN(mfs_AuditValueToken);
authentication                          LOAD_TOKEN(mfs_AuthToken);
au                                      LOAD_TOKEN(mfs_AuthToken);
both                                    LOAD_TOKEN(mfs_BothToken);
b                                       LOAD_TOKEN(mfs_BothToken);
bothway                                 LOAD_TOKEN(mfs_BothwayToken);
bw                                      LOAD_TOKEN(mfs_BothwayToken);
brief                                   LOAD_TOKEN(mfs_BriefToken);
br                                      LOAD_TOKEN(mfs_BriefToken);
buffer                                  LOAD_TOKEN(mfs_BufferToken);
bf                                      LOAD_TOKEN(mfs_BufferToken);
context                                 LOAD_TOKEN(mfs_CtxToken);
c                                       LOAD_TOKEN(mfs_CtxToken);
contextattr                             LOAD_TOKEN(mfs_ContextAttrToken);
ct                                      LOAD_TOKEN(mfs_ContextAttrToken);
contextaudit                            LOAD_TOKEN(mfs_ContextAuditToken);
ca                                      LOAD_TOKEN(mfs_ContextAuditToken);
contextlist                             LOAD_TOKEN(mfs_ContextListToken);
clt                                     LOAD_TOKEN(mfs_ContextListToken);
spadirection                            LOAD_TOKEN(mfs_DirectionToken);
direction                               LOAD_TOKEN(mfs_DirectionToken);
spadi                                   LOAD_TOKEN(mfs_DirectionToken);
di                                      LOAD_TOKEN(mfs_DirectionToken);
discard                                 LOAD_TOKEN(mfs_DiscardToken);
ds                                      LOAD_TOKEN(mfs_DiscardToken);
disconnected                            LOAD_TOKEN(mfs_DisconnectedToken);
dc                                      LOAD_TOKEN(mfs_DisconnectedToken);
delay                                   LOAD_TOKEN(mfs_DelayToken);
dl                                      LOAD_TOKEN(mfs_DelayToken);
delete                                  LOAD_TOKEN(mfs_DeleteToken);
de                                      LOAD_TOKEN(mfs_DeleteToken);
duration                                LOAD_TOKEN(mfs_DurationToken);
dr                                      LOAD_TOKEN(mfs_DurationToken);
embed                                   LOAD_TOKEN(mfs_EmbedToken);
em                                      LOAD_TOKEN(mfs_EmbedToken);
emergency                               LOAD_TOKEN(mfs_EmergencyToken);
eg                                      LOAD_TOKEN(mfs_EmergencyToken);
emergencyoff                            LOAD_TOKEN(mfs_EmergencyOffToken); 
emergencyofftoken                       LOAD_TOKEN(mfs_EmergencyOffToken);
ego                                     LOAD_TOKEN(mfs_EmergencyOffToken);
emergencyvalue                          LOAD_TOKEN(mfs_EmergencyValueToken); 
egv                                     LOAD_TOKEN(mfs_EmergencyValueToken);
error                                   LOAD_TOKEN(mfs_ErrorToken);
er                                      LOAD_TOKEN(mfs_ErrorToken);
eventbuffer                             LOAD_TOKEN(mfs_EventBufferToken);
eb                                      LOAD_TOKEN(mfs_EventBufferToken);
events                                  LOAD_TOKEN(mfs_EventsToken);
e                                       LOAD_TOKEN(mfs_EventsToken);
external                                LOAD_TOKEN(mfs_ExternalToken);
ex                                      LOAD_TOKEN(mfs_ExternalToken);
failover                                LOAD_TOKEN(mfs_FailoverToken);
fl                                      LOAD_TOKEN(mfs_FailoverToken);
forced                                  LOAD_TOKEN(mfs_ForcedToken);
fo                                      LOAD_TOKEN(mfs_ForcedToken);
graceful                                LOAD_TOKEN(mfs_GracefulToken);
gr                                      LOAD_TOKEN(mfs_GracefulToken);
h221                                    LOAD_TOKEN(mfs_H221Token);
h223                                    LOAD_TOKEN(mfs_H223Token);
h226                                    LOAD_TOKEN(mfs_H226Token);
handoff                                 LOAD_TOKEN(mfs_HandOffToken);
ho                                      LOAD_TOKEN(mfs_HandOffToken);
iepscall                                LOAD_TOKEN(mfs_IEPSToken);
ieps                                    LOAD_TOKEN(mfs_IEPSToken);
inactive                                LOAD_TOKEN(mfs_InactiveToken);
in                                      LOAD_TOKEN(mfs_InactiveToken);
immackrequired                          LOAD_TOKEN(mfs_ImmAckRequiredToken);
ia                                      LOAD_TOKEN(mfs_ImmAckRequiredToken);
inservice                               LOAD_TOKEN(mfs_InSvcToken);
iv                                      LOAD_TOKEN(mfs_InSvcToken);
internal                                LOAD_TOKEN(mfs_InternalToken);
it                                      LOAD_TOKEN(mfs_InternalToken);
intersignal                             LOAD_TOKEN(mfs_IntsigDelayToken);
spais                                   LOAD_TOKEN(mfs_IntsigDelayToken);
isolate                                 LOAD_TOKEN(mfs_IsolateToken);
is                                      LOAD_TOKEN(mfs_IsolateToken);
intbyevent                              LOAD_TOKEN(mfs_InterruptByEventToken);
ibe                                     LOAD_TOKEN(mfs_InterruptByEventToken);
intbysigdescr                           LOAD_TOKEN(mfs_InterruptByNewSignalsDescrToken);
ibs                                     LOAD_TOKEN(mfs_InterruptByNewSignalsDescrToken);
iteration                               LOAD_TOKEN(mfs_IterationToken);
ir                                      LOAD_TOKEN(mfs_IterationToken);
keepactive                              LOAD_TOKEN(mfs_KeepActiveToken);
ka                                      LOAD_TOKEN(mfs_KeepActiveToken);
local                                   LOAD_TOKEN(mfs_LocalToken);
l                                       LOAD_TOKEN(mfs_LocalToken);
localcontrol                            LOAD_TOKEN(mfs_LocalControlToken);
lockstep                                LOAD_TOKEN(mfs_LockStepToken);
sp                                      LOAD_TOKEN(mfs_LockStepToken);
o                                       LOAD_TOKEN(mfs_LocalControlToken);
loopback                                LOAD_TOKEN(mfs_LoopbackToken);
lb                                      LOAD_TOKEN(mfs_LoopbackToken);
media                                   LOAD_TOKEN(mfs_MediaToken);
m                                       LOAD_TOKEN(mfs_MediaToken);
megaco                                  LOAD_TOKEN(mfs_MegacopToken);
!                                       LOAD_TOKEN(mfs_MegacopToken);
segment                                 LOAD_TOKEN(mfs_MessageSegmentToken);
sm                                      LOAD_TOKEN(mfs_MessageSegmentToken);
method                                  LOAD_TOKEN(mfs_MethodToken);
mt                                      LOAD_TOKEN(mfs_MethodToken);
mgcidtotry                              LOAD_TOKEN(mfs_MgcIdToken);
mg                                      LOAD_TOKEN(mfs_MgcIdToken);
mode                                    LOAD_TOKEN(mfs_ModeToken);
mo                                      LOAD_TOKEN(mfs_ModeToken);
{opt}modify                             LOAD_TOKEN(mfs_ModifyToken);
{opt}mf                                 LOAD_TOKEN(mfs_ModifyToken);
modem                                   LOAD_TOKEN(mfs_ModemToken);
md                                      LOAD_TOKEN(mfs_ModemToken);
{opt}move                               LOAD_TOKEN(mfs_MoveToken);
{opt}mv                                 LOAD_TOKEN(mfs_MoveToken);
mux                                     LOAD_TOKEN(mfs_MuxToken);
mx                                      LOAD_TOKEN(mfs_MuxToken);
nevernotify                             LOAD_TOKEN(mfs_NeverNotifyToken);
nbnn                                    LOAD_TOKEN(mfs_NeverNotifyToken);
{opt}{wild}notify                       LOAD_TOKEN(mfs_NotifyToken);
{opt}{wild}n                            LOAD_TOKEN(mfs_NotifyToken);
notifycompletion                        LOAD_TOKEN(mfs_NotifyCompletionToken);
nc                                      LOAD_TOKEN(mfs_NotifyCompletionToken);
immediatenotify                         LOAD_TOKEN(mfs_NotifyImmediateToken);
nbin                                    LOAD_TOKEN(mfs_NotifyImmediateToken);
regulatednotify                         LOAD_TOKEN(mfs_NotifyRegulatedToken);
nbrn                                    LOAD_TOKEN(mfs_NotifyRegulatedToken);
nx64kservice                            LOAD_TOKEN(mfs_Nx64kToken);
n64                                     LOAD_TOKEN(mfs_Nx64kToken);
observedevents                          LOAD_TOKEN(mfs_ObservedEventsToken);
oe                                      LOAD_TOKEN(mfs_ObservedEventsToken);
oneway                                  LOAD_TOKEN(mfs_OnewayToken);
ow                                      LOAD_TOKEN(mfs_OnewayToken);
onewayboth                              LOAD_TOKEN(mfs_OnewayBothToken);
owb                                     LOAD_TOKEN(mfs_OnewayBothToken);
onewayexternal                          LOAD_TOKEN(mfs_OnewayExternalToken);
owe                                     LOAD_TOKEN(mfs_OnewayExternalToken);
off                                     LOAD_TOKEN(mfs_OffToken);
on                                      LOAD_TOKEN(mfs_OnToken);
onoff                                   LOAD_TOKEN(mfs_OnOffToken);
oo                                      LOAD_TOKEN(mfs_OnOffToken);
orlgc                                   LOAD_TOKEN(mfs_OrAUDITselectToken);
otherreason                             LOAD_TOKEN(mfs_OtherReasonToken);
or                                      LOAD_TOKEN(mfs_OtherReasonToken);
outofservice                            LOAD_TOKEN(mfs_OutOfSvcToken);
os                                      LOAD_TOKEN(mfs_OutOfSvcToken);
packages                                LOAD_TOKEN(mfs_PackagesToken);
pg                                      LOAD_TOKEN(mfs_PackagesToken);
pending                                 LOAD_TOKEN(mfs_PendingToken);
pn                                      LOAD_TOKEN(mfs_PendingToken);
priority                                LOAD_TOKEN(mfs_PriorityToken);
pr                                      LOAD_TOKEN(mfs_PriorityToken);
profile                                 LOAD_TOKEN(mfs_ProfileToken);
pf                                      LOAD_TOKEN(mfs_ProfileToken);
reason                                  LOAD_TOKEN(mfs_ReasonToken);
re                                      LOAD_TOKEN(mfs_ReasonToken);
receiveonly                             LOAD_TOKEN(mfs_RecvonlyToken);
rc                                      LOAD_TOKEN(mfs_RecvonlyToken);
reply                                   LOAD_TOKEN(mfs_ReplyToken);
p                                       LOAD_TOKEN(mfs_ReplyToken);
reseteventsdescriptor                   LOAD_TOKEN(mfs_ResetEventsDescriptorToken);
rse                                     LOAD_TOKEN(mfs_ResetEventsDescriptorToken);
transactionresponseack                  LOAD_TOKEN(mfs_ResponseAckToken);
k                                       LOAD_TOKEN(mfs_ResponseAckToken);
restart                                 LOAD_TOKEN(mfs_RestartToken);
rs                                      LOAD_TOKEN(mfs_RestartToken);
remote                                  LOAD_TOKEN(mfs_RemoteToken);
r                                       LOAD_TOKEN(mfs_RemoteToken);
sparequestid                            LOAD_TOKEN(mfs_RequestIDToken);
requestid                               LOAD_TOKEN(mfs_RequestIDToken);
sparq                                   LOAD_TOKEN(mfs_RequestIDToken);
rq                                      LOAD_TOKEN(mfs_RequestIDToken);
reservedgroup                           LOAD_TOKEN(mfs_ReservedGroupToken);
rg                                      LOAD_TOKEN(mfs_ReservedGroupToken);
reservedvalue                           LOAD_TOKEN(mfs_ReservedValueToken);
rv                                      LOAD_TOKEN(mfs_ReservedValueToken);
end                                     LOAD_TOKEN(mfs_SegmentationCompleteToken);
&                                       LOAD_TOKEN(mfs_SegmentationCompleteToken);
sendonly                                LOAD_TOKEN(mfs_SendonlyToken);
so                                      LOAD_TOKEN(mfs_SendonlyToken);
sendreceive                             LOAD_TOKEN(mfs_SendrecvToken);
sr                                      LOAD_TOKEN(mfs_SendrecvToken);
services                                LOAD_TOKEN(mfs_ServicesToken);
sv                                      LOAD_TOKEN(mfs_ServicesToken);
servicestates                           LOAD_TOKEN(mfs_ServiceStatesToken);
si                                      LOAD_TOKEN(mfs_ServiceStatesToken);
{opt}{wild}servicechange                LOAD_TOKEN(mfs_ServiceChangeToken);
{opt}{wild}sc                           LOAD_TOKEN(mfs_ServiceChangeToken);
servicechangeaddress                    LOAD_TOKEN(mfs_ServiceChangeAddressToken);
ad                                      LOAD_TOKEN(mfs_ServiceChangeAddressToken);
servicechangeinc                        LOAD_TOKEN(mfs_ServiceChangeIncompleteToken);
sic                                     LOAD_TOKEN(mfs_ServiceChangeIncompleteToken);
signallist                              LOAD_TOKEN(mfs_SignalListToken);
sl                                      LOAD_TOKEN(mfs_SignalListToken);
signals                                 LOAD_TOKEN(mfs_SignalsToken);
sg                                      LOAD_TOKEN(mfs_SignalsToken);
signaltype                              LOAD_TOKEN(mfs_SignalTypeToken);
sy                                      LOAD_TOKEN(mfs_SignalTypeToken);
statistics                              LOAD_TOKEN(mfs_StatsToken);
sa                                      LOAD_TOKEN(mfs_StatsToken);
stream                                  LOAD_TOKEN(mfs_StreamToken);
st                                      LOAD_TOKEN(mfs_StreamToken);
{opt}{wild}subtract                     LOAD_TOKEN(mfs_SubtractToken);
{opt}{wild}s                            LOAD_TOKEN(mfs_SubtractToken);
synchisdn                               LOAD_TOKEN(mfs_SynchISDNToken);
sn                                      LOAD_TOKEN(mfs_SynchISDNToken);
terminationstate                        LOAD_TOKEN(mfs_TerminationStateToken);
ts                                      LOAD_TOKEN(mfs_TerminationStateToken);
test                                    LOAD_TOKEN(mfs_TestToken);
te                                      LOAD_TOKEN(mfs_TestToken);
timeout                                 LOAD_TOKEN(mfs_TimeOutToken);
to                                      LOAD_TOKEN(mfs_TimeOutToken);
topology                                LOAD_TOKEN(mfs_TopologyToken);
tp                                      LOAD_TOKEN(mfs_TopologyToken);
transaction                             LOAD_TOKEN(mfs_TransToken);
t                                       LOAD_TOKEN(mfs_TransToken);
v18                                     LOAD_TOKEN(mfs_V18Token);
v22                                     LOAD_TOKEN(mfs_V22Token);
v22b                                    LOAD_TOKEN(mfs_V22bisToken);
v32                                     LOAD_TOKEN(mfs_V32Token);
v32b                                    LOAD_TOKEN(mfs_V32bisToken);
v34                                     LOAD_TOKEN(mfs_V34Token);
v76                                     LOAD_TOKEN(mfs_V76Token);
v90                                     LOAD_TOKEN(mfs_V90Token);
v91                                     LOAD_TOKEN(mfs_V91Token);
version                                 LOAD_TOKEN(mfs_VersionToken);
v                                       LOAD_TOKEN(mfs_VersionToken);
({safechar})+                           LOAD_TOKEN(mfs_SafeChars);
                                        
<<EOF>>                                 {LOAD_SHORT_TOKEN(mfs_endOfMessage); BEGIN(INITIAL); yyterminate();}
<*>.|\n                                 {LOAD_TOKEN(mfs_IllegalChar); BEGIN(INITIAL); yyterminate();}

%%

/* MEGACO_LINENO_OR_TOKENCOUNTER
 * Note that this construction is intended to make it
 * possible to generate flex files that either reports
 * line-number or one that don't.
 * See MEGACO_YY_LINENO_OPTION and 
 *     MEGACO_DUMMY_DECL_YY_LINENO above.
 */

#if defined(MEGACO_LINENO)
#define LINENO_OR_TOKENCNT(P) yylineno
#else
#define LINENO_OR_TOKENCNT(P) P->token_counter
#endif


// #define MFS_DEBUG true 
#if defined(MFS_DEBUG)
#  define DBG( proto ) printf proto
#  define DBG_BUF(func, bufName, buf, bufSz) mfs_dbg_buf_print(func, bufName, buf, bufSz)
#else
#  define DBG( proto ) ((void) 0)
#  define DBG_BUF(func, bufName, buf, bufSz) ((void) 0)
#endif /* if defined(MFS_DEBUG) */


#if defined(MFS_DEBUG)

#define CHUNK 16

static void hexdump(unsigned char *buf, int bufsz)
{
  int i,j;
  int count;

  /* do this in chunks of CHUNK bytes */
  for (i=0; i<bufsz; i+=CHUNK) {
    /* show the offset */
    printf("0x%06x  ", i);

    /* max of CHUNK or remaining bytes */
    count = ((bufsz-i) > CHUNK ? CHUNK : bufsz-i);
    
    /* show the bytes */
    for (j=0; j<count; j++) {
      if (j==CHUNK/2) printf(" ");
      printf("%02x ",buf[i+j]);
    }
    
    /* pad with spaces if less than CHUNK */
    for (j=count; j<CHUNK; j++) {
      if (j==CHUNK/2) printf(" ");
      printf("   ");
    }

    /* divider between hex and ascii */
    printf(" ");
  
    for (j=0; j<count; j++) 
      printf("%c",(isprint(buf[i+j]) ? buf[i+j] : '.'));
 
    printf("\n");
  }
}

static void mfs_dbg_buf_print(char* func, char* bufName, char* buf, int len)
{
  printf("%s -> %s (%d):\n", func, bufName, len);
  hexdump((unsigned char*) buf, len);
}


#endif /* if defined(MFS_DEBUG) */

static void mfs_alloc_failed(MfsErlDrvData* dataP, char* msg, int sz)
{
  /*
   * Make sure we are not allready in error state
   */
  if (!dataP->error) {

    /* 
     * Make sure that there is room in the buffer:
     * length of msg + 10 chars for the ' of %d bytes'
     * + 10 chars for the size value...
     * This is really overkill since the msg string is never
     * longer then 50 chars, but sinze this function is 
     * called when we have run out of memory...
     */

    int msg_len = strlen(msg);
    if ((10 + 10 + msg_len) < sizeof(dataP->error_msg)) {
      if (0 >= sprintf(dataP->error_msg, "%s of %d bytes", msg, sz)) {
	mfs_fatal_error(dataP, msg);
      }
    } else {
      mfs_fatal_error(dataP, msg);
    }
    dataP->error = TRUE;
  }
}


static void mfs_ensure_term_spec(MfsErlDrvData* dataP, int size)
{
  DBG( ("mfs_ensure_term_spec -> entry with"
	"\n   size:       %d"
	"\nwhen"
	"\n   spec_index: %d"
	"\n   spec_size:  %d"
	"\n", size, dataP->term_spec_index, dataP->term_spec_size) );

  /* OTP-4236 - BEGIN */
  if ((dataP->term_spec_index + size) >= dataP->term_spec_size) {
    void *tmp;

    DBG( ("mfs_ensure_term_spec -> allocate more memory when"
	  "\n   term_spec_index: %d"
	  "\n   term_spec_size:  %d\n", 
	  dataP->term_spec_index, dataP->term_spec_size) );

    dataP->term_spec_size = TERM_SPEC_SIZE_NEXT(dataP->term_spec_size, size);

    DBG( ("mfs_ensure_term_spec -> "
	  "term_spec is at 0x%X, new term_spec_size is %d (%lu)\n", 
	  (unsigned int) dataP->term_spec, 
	  dataP->term_spec_size, 
	  dataP->term_spec_size * sizeof(ErlDrvTermData)) );

    tmp = REALLOC(dataP->term_spec, 
                  dataP->term_spec_size * sizeof(ErlDrvTermData));

    DBG( ("mfs_ensure_term_spec -> "
	  "realloc result: 0x%X\n", (unsigned int) tmp) );

    if (tmp == NULL) {
      /*
       * Ouch, we did'nt get any new memory.
       * Just give ut. I.e. free the memory we have (note that
       * the assign macro tests the buffer before assigning).
       */
      FREE(dataP->term_spec);
      dataP->term_spec = NULL;

      mfs_alloc_failed(dataP, "failed reallocating term spec buffer", 
		       dataP->term_spec_size * sizeof(ErlDrvTermData));

    } else {
      dataP->term_spec = tmp;
    }

    DBG( ("mfs_ensure_term_spec -> new term_spec is at 0x%X\n", 
	  (unsigned int) dataP->term_spec) );
  }
  /* OTP-4236 - END */
}

#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
static void mfs_short_load_token(ErlDrvTermData TokenTag, yyscan_t yyscanner)
#else
static void mfs_short_load_token(ErlDrvTermData TokenTag)
#endif
{
  /* Build a {TokenTag, LineNumber} tuple */
#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
  struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
  MfsErlDrvData* dataP = (MfsErlDrvData*) yyget_extra(yyscanner);
#else
  MfsErlDrvData* dataP = &mfs_drv_data;
#endif

  /*
  DBG( ("mfs_short_load_token -> entry with"
	"\n   TokenTag: %ld\n", TokenTag) );
  */

  mfs_ensure_term_spec(dataP, 6); 
  dataP->token_counter++; 
  ASSIGN_TERM_SPEC(dataP, ERL_DRV_ATOM);
  ASSIGN_TERM_SPEC(dataP, TokenTag);
  ASSIGN_TERM_SPEC(dataP, ERL_DRV_INT);
  ASSIGN_TERM_SPEC(dataP, LINENO_OR_TOKENCNT(dataP));
  ASSIGN_TERM_SPEC(dataP, ERL_DRV_TUPLE);
  ASSIGN_TERM_SPEC(dataP, 2);
}

#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
static void mfs_octet_load_token(ErlDrvTermData TokenTag, int is_empty, 
                                 yyscan_t yyscanner)
#else
static void mfs_octet_load_token(ErlDrvTermData TokenTag, int is_empty)
#endif
{
  /* Build a {TokenTag, LineNumber, String} tuple */
#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
  struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
  MfsErlDrvData* dataP = (MfsErlDrvData*) yyget_extra(yyscanner);
#else
  MfsErlDrvData* dataP = &mfs_drv_data;
#endif

  DBG( ("mfs_octet_load_token -> entry with"
	"\n   TokenTag: %d"
	"\n   is_empty: %d"
	"\n   yyleng:   %d"
        "\n", (int) TokenTag, is_empty, yyleng) );

  mfs_ensure_term_spec(dataP, 9); 
  dataP->token_counter++; 
  ASSIGN_TERM_SPEC(dataP, ERL_DRV_ATOM);
  ASSIGN_TERM_SPEC(dataP, TokenTag);
  ASSIGN_TERM_SPEC(dataP, ERL_DRV_INT);
  ASSIGN_TERM_SPEC(dataP, LINENO_OR_TOKENCNT(dataP));

  if (is_empty) {

    ASSIGN_TERM_SPEC(dataP, ERL_DRV_NIL);         // End of list

  } else {

    LOAD_PROP_GRPS(dataP);

  }

  ASSIGN_TERM_SPEC(dataP, ERL_DRV_TUPLE);
  ASSIGN_TERM_SPEC(dataP, 3);

  DBG( ("mfs_octet_load_token -> done\n") );

}

#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
static void mfs_lower_load_token(ErlDrvTermData TokenTag, int is_empty, 
                                 yyscan_t yyscanner)
#else
static void mfs_lower_load_token(ErlDrvTermData TokenTag, int is_empty)
#endif
{
  /* Build a {TokenTag, LineNumber, LowerCaseString} tuple */
  int i;
#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
  struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
  MfsErlDrvData* dataP = (MfsErlDrvData*) yyget_extra(yyscanner);
#else
  MfsErlDrvData* dataP = &mfs_drv_data;
#endif

  DBG( ("mfs_lower_load_token -> entry with"
	"\n   TokenTag: %ld"
	"\n   is_empty: %d"
        "\n", TokenTag, is_empty) );

  mfs_ensure_term_spec(dataP, 9); 
  dataP->token_counter++; 
  ASSIGN_TERM_SPEC(dataP, ERL_DRV_ATOM);
  ASSIGN_TERM_SPEC(dataP, TokenTag);
  ASSIGN_TERM_SPEC(dataP, ERL_DRV_INT);
  ASSIGN_TERM_SPEC(dataP, LINENO_OR_TOKENCNT(dataP));
  ASSIGN_TERM_SPEC(dataP, ERL_DRV_STRING);

  if (is_empty) {

    ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData)"");
    ASSIGN_TERM_SPEC(dataP, 0);

  } else {
    for ( i = 0; i < yyleng; ++i ) {
      dataP->text_ptr[i] = tolower(yytext[i]);
    }
    
    DBG_BUF("mfs_lower_load_token", "dataP->text_ptr", 
             dataP->text_ptr, yyleng);
    
    ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData) dataP->text_ptr);
    dataP->text_ptr += yyleng;
    ASSIGN_TERM_SPEC(dataP, yyleng);
  }

  ASSIGN_TERM_SPEC(dataP, ERL_DRV_TUPLE);
  ASSIGN_TERM_SPEC(dataP, 3);
}

#define PG_ERR_PRE "bad_property_parm:"
#define PG_ERR1    "Could not find property parm value for"
#define PG_ERR2    "Could not find proper property parm name"

#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
static void mfs_load_property_groups(MfsErlDrvData* dataP, yyscan_t yyscanner)
#else
static void mfs_load_property_groups(MfsErlDrvData* dataP)
#endif
{
#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
  struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
  // MfsErlDrvData* dataP = (MfsErlDrvData*) yyget_extra(yyscanner);
#else
  // MfsErlDrvData* dataP = &mfs_drv_data;
#endif

  /* 
   * Process the property groups string 
   * v= is a property group delimiter
   */
  
  /*
   * For each string, look for the first '='.
   * Everything to the left is the name and 
   * everything to the right is the value.
   */
  
  int i = 0;          // loop counter
  int numGroups = 0;  // Number of property groups
  int numPps    = 0;  // Number of property parms (in the group)
  char* name;         // Pointer to the name buffer
  int nameStart = 0;  // Start position of the property parm name
  int nameLen;        // Length of the name part
  char* value;        // Pointer to the value buffer
  int valueStart = 0; // Start position of the property parm name
  int valueLen   = 0; // Length of the value part

  DBG( ("mfs_load_property_groups -> entry\n") );

  mfs_ensure_term_spec(dataP, 10);  /*�Just in case... */
 
  while (i <= yyleng) {
    
    /* Skip white-spaces and end-of-line */

    DBG( ("mfs_load_property_groups -> "
          "skip white-spaces and end-of-line: i = %d\n", i) );

    if ((yytext[i] != SP)   && 
        (yytext[i] != HTAB) && 
        (yytext[i] != LF)   &&
        (yytext[i] != CR)   &&
        (yytext[i] != NUL)) {

      DBG( ("mfs_load_property_groups -> "
            "start looking for delimiter ('=')\n") );

      /* Start looking for '=' */
      nameStart = i;
      nameLen   = 0;
      while (i <= yyleng) { 

        /* Is it a name-value delimiter? */
        if (yytext[i] == '=') {

          /* 
           * Found the name/value delimiter 
           */
          nameLen = i-nameStart;

          DBG( ("mfs_load_property_groups -> "
                "found delimiter at %d (name length = %d)\n", i, nameLen) );

          /* 
           * "v=" is the start of a new group.
           * So, check if this maybe is the beginning of
           * the first group or not. If not, we need to
           * "terminate" the previous group.
           */
          if (0 == strncmp("v", &yytext[nameStart], nameLen)) {

            DBG( ("mfs_load_property_groups -> "
                    "found a 'v' when group count is %d\n", numGroups) );

            if (numGroups > 0) {
              /* 
               * End the previous group 
               * (only if this is not the first group) 
               */

              DBG( ("mfs_load_property_groups -> "
                    "start of new group - terminate previous group\n") );

              mfs_ensure_term_spec(dataP, 3);
              ASSIGN_TERM_SPEC(dataP, ERL_DRV_NIL);                  // End of list
              ASSIGN_TERM_SPEC(dataP, ERL_DRV_LIST);                 // List
              ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData) numPps + 1);  // Length of (group) list
              numPps = 0; /* reset for next group */
            } // if ...
            numGroups++;
          } // if ...
          numPps++;
          i++;
          
          /* 
           * Now, look for the end of the value string,
           * which is an EOL = (CR [LF] / LF )
           */ 

          DBG( ("mfs_load_property_groups -> "
                "start looking for end of value\n") );
          valueStart = i;
          valueLen   = 0;
          while (i <= yyleng) { 
            if ((yytext[i] == CR) || (yytext[i] == LF)) {
              valueLen = i-valueStart;
              DBG( ("mfs_load_property_groups -> "
                    "found end of value at %d\n", i) );
              break;
            } else {
              i++;
            } // if ...
          } // while ...

          /* Name */
          name = dataP->text_ptr; 
          strncpy(name, &yytext[nameStart], nameLen);
          name[nameLen] = 0;
          dataP->text_ptr += (nameLen + 1); // Make room for the NULL termination

          /* Check that we actually got a proper value */
          if (valueLen == 0) {
            /* Invalid property parm value */
            DBG( ("mfs_load_property_groups -> "
                  "property parm value not found\n") );

            /**********************************************
             * -record('ErrorDescriptor',
             *         {
             *           errorCode,
             *           errorText = asn1_NOVALUE
             *          }).
             */ 
    
            if (0 >= sprintf(dataP->error_msg, "%s %s %s", 
                             PG_ERR_PRE, PG_ERR1, name)) {
              mfs_fatal_error(dataP, PG_ERR1);
            }
            dataP->error = TRUE;

            DBG( ("mfs_load_property_groups -> "
                  "done after value error (%s)\n", name) );

            return;  // Bail out

          } else {


            /***************************************
             * -record('PropertyParm',
             *         {
             *           name,
             *           value,
             *           extraInfo = asn1_NOVALUE
             *          }). % with extension mark
             */ 
  
            mfs_ensure_term_spec(dataP, 15);       // 2 + 3 + 6 + 2 + 2
  
            DBG( ("mfs_load_property_groups -> "
                  "insert PropertyParm record name\n") );
            ASSIGN_TERM_SPEC(dataP, ERL_DRV_ATOM);
            ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData) mfs_PropertyParm);
  	  
            /* Name */
            DBG( ("mfs_load_property_groups -> insert name field\n") );
            ASSIGN_TERM_SPEC(dataP, ERL_DRV_STRING);
            ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData) name);
            ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData) nameLen);
  	
            /* 
             * value, which is actually a list of length 1 
             * where the "actual value" is the (only) element
             */
            DBG( ("mfs_load_property_groups -> "
                  "insert value field (length = %d)\n", valueLen) );
            value = dataP->text_ptr; 
            strncpy(value, &yytext[valueStart], valueLen);
            dataP->text_ptr += valueLen;
            ASSIGN_TERM_SPEC(dataP, ERL_DRV_STRING);
            ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData) value);
            ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData) valueLen);
            ASSIGN_TERM_SPEC(dataP, ERL_DRV_NIL);            // End of value list
            ASSIGN_TERM_SPEC(dataP, ERL_DRV_LIST); 
            ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData) 1 + 1); // Length of (group) list
  	  
            /* extraInfo - never used */
            DBG( ("mfs_load_property_groups -> "
                  "insert the extraInfo field\n") );
            ASSIGN_TERM_SPEC(dataP, ERL_DRV_ATOM);
            ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData) mfs_asn1_NOVALUE);
  
            DBG( ("mfs_load_property_groups -> "
                  "terminate PropertyParm tuple\n") );
            ASSIGN_TERM_SPEC(dataP, ERL_DRV_TUPLE);
            ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData) 4);
            break;

          } // if (valueLen == 0) ...

        } else {
          DBG( ("mfs_load_property_groups -> "
                "b) skipping %d [%d] (%d)\n", i, yyleng - i, yytext[i]) );
          i++;
        }  // if (yytext[i] == '=')

      } // while (i <= yyleng)

      /* Check that we actually got a proper name  */
      if (nameLen == 0) {
        /* Invalid property parm name */
        DBG( ("mfs_load_property_groups -> "
              "property parm name not found when "
              "nameStart = %d\n", nameStart) );

        if (0 >= sprintf(dataP->error_msg, "%s %s (name start at %d)", 
                         PG_ERR_PRE, PG_ERR2, nameStart)) {
          mfs_fatal_error(dataP, PG_ERR2);
        }

        dataP->error = TRUE;

        DBG( ("mfs_load_property_groups -> done after name error\n") );

        return;  // Bail out

      } // if (nameLen == 0) ...

    } else {
      DBG( ("mfs_load_property_groups -> "
            "a) skipping %d [%d] (%d)\n", i, yyleng - i, yytext[i]) );
      i++; // next
    } // if ((yytext[i] != SP)...
  } // while ...      
      
  mfs_ensure_term_spec(dataP, 6); // 3 + 3 just in case

  /* Make sure we actually have some groups */

  if (numGroups > 0) {

    DBG( ("mfs_load_property_groups -> "
          "terminate group (list of properties) list (length = %d)\n", 
          numPps) );

    /* Terminate the final group */
    ASSIGN_TERM_SPEC(dataP, ERL_DRV_NIL);                  // End of list
    ASSIGN_TERM_SPEC(dataP, ERL_DRV_LIST); 
    ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData) numPps + 1);  // Length of (group) list
    
  }

  DBG( ("mfs_load_property_groups -> "
        "terminate groups (list of property groups) list (length = %d)\n", 
        numGroups) );
  
  ASSIGN_TERM_SPEC(dataP, ERL_DRV_NIL);                    // End of list
  ASSIGN_TERM_SPEC(dataP, ERL_DRV_LIST);
  ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData) numGroups + 1); // Length of (groups) list

  DBG( ("mfs_load_property_groups -> done\n") );
}


#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
static void mfs_load_map_name(yyscan_t yyscanner)
#else
static void mfs_load_map_name()
#endif
{
  /* Copy digit map name as lower case */
  int i;
#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
  struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
  MfsErlDrvData* dataP = (MfsErlDrvData*) yyget_extra(yyscanner);
#else
  MfsErlDrvData* dataP = &mfs_drv_data;
#endif
  
  for ( i = 0; i < yyleng; ++i ) {
    dataP->text_ptr[i] = tolower(yytext[i]);
  }
  
  dataP->digit_map_name_ptr = dataP->text_ptr;
  dataP->digit_map_name_len = yyleng;
  dataP->text_ptr += yyleng;
}

#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
static void mfs_load_map_value(yyscan_t yyscanner)
#else
static void mfs_load_map_value()
#endif
{
  /* Copy digit map value as lower case */
  int i;
#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
  struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
  MfsErlDrvData* dataP = (MfsErlDrvData*) yyget_extra(yyscanner);
#else
  MfsErlDrvData* dataP = &mfs_drv_data;
#endif
  
  for ( i = 0; i < yyleng; ++i ) {
    dataP->text_ptr[i] = tolower(yytext[i]);
  }
  
  dataP->digit_map_value_ptr = dataP->text_ptr;
  dataP->digit_map_value_len = yyleng;
  dataP->text_ptr += yyleng;
}

#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
static void mfs_load_map_timer(yyscan_t yyscanner)
#else
static void mfs_load_map_timer()
#endif
{
#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
  struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
  MfsErlDrvData* dataP = (MfsErlDrvData*) yyget_extra(yyscanner);
#else
  MfsErlDrvData* dataP = &mfs_drv_data;
#endif
  int timer_len = yyleng - 2;

  /* The digit map timer consists of 3 or 4 characters:
   * z and Z are actually version 2 only
   * 0 - the kind of timer (t|T|s|S|l|L|z|Z)
   * 1 - a colon
   * 2 - mandatory digit
   * 3 - optional digit
   */
  
  /*
  DBG( ("mfs_load_map_timer -> entry when yyleng: %d\n", yyleng) );
  DBG( ("mfs_load_map_timer -> yytext: 0x%x\n", yytext) );

  DBG( ("mfs_load_map_timer -> yytext[0]: %u (%c)\n", yytext[0], yytext[0]) );
  DBG( ("mfs_load_map_timer -> yytext[1]: %u (%c)\n", yytext[1], yytext[1]) );
  DBG( ("mfs_load_map_timer -> yytext[2]: %u (%c)\n", yytext[2], yytext[2]) );
  DBG( ("mfs_load_map_timer -> yytext[3]: %u (%c)\n", yytext[3], yytext[3]) );
  */

  /* Pad with leading zero */

  if (timer_len == 1) {
    dataP->text_ptr[0] = '0';
    dataP->text_ptr[1] = yytext[2];
  } else if (timer_len == 2) {
    dataP->text_ptr[0] = yytext[2];
    dataP->text_ptr[1] = yytext[3];
  }

  /*
  DBG( ("mfs_load_map_timer -> dataP->text_ptr[0]: %u (%c)\n", 
	dataP->text_ptr[0], dataP->text_ptr[0]) );
  DBG( ("mfs_load_map_timer -> dataP->text_ptr[1]: %u (%c)\n", 
	dataP->text_ptr[1], dataP->text_ptr[1]) );

  DBG( ("mfs_load_map_timer -> dataP->text_ptr: 0x%x\n", 
	dataP->text_ptr) );
  */

  switch (yytext[0]) {
  case 't':
  case 'T':
    dataP->digit_map_start_ptr = dataP->text_ptr;
    break;;
  case 's':
  case 'S':
    dataP->digit_map_short_ptr = dataP->text_ptr;
    break;;
  case 'l':
  case 'L':
    dataP->digit_map_long_ptr = dataP->text_ptr;
    break;;
  case 'z':
  case 'Z':
    dataP->digit_map_duration_ptr = dataP->text_ptr;
    break;;
  }

  /* We pad when there is only one digit, so it will always be two */
  dataP->text_ptr += 2; 

}

static void mfs_load_timer_field(MfsErlDrvData* dataP, char* text)
{
  mfs_ensure_term_spec(dataP, 2);    /* OTP-4236 */
  if (text == NULL) {
    ASSIGN_TERM_SPEC(dataP, ERL_DRV_ATOM);
    ASSIGN_TERM_SPEC(dataP, mfs_asn1_NOVALUE);
  } else {
    ASSIGN_TERM_SPEC(dataP, ERL_DRV_INT);
    ASSIGN_TERM_SPEC(dataP, ((text[0] - '0') * 10) + (text[1] - '0'));
  }
}

#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
static void mfs_load_map_token(yyscan_t yyscanner)
#else
static void mfs_load_map_token()
#endif
{
  /* 
   * Build a {'DigitMapDescriptorToken', LineNumber, 
   *          {'DigitMapDescriptor', DigitMapName, DigitMapValue}} tuple 
   */
#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
  struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; 
  MfsErlDrvData* dataP = (MfsErlDrvData*) yyget_extra(yyscanner);
#else
  MfsErlDrvData* dataP = &mfs_drv_data;
#endif

  mfs_ensure_term_spec(dataP, 20); 
  dataP->token_counter++; 
  ASSIGN_TERM_SPEC(dataP, ERL_DRV_ATOM);
  ASSIGN_TERM_SPEC(dataP, mfs_DigitMapDescriptorToken);
  ASSIGN_TERM_SPEC(dataP, ERL_DRV_INT);
  ASSIGN_TERM_SPEC(dataP, LINENO_OR_TOKENCNT(dataP));
  
  ASSIGN_TERM_SPEC(dataP, ERL_DRV_ATOM);
  ASSIGN_TERM_SPEC(dataP, mfs_DigitMapDescriptor);
  
  if (dataP->digit_map_name_ptr == 0) {
    ASSIGN_TERM_SPEC(dataP, ERL_DRV_ATOM);
    ASSIGN_TERM_SPEC(dataP, mfs_asn1_NOVALUE);
  } else {
    ASSIGN_TERM_SPEC(dataP, ERL_DRV_STRING);
    ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData) dataP->digit_map_name_ptr);
    ASSIGN_TERM_SPEC(dataP, dataP->digit_map_name_len);
    dataP->digit_map_name_ptr = NULL; 
  }
  
  if (dataP->digit_map_value_ptr == NULL) {
    ASSIGN_TERM_SPEC(dataP, ERL_DRV_ATOM);
    ASSIGN_TERM_SPEC(dataP, mfs_asn1_NOVALUE);
  } else {
    ASSIGN_TERM_SPEC(dataP, ERL_DRV_ATOM);
    ASSIGN_TERM_SPEC(dataP, mfs_DigitMapValue);
    
    /* Take care of timer values */
    mfs_load_timer_field(dataP, dataP->digit_map_start_ptr);
    dataP->digit_map_start_ptr = NULL;
    
    mfs_load_timer_field(dataP, dataP->digit_map_short_ptr);
    dataP->digit_map_short_ptr = NULL;
    
    mfs_load_timer_field(dataP, dataP->digit_map_long_ptr);
    dataP->digit_map_long_ptr = NULL;
    
    mfs_load_timer_field(dataP, dataP->digit_map_duration_ptr);
    dataP->digit_map_duration_ptr = NULL;
    
    ASSIGN_TERM_SPEC(dataP, ERL_DRV_STRING);
    ASSIGN_TERM_SPEC(dataP, (ErlDrvTermData) dataP->digit_map_value_ptr);
    ASSIGN_TERM_SPEC(dataP, dataP->digit_map_value_len);
    dataP->digit_map_value_ptr = NULL; 
    ASSIGN_TERM_SPEC(dataP, ERL_DRV_TUPLE);
    ASSIGN_TERM_SPEC(dataP, 6);
  }
  
  ASSIGN_TERM_SPEC(dataP, ERL_DRV_TUPLE);
  ASSIGN_TERM_SPEC(dataP, 3);
  
  ASSIGN_TERM_SPEC(dataP, ERL_DRV_TUPLE);
  ASSIGN_TERM_SPEC(dataP, 3);

}


DRIVER_INIT(mfs_drv)
{
  DBG( ("DRIVER_INIT(mfs_drv) -> entry\n") );

  return &mfs_entry;
}

static ErlDrvData mfs_start(ErlDrvPort port, char *buf)
{
#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
  MfsErlDrvData* dataP = ALLOC(sizeof(MfsErlDrvData));
#else
  MfsErlDrvData* dataP = &mfs_drv_data;
#endif

  DBG( ("mfs_start -> entry\n") );

  dataP->port                   = port;
  dataP->port_id                = driver_mk_port(port);
  dataP->digit_map_name_ptr     = NULL;
  dataP->digit_map_name_len     = 0;
  dataP->digit_map_value_ptr    = NULL;
  dataP->digit_map_value_len    = 0;
  dataP->digit_map_start_ptr    = NULL;
  dataP->digit_map_short_ptr    = NULL;
  dataP->digit_map_long_ptr     = NULL;
  dataP->digit_map_duration_ptr = NULL;
  dataP->error                  = FALSE;
  /* dataP->error_msg[512]; */
  dataP->text_buf               = NULL;
  dataP->text_ptr               = NULL;
  dataP->term_spec              = NULL;
  dataP->term_spec_size         = 0;
  dataP->term_spec_index        = 0;
  dataP->token_counter          = 0;

  mfs_AddToken = driver_mk_atom("AddToken");
  mfs_AndAUDITSelectToken = driver_mk_atom("AndAUDITSelectToken");
  mfs_AuditCapToken = driver_mk_atom("AuditCapToken");
  mfs_AuditToken = driver_mk_atom("AuditToken");
  mfs_AuditValueToken = driver_mk_atom("AuditValueToken");
  mfs_AuthToken = driver_mk_atom("AuthToken");
  mfs_BothToken = driver_mk_atom("BothToken");
  mfs_BothwayToken = driver_mk_atom("BothwayToken");
  mfs_BriefToken = driver_mk_atom("BriefToken");
  mfs_BufferToken = driver_mk_atom("BufferToken");
  mfs_COLON = driver_mk_atom("COLON");
  mfs_COMMA = driver_mk_atom("COMMA");
  mfs_ContextAttrToken = driver_mk_atom("ContextAttrToken");
  mfs_ContextAuditToken = driver_mk_atom("ContextAuditToken");
  mfs_ContextListToken = driver_mk_atom("ContextListToken");
  mfs_CtxToken = driver_mk_atom("CtxToken");
  mfs_DelayToken = driver_mk_atom("DelayToken");
  mfs_DeleteToken = driver_mk_atom("DeleteToken");
  mfs_DigitMapDescriptor = driver_mk_atom("DigitMapDescriptor");
  mfs_DigitMapDescriptorToken = driver_mk_atom("DigitMapDescriptorToken");
  mfs_DigitMapToken = driver_mk_atom("DigitMapToken");
  mfs_DigitMapValue = driver_mk_atom("DigitMapValue");
  mfs_DirectionToken = driver_mk_atom("DirectionToken");
  mfs_DiscardToken = driver_mk_atom("DiscardToken");
  mfs_DisconnectedToken = driver_mk_atom("DisconnectedToken");
  mfs_DurationToken = driver_mk_atom("DurationToken");
  mfs_EQUAL = driver_mk_atom("EQUAL");
  mfs_EmbedToken = driver_mk_atom("EmbedToken");
  mfs_EmergencyToken = driver_mk_atom("EmergencyToken");
  mfs_EmergencyOffToken = driver_mk_atom("EmergencyOffToken");
  mfs_EmergencyValueToken = driver_mk_atom("EmergencyValueToken");
  mfs_ErrorToken = driver_mk_atom("ErrorToken");
  mfs_EventBufferToken = driver_mk_atom("EventBufferToken");
  mfs_EventsToken = driver_mk_atom("EventsToken");
  mfs_ExternalToken = driver_mk_atom("ExternalToken");
  mfs_FailoverToken = driver_mk_atom("FailoverToken");
  mfs_ForcedToken = driver_mk_atom("ForcedToken");
  mfs_GREATER = driver_mk_atom("GREATER");
  mfs_GracefulToken = driver_mk_atom("GracefulToken");
  mfs_H221Token = driver_mk_atom("H221Token");
  mfs_H223Token = driver_mk_atom("H223Token");
  mfs_H226Token = driver_mk_atom("H226Token");
  mfs_HandOffToken = driver_mk_atom("HandOffToken");
  mfs_IEPSToken = driver_mk_atom("IEPSToken");
  mfs_IllegalChar = driver_mk_atom("IllegalChar");
  mfs_ImmAckRequiredToken = driver_mk_atom("ImmAckRequiredToken");
  mfs_InSvcToken = driver_mk_atom("InSvcToken");
  mfs_InactiveToken = driver_mk_atom("InactiveToken");
  mfs_InternalToken = driver_mk_atom("InternalToken");
  mfs_InterruptByEventToken = driver_mk_atom("InterruptByEventToken");
  mfs_InterruptByNewSignalsDescrToken = driver_mk_atom("InterruptByNewSignalsDescrToken");
  mfs_IntsigDelayToken = driver_mk_atom("IntsigDelayToken");
  mfs_IsolateToken = driver_mk_atom("IsolateToken");
  mfs_IterationToken = driver_mk_atom("IterationToken");
  mfs_KeepActiveToken = driver_mk_atom("KeepActiveToken");
  mfs_LBRKT = driver_mk_atom("LBRKT");
  mfs_LESSER = driver_mk_atom("LESSER");
  mfs_LSBRKT = driver_mk_atom("LSBRKT");
  mfs_LocalControlToken = driver_mk_atom("LocalControlToken");
  mfs_LocalDescriptorToken = driver_mk_atom("LocalDescriptorToken");
  mfs_LocalToken = driver_mk_atom("LocalToken");
  mfs_LockStepToken = driver_mk_atom("LockStepToken");
  mfs_LoopbackToken = driver_mk_atom("LoopbackToken");
  mfs_MediaToken = driver_mk_atom("MediaToken");
  mfs_MegacopToken = driver_mk_atom("MegacopToken");
  mfs_MessageSegmentToken = driver_mk_atom("MessageSegmentToken");
  mfs_MethodToken = driver_mk_atom("MethodToken");
  mfs_MgcIdToken = driver_mk_atom("MgcIdToken");
  mfs_ModeToken = driver_mk_atom("ModeToken");
  mfs_ModemToken = driver_mk_atom("ModemToken");
  mfs_ModifyToken = driver_mk_atom("ModifyToken");
  mfs_MoveToken = driver_mk_atom("MoveToken");
  mfs_MtpAddressToken = driver_mk_atom("MtpAddressToken");
  mfs_MuxToken = driver_mk_atom("MuxToken");
  mfs_NEQUAL = driver_mk_atom("NEQUAL");
  mfs_NotifyCompletionToken = driver_mk_atom("NotifyCompletionToken");
  mfs_NotifyImmediateToken = driver_mk_atom("NotifyImmediateToken");
  mfs_NotifyRegulatedToken = driver_mk_atom("NotifyRegulatedToken");
  mfs_NeverNotifyToken = driver_mk_atom("NeverNotifyToken");
  mfs_NotifyToken = driver_mk_atom("NotifyToken");
  mfs_Nx64kToken = driver_mk_atom("Nx64kToken");
  mfs_ObservedEventsToken = driver_mk_atom("ObservedEventsToken");
  mfs_OffToken = driver_mk_atom("OffToken");
  mfs_OnOffToken = driver_mk_atom("OnOffToken");
  mfs_OnToken = driver_mk_atom("OnToken");
  mfs_OnewayToken = driver_mk_atom("OnewayToken");
  mfs_OnewayBothToken = driver_mk_atom("OnewayBothToken");
  mfs_OnewayExternalToken = driver_mk_atom("OnewayExternalToken");
  mfs_OrAUDITselectToken = driver_mk_atom("OrAUDITselectToken");
  mfs_OtherReasonToken = driver_mk_atom("OtherReasonToken");
  mfs_OutOfSvcToken = driver_mk_atom("OutOfSvcToken");
  mfs_PackagesToken = driver_mk_atom("PackagesToken");
  mfs_PendingToken = driver_mk_atom("PendingToken");
  mfs_PriorityToken = driver_mk_atom("PriorityToken");
  mfs_ProfileToken = driver_mk_atom("ProfileToken");
  mfs_QuotedChars = driver_mk_atom("QuotedChars");
  mfs_RBRKT = driver_mk_atom("RBRKT");
  mfs_RSBRKT = driver_mk_atom("RSBRKT");
  mfs_ReasonToken = driver_mk_atom("ReasonToken");
  mfs_RecvonlyToken = driver_mk_atom("RecvonlyToken");
  mfs_RemoteDescriptorToken = driver_mk_atom("RemoteDescriptorToken");
  mfs_RemoteToken = driver_mk_atom("RemoteToken");
  mfs_ReplyToken = driver_mk_atom("ReplyToken");
  mfs_RequestIDToken = driver_mk_atom("RequestIDToken");
  mfs_ReservedGroupToken = driver_mk_atom("ReservedGroupToken");
  mfs_ReservedValueToken = driver_mk_atom("ReservedValueToken");
  mfs_ResetEventsDescriptorToken = driver_mk_atom("ResetEventsDescriptorToken");
  mfs_ResponseAckToken = driver_mk_atom("ResponseAckToken");
  mfs_RestartToken = driver_mk_atom("RestartToken");
  mfs_SEP = driver_mk_atom("SEP");
  mfs_SafeChars = driver_mk_atom("SafeChars");
  mfs_SegmentationCompleteToken = driver_mk_atom("SegmentationCompleteToken");
  mfs_SendonlyToken = driver_mk_atom("SendonlyToken");
  mfs_SendrecvToken = driver_mk_atom("SendrecvToken");
  mfs_ServiceChangeAddressToken = driver_mk_atom("ServiceChangeAddressToken");
  mfs_ServiceChangeIncompleteToken = driver_mk_atom("ServiceChangeIncompleteToken");
  mfs_ServiceChangeToken = driver_mk_atom("ServiceChangeToken");
  mfs_ServiceStatesToken = driver_mk_atom("ServiceStatesToken");
  mfs_ServicesToken = driver_mk_atom("ServicesToken");
  mfs_SignalListToken = driver_mk_atom("SignalListToken");
  mfs_SignalTypeToken = driver_mk_atom("SignalTypeToken");
  mfs_SignalsToken = driver_mk_atom("SignalsToken");
  mfs_StatsToken = driver_mk_atom("StatsToken");
  mfs_StreamToken = driver_mk_atom("StreamToken");
  mfs_SubtractToken = driver_mk_atom("SubtractToken");
  mfs_SynchISDNToken = driver_mk_atom("SynchISDNToken");
  mfs_TerminationStateToken = driver_mk_atom("TerminationStateToken");
  mfs_TestToken = driver_mk_atom("TestToken");
  mfs_TimeOutToken = driver_mk_atom("TimeOutToken");
  mfs_TimeStampToken = driver_mk_atom("TimeStampToken"); /* OTP-5042 */
  mfs_TopologyToken = driver_mk_atom("TopologyToken");
  mfs_TransToken = driver_mk_atom("TransToken");
  mfs_V18Token = driver_mk_atom("V18Token");
  mfs_V22Token = driver_mk_atom("V22Token");
  mfs_V22bisToken = driver_mk_atom("V22bisToken");
  mfs_V32Token = driver_mk_atom("V32Token");
  mfs_V32bisToken = driver_mk_atom("V32bisToken");
  mfs_V34Token = driver_mk_atom("V34Token");
  mfs_V76Token = driver_mk_atom("V76Token");
  mfs_V90Token = driver_mk_atom("V90Token");
  mfs_V91Token = driver_mk_atom("V91Token");
  mfs_VersionToken = driver_mk_atom("VersionToken");
  mfs_asn1_NOVALUE = driver_mk_atom("asn1_NOVALUE");
  mfs_endOfMessage = driver_mk_atom("endOfMessage");
  mfs_PropertyParm = driver_mk_atom("PropertyParm"); 
  mfs_ErrorDescriptor = driver_mk_atom("ErrorDescriptor"); 

  DBG( ("mfs_start -> exit\n") );

  return (ErlDrvData) dataP;
}

static void mfs_stop(ErlDrvData handle)
{
  MfsErlDrvData*  dataP = (MfsErlDrvData*) handle;

  dataP->port = 0;

  DBG( ("mfs_stop -> exit\n") );

  return;
}

static void mfs_command(ErlDrvData handle, 
			char *buf, ErlDrvSizeT buf_len)
{
  driver_failure_atom(((MfsErlDrvData*) handle)->port, "bad_usage");

  return;
}

static ErlDrvSSizeT mfs_control(ErlDrvData          handle,
		       unsigned int        command,
		       char  *buf,     ErlDrvSizeT buf_len, 
		       char **res_buf, ErlDrvSizeT res_buf_len)
{
  MfsErlDrvData*  dataP = (MfsErlDrvData*) handle;
  char*           tmp;
  YY_BUFFER_STATE state;
#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
  yyscan_t        scanner;
  /* struct yyguts_t * yyg = (struct yyguts_t*) scanner; */
#endif
	
  DBG( ("mfs_control -> entry with"
	"\n   command:     %d"
	"\n   buf_len:     %d"
	"\n   res_buf_len: %d\n", command, buf_len, res_buf_len) );

  if (NULL == (tmp = ALLOC(buf_len))) {
    int len;
    mfs_alloc_failed(dataP, "failed allocating text buffer", buf_len);

    len = strlen(dataP->error_msg);

    if (res_buf_len < len) {
      /* 
       * Since we failed the memory allocation in the first place,
       * there is no point in trying to get more memory for the 
       * error code...
       */
      len = res_buf_len;
    }

    strncpy(*res_buf, dataP->error_msg, len);

    return len;
  }
  dataP->text_buf = tmp;
  dataP->text_ptr = tmp;

  dataP->term_spec_size = TERM_SPEC_SIZE_INITIAL(buf_len); 

  DBG( ("mfs_control -> allocate term-spec buffer: "
	"\n   term_spec_size: %d\n", dataP->term_spec_size) );

  dataP->term_spec = ALLOC(dataP->term_spec_size * sizeof(ErlDrvTermData));
  if (NULL == dataP->term_spec) {
    int len;
    mfs_alloc_failed(dataP, "failed allocating term spec buffer", 
		     dataP->term_spec_size * sizeof(ErlDrvTermData));

    len = strlen(dataP->error_msg);

    if (res_buf_len < len) {
      /* 
       * Since we failed the memory allocation in the first place,
       * there is no point in trying to get more memory for the 
       * error code...
       */
      len = res_buf_len;
    }

    strncpy(*res_buf, dataP->error_msg, len);

    FREE(dataP->text_buf);

    return len;    
  }
  dataP->term_spec_index = 0;
  dataP->token_counter   = 0;
  dataP->error           = FALSE;

  /* Prepare the first field in the {tokens, TokenList, LastLine} tuple */
  DBG( ("mfs_control -> prepare the first field in the tokens tuple\n") );
  mfs_ensure_term_spec(dataP, 2);
  ASSIGN_TERM_SPEC(dataP, ERL_DRV_ATOM);
  ASSIGN_TERM_SPEC(dataP, driver_mk_atom("tokens"));

  /* Perform the actual scan */
#if defined(MEGACO_REENTRANT_FLEX_SCANNER)

  /*
   * R e e n t r a n t   s c a n n e r 
   */

  DBG( ("mfs_control -> initiate scanner\n") );
  yylex_init(&scanner);

  DBG( ("mfs_control -> maybe enable flex debug\n") );
  yyset_debug(MFS_FLEX_DEBUG, scanner);

  DBG( ("mfs_control -> set my extra data (ErlDrvData)\n") );
  yyset_extra(dataP, scanner);

  DBG( ("mfs_control -> scan bytes\n") );
  state = yy_scan_bytes(buf, buf_len, scanner);

  DBG( ("mfs_control -> set initial line-no (1) when state is at 0x%x\n", 
        (unsigned int) state) );
  yyset_lineno(1, scanner);

  DBG( ("mfs_control -> do the actual scan\n") );
  yylex(scanner);

#else

  /*
   * N o n  -  R e e n t r a n t   s c a n n e r 
   */

  yylineno = 1;
  state = yy_scan_bytes(buf, buf_len);
  yylex();
  yy_delete_buffer(state);

#endif

  DBG( ("mfs_control -> scan done - now check if ok or not (%d)\n", dataP->error) );
  if (!dataP->error) {

    /* 
     * Prepare the rest of the {tokens, TokenList, LastLine} tuple 
     * and send it as message top caller. 
     */

    DBG( ("mfs_control -> ensure term spec(7)\n") );

    mfs_ensure_term_spec(dataP, 7);
    DBG( ("mfs_control -> assign nil\n") );
    ASSIGN_TERM_SPEC(dataP, ERL_DRV_NIL);
    DBG( ("mfs_control -> assign type list\n") );
    ASSIGN_TERM_SPEC(dataP, ERL_DRV_LIST);
    DBG( ("mfs_control -> assign size of list: %d\n", dataP->token_counter + 1) );
    ASSIGN_TERM_SPEC(dataP, dataP->token_counter + 1);
    DBG( ("mfs_control -> assign type int\n") );
    ASSIGN_TERM_SPEC(dataP, ERL_DRV_INT);
#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
    DBG( ("mfs_control -> assign lineno (or tokenno): %d\n", yyget_lineno(scanner)) );
    // ASSIGN_TERM_SPEC(LINENO_OR_TOKENCNT);
    ASSIGN_TERM_SPEC(dataP, yyget_lineno(scanner));
#else
    DBG( ("mfs_control -> assign lineno (or tokenno): %d\n", LINENO_OR_TOKENCNT(dataP)) );
    // ASSIGN_TERM_SPEC(LINENO_OR_TOKENCNT);
    ASSIGN_TERM_SPEC(dataP, LINENO_OR_TOKENCNT(dataP));
#endif
    // ASSIGN_TERM_SPEC(1);
    DBG( ("mfs_control -> assign tuple\n") );
    ASSIGN_TERM_SPEC(dataP, ERL_DRV_TUPLE);
    DBG( ("mfs_control -> assign size 3\n") );
    ASSIGN_TERM_SPEC(dataP, 3);
    
    DBG( ("mfs_control -> send the term when"
	  "\n   term_spec_index: %d"
	  "\n   term_spec_size:  %d\n", 
	  dataP->term_spec_index, dataP->term_spec_size) );

    erl_drv_send_term(dataP->port_id, 
                      driver_caller(dataP->port),
                      dataP->term_spec, 
                      dataP->term_spec_index);
    
    if (dataP->text_buf  != NULL) FREE(dataP->text_buf);
    if (dataP->term_spec != NULL) FREE(dataP->term_spec);

#if defined(MEGACO_REENTRANT_FLEX_SCANNER)

    /*
     * R e e n t r a n t   s c a n n e r 
     */

    DBG( ("mfs_control -> delete buffer\n") );
    yy_delete_buffer(state, scanner);

    DBG( ("mfs_control -> destroy scanner\n") );
    yylex_destroy(scanner);

#endif

    DBG( ("mfs_control -> done (0)\n") );

    return 0;

  } else {
    /* 
     * Return the error message 
     */
    int len = strlen(dataP->error_msg);

    DBG( ("mfs_control -> return the error message: \n%s\n\n", 
          dataP->error_msg) );

    /*
     * If we fail to alloc a bigger block of memory
     * we have to make do with what we got
     */
    if (res_buf_len < len) {
      void *tmp = ALLOC(len);
      if (tmp != NULL)
	*res_buf = tmp;
      else
	len = res_buf_len;
    }

    strncpy(*res_buf, dataP->error_msg, len);

    if (dataP->text_buf  != NULL) FREE(dataP->text_buf);
    if (dataP->term_spec != NULL) FREE(dataP->term_spec);

#if defined(MEGACO_REENTRANT_FLEX_SCANNER)

    /*
     * R e e n t r a n t   s c a n n e r 
     */

    DBG( ("mfs_control -> delete buffer\n") );
    yy_delete_buffer(state, scanner);

    DBG( ("mfs_control -> destroy scanner\n") );
    yylex_destroy(scanner);

#endif

    DBG( ("mfs_control -> done (%d)\n", len) );

    return len;
  }
}

static void mfs_finish(void)
{
  return;
}

static void mfs_fatal_error(MfsErlDrvData* dataP, char* msg)
{
  if (!dataP->error) {
    int len = strlen(msg);

    if (len >= sizeof(dataP->error_msg))
      len = sizeof(dataP->error_msg) - 1;
      
    strncpy(dataP->error_msg, msg, len);
    dataP->error_msg[len] = '\0';
    dataP->error = TRUE;
  }
}