/*      $NetBSD: scanner.l,v 1.14 2024/09/02 15:33:38 christos Exp $    */

%top {
/* Must come first for _LARGE_FILE_API on AIX. */
#include <config.h>

/*
* Must come first to avoid warnings on Windows.
*
* Flex-generated scanners may only include <inttypes.h> if __STDC_VERSION__
* is defined with a value >= 199901, meaning "full C99", and MSVC may not
* define it with that value, because it isn't 100% C99-compliant, even
* though it has an <inttypes.h> capable of defining everything the Flex
* scanner needs.
*
* We, however, will include it if we know we have an MSVC version that has
* it; this means that we may define the INTn_MAX and UINTn_MAX values in
* scanner.c, and then include <stdint.h>, which may define them differently
* (same value, but different string of characters), causing compiler warnings.
*
* If we include it here, and they're defined, that'll prevent scanner.c
* from defining them.  So we include <pcap/pcap-inttypes.h>, to get
* <inttypes.h> if we have it.
*/
#include <pcap/pcap-inttypes.h>

/*
* grammar.h requires gencode.h and sometimes breaks in a polluted namespace
* (see ftmacros.h), so include it early.
*/
#include "gencode.h"
#include "grammar.h"

#include "diag-control.h"

/*
* Convert string to 32-bit unsigned integer; the string starts at
* string and is string_len bytes long.
*
* On success, sets *val to the value and returns 1.
* On failure, sets the BPF error string and returns 0.
*
* Also used in gencode.c
*/
typedef enum {
       STOULEN_OK,
       STOULEN_NOT_HEX_NUMBER,
       STOULEN_NOT_OCTAL_NUMBER,
       STOULEN_NOT_DECIMAL_NUMBER,
       STOULEN_ERROR
} stoulen_ret;

stoulen_ret stoulen(const char *string, size_t stringlen, bpf_u_int32 *val,
   compiler_state_t *cstate);
}

/*
* We want a reentrant scanner.
*/
%option reentrant

/*
* And we need to pass the compiler state to the scanner.
*/
%option extra-type="compiler_state_t *"

/*
* We don't use input, so don't generate code for it.
*/
%option noinput

/*
* We don't use unput, so don't generate code for it.
*/
%option nounput

/*
* We don't read from the terminal.
*/
%option never-interactive

/*
* We want to stop processing when we get to the end of the input.
*/
%option noyywrap

/*
* We want to generate code that can be used by a reentrant parser
* generated by Bison or Berkeley YACC.
*/
%option bison-bridge

%{
/*
* Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
*      The Regents of the University of California.  All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that: (1) source code distributions
* retain the above copyright notice and this paragraph in its entirety, (2)
* distributions including binary code include the above copyright notice and
* this paragraph in its entirety in the documentation or other materials
* provided with the distribution, and (3) all advertising materials mentioning
* features or use of this software display the following acknowledgement:
* ``This product includes software developed by the University of California,
* Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
* the University nor the names of its contributors may be used to endorse
* or promote products derived from this software without specific prior
* written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: scanner.l,v 1.14 2024/09/02 15:33:38 christos Exp $");

#include <string.h>

#include "pcap-int.h"

/*
* Earlier versions of Flex don't declare these, so we declare them
* ourselves to squelch warnings.
*/
int pcap_get_column(yyscan_t);
void pcap_set_column(int, yyscan_t);

#ifdef INET6

#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
/*
* To quote the MSDN page for getaddrinfo() at
*
*    https://msdn.microsoft.com/en-us/library/windows/desktop/ms738520(v=vs.85).aspx
*
* "Support for getaddrinfo on Windows 2000 and older versions
* The getaddrinfo function was added to the Ws2_32.dll on Windows XP and
* later. To execute an application that uses this function on earlier
* versions of Windows, then you need to include the Ws2tcpip.h and
* Wspiapi.h files. When the Wspiapi.h include file is added, the
* getaddrinfo function is defined to the WspiapiGetAddrInfo inline
* function in the Wspiapi.h file. At runtime, the WspiapiGetAddrInfo
* function is implemented in such a way that if the Ws2_32.dll or the
* Wship6.dll (the file containing getaddrinfo in the IPv6 Technology
* Preview for Windows 2000) does not include getaddrinfo, then a
* version of getaddrinfo is implemented inline based on code in the
* Wspiapi.h header file. This inline code will be used on older Windows
* platforms that do not natively support the getaddrinfo function."
*
* We use getaddrinfo(), so we include Wspiapi.h here.
*/
#include <wspiapi.h>
#else /* _WIN32 */
#include <sys/socket.h> /* for "struct sockaddr" in "struct addrinfo" */
#include <netdb.h>      /* for "struct addrinfo" */
#endif /* _WIN32 */

/* Workaround for AIX 4.3 */
#if !defined(AI_NUMERICHOST)
#define AI_NUMERICHOST 0x04
#endif

#endif /*INET6*/

#include <pcap/namedb.h>
#include "grammar.h"

#ifdef HAVE_OS_PROTO_H
#include "os-proto.h"
#endif

static int stou(const char *, YYSTYPE *, compiler_state_t *);

/*
* Disable diagnostics in the code generated by Flex.
*/
DIAG_OFF_FLEX

%}

N               ([0-9]+|(0X|0x)[0-9A-Fa-f]+)
B               ([0-9A-Fa-f][0-9A-Fa-f]?)
B2              ([0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f])
W               ([0-9A-Fa-f][0-9A-Fa-f]?[0-9A-Fa-f]?[0-9A-Fa-f]?)

%a 18400
%o 21500
%e 7600
%k 4550
%p 27600
%n 2000

V680            {W}:{W}:{W}:{W}:{W}:{W}:{W}:{W}

V670            ::{W}:{W}:{W}:{W}:{W}:{W}:{W}
V671            {W}::{W}:{W}:{W}:{W}:{W}:{W}
V672            {W}:{W}::{W}:{W}:{W}:{W}:{W}
V673            {W}:{W}:{W}::{W}:{W}:{W}:{W}
V674            {W}:{W}:{W}:{W}::{W}:{W}:{W}
V675            {W}:{W}:{W}:{W}:{W}::{W}:{W}
V676            {W}:{W}:{W}:{W}:{W}:{W}::{W}
V677            {W}:{W}:{W}:{W}:{W}:{W}:{W}::

V660            ::{W}:{W}:{W}:{W}:{W}:{W}
V661            {W}::{W}:{W}:{W}:{W}:{W}
V662            {W}:{W}::{W}:{W}:{W}:{W}
V663            {W}:{W}:{W}::{W}:{W}:{W}
V664            {W}:{W}:{W}:{W}::{W}:{W}
V665            {W}:{W}:{W}:{W}:{W}::{W}
V666            {W}:{W}:{W}:{W}:{W}:{W}::

V650            ::{W}:{W}:{W}:{W}:{W}
V651            {W}::{W}:{W}:{W}:{W}
V652            {W}:{W}::{W}:{W}:{W}
V653            {W}:{W}:{W}::{W}:{W}
V654            {W}:{W}:{W}:{W}::{W}
V655            {W}:{W}:{W}:{W}:{W}::

V640            ::{W}:{W}:{W}:{W}
V641            {W}::{W}:{W}:{W}
V642            {W}:{W}::{W}:{W}
V643            {W}:{W}:{W}::{W}
V644            {W}:{W}:{W}:{W}::

V630            ::{W}:{W}:{W}
V631            {W}::{W}:{W}
V632            {W}:{W}::{W}
V633            {W}:{W}:{W}::

V620            ::{W}:{W}
V621            {W}::{W}
V622            {W}:{W}::

V610            ::{W}
V611            {W}::

V600            ::

V6604           {W}:{W}:{W}:{W}:{W}:{W}:{N}\.{N}\.{N}\.{N}

V6504           ::{W}:{W}:{W}:{W}:{W}:{N}\.{N}\.{N}\.{N}
V6514           {W}::{W}:{W}:{W}:{W}:{N}\.{N}\.{N}\.{N}
V6524           {W}:{W}::{W}:{W}:{W}:{N}\.{N}\.{N}\.{N}
V6534           {W}:{W}:{W}::{W}:{W}:{N}\.{N}\.{N}\.{N}
V6544           {W}:{W}:{W}:{W}::{W}:{N}\.{N}\.{N}\.{N}
V6554           {W}:{W}:{W}:{W}:{W}::{N}\.{N}\.{N}\.{N}

V6404           ::{W}:{W}:{W}:{W}:{N}\.{N}\.{N}\.{N}
V6414           {W}::{W}:{W}:{W}:{N}\.{N}\.{N}\.{N}
V6424           {W}:{W}::{W}:{W}:{N}\.{N}\.{N}\.{N}
V6434           {W}:{W}:{W}::{W}:{N}\.{N}\.{N}\.{N}
V6444           {W}:{W}:{W}:{W}::{N}\.{N}\.{N}\.{N}

V6304           ::{W}:{W}:{W}:{N}\.{N}\.{N}\.{N}
V6314           {W}::{W}:{W}:{N}\.{N}\.{N}\.{N}
V6324           {W}:{W}::{W}:{N}\.{N}\.{N}\.{N}
V6334           {W}:{W}:{W}::{N}\.{N}\.{N}\.{N}

V6204           ::{W}:{W}:{N}\.{N}\.{N}\.{N}
V6214           {W}::{W}:{N}\.{N}\.{N}\.{N}
V6224           {W}:{W}::{N}\.{N}\.{N}\.{N}

V6104           ::{W}:{N}\.{N}\.{N}\.{N}
V6114           {W}::{N}\.{N}\.{N}\.{N}

V6004           ::{N}\.{N}\.{N}\.{N}


V6              ({V680}|{V670}|{V671}|{V672}|{V673}|{V674}|{V675}|{V676}|{V677}|{V660}|{V661}|{V662}|{V663}|{V664}|{V665}|{V666}|{V650}|{V651}|{V652}|{V653}|{V654}|{V655}|{V640}|{V641}|{V642}|{V643}|{V644}|{V630}|{V631}|{V632}|{V633}|{V620}|{V621}|{V622}|{V610}|{V611}|{V600}|{V6604}|{V6504}|{V6514}|{V6524}|{V6534}|{V6544}|{V6554}|{V6404}|{V6414}|{V6424}|{V6434}|{V6444}|{V6304}|{V6314}|{V6324}|{V6334}|{V6204}|{V6214}|{V6224}|{V6104}|{V6114}|{V6004})

MAC             ({B}:{B}:{B}:{B}:{B}:{B}|{B}\-{B}\-{B}\-{B}\-{B}\-{B}|{B}\.{B}\.{B}\.{B}\.{B}\.{B}|{B2}\.{B2}\.{B2}|{B2}{3})



%option nounput
%option noinput

%%
dst             return DST;
src             return SRC;

link|ether|ppp|slip  return LINK;
fddi|tr|wlan    return LINK;
arp             return ARP;
rarp            return RARP;
ip              return IP;
sctp            return SCTP;
tcp             return TCP;
udp             return UDP;
icmp            return ICMP;
igmp            return IGMP;
igrp            return IGRP;
pim             return PIM;
vrrp            return VRRP;
carp            return CARP;
radio           return RADIO;

ip6             return IPV6;
icmp6           return ICMPV6;
ah              return AH;
esp             return ESP;

atalk           return ATALK;
aarp            return AARP;
decnet          return DECNET;
lat             return LAT;
sca             return SCA;
moprc           return MOPRC;
mopdl           return MOPDL;

iso             return ISO;
esis            return ESIS;
es-is           return ESIS;
isis            return ISIS;
is-is           return ISIS;
l1              return L1;
l2              return L2;
iih             return IIH;
lsp             return LSP;
snp             return SNP;
csnp            return CSNP;
psnp            return PSNP;

clnp            return CLNP;

stp             return STP;

ipx             return IPX;

netbeui         return NETBEUI;

host            return HOST;
net             return NET;
mask            return NETMASK;
port            return PORT;
portrange       return PORTRANGE;
proto           return PROTO;
protochain      return PROTOCHAIN;

gateway         return GATEWAY;

type            return TYPE;
subtype         return SUBTYPE;
direction|dir   return DIR;
address1|addr1  return ADDR1;
address2|addr2  return ADDR2;
address3|addr3  return ADDR3;
address4|addr4  return ADDR4;
ra              return RA;
ta              return TA;

less            return LESS;
greater         return GREATER;
byte            return CBYTE;
broadcast       return TK_BROADCAST;
multicast       return TK_MULTICAST;

and|"&&"        return AND;
or|"||"         return OR;
not             return '!';

len|length      return LEN;
inbound         return INBOUND;
outbound        return OUTBOUND;

ifindex         return IFINDEX;

vlan            return VLAN;
mpls            return MPLS;
pppoed          return PPPOED;
pppoes          return PPPOES;
geneve          return GENEVE;

lane            return LANE;
llc             return LLC;
metac           return METAC;
bcc             return BCC;
oam             return OAM;
oamf4           return OAMF4;
oamf4ec         return OAMF4EC;
oamf4sc         return OAMF4SC;
sc              return SC;
ilmic           return ILMIC;
vpi             return VPI;
vci             return VCI;
connectmsg      return CONNECTMSG;
metaconnect     return METACONNECT;

on|ifname       return PF_IFNAME;
rset|ruleset    return PF_RSET;
rnr|rulenum     return PF_RNR;
srnr|subrulenum return PF_SRNR;
reason          return PF_REASON;
action          return PF_ACTION;

fisu            return FISU;
lssu            return LSSU;
lsu             return LSSU;
msu             return MSU;
hfisu           return HFISU;
hlssu           return HLSSU;
hmsu            return HMSU;
sio             return SIO;
opc             return OPC;
dpc             return DPC;
sls             return SLS;
hsio            return HSIO;
hopc            return HOPC;
hdpc            return HDPC;
hsls            return HSLS;

[ \r\n\t]               ;
[+\-*/%:\[\]!<>()&|\^=] return yytext[0];
">="                    return GEQ;
"<="                    return LEQ;
"!="                    return NEQ;
"=="                    return '=';
"<<"                    return LSH;
">>"                    return RSH;
${B}                    { yylval->s = sdup(yyextra, yytext); return AID; }
{MAC}                   { yylval->s = sdup(yyextra, yytext); return EID; }
{N}                     { return stou(yytext, yylval, yyextra); }
({N}\.{N})|({N}\.{N}\.{N})|({N}\.{N}\.{N}\.{N}) {
                       yylval->s = sdup(yyextra, (char *)yytext); return HID; }
{V6}                    {
#ifdef INET6
                         struct addrinfo hints, *res;
                         memset(&hints, 0, sizeof(hints));
                         hints.ai_family = AF_INET6;
                         hints.ai_flags = AI_NUMERICHOST;
                         if (getaddrinfo(yytext, NULL, &hints, &res)) {
                               bpf_set_error(yyextra, "bogus IPv6 address %s", yytext);
                               yylval->s = NULL;
                         } else {
                               freeaddrinfo(res);
                               yylval->s = sdup(yyextra, (char *)yytext);
                         }
#else
                         bpf_set_error(yyextra, "IPv6 address %s not supported", yytext);
                         yylval->s = NULL;
#endif /*INET6*/
                         return HID6;
                       }
{B}:+({B}:+)+           { bpf_set_error(yyextra, "bogus ethernet address %s", yytext); yylval->s = NULL; return EID; }
icmptype                { yylval->h = 0; return NUM; }
icmpcode                { yylval->h = 1; return NUM; }
icmp-echoreply          { yylval->h = 0; return NUM; }
icmp-unreach            { yylval->h = 3; return NUM; }
icmp-sourcequench       { yylval->h = 4; return NUM; }
icmp-redirect           { yylval->h = 5; return NUM; }
icmp-echo               { yylval->h = 8; return NUM; }
icmp-routeradvert       { yylval->h = 9; return NUM; }
icmp-routersolicit      { yylval->h = 10; return NUM; }
icmp-timxceed           { yylval->h = 11; return NUM; }
icmp-paramprob          { yylval->h = 12; return NUM; }
icmp-tstamp             { yylval->h = 13; return NUM; }
icmp-tstampreply        { yylval->h = 14; return NUM; }
icmp-ireq               { yylval->h = 15; return NUM; }
icmp-ireqreply          { yylval->h = 16; return NUM; }
icmp-maskreq            { yylval->h = 17; return NUM; }
icmp-maskreply          { yylval->h = 18; return NUM; }

icmp6type       { yylval->h = 0; return NUM; }
icmp6code       { yylval->h = 1; return NUM; }

icmp6-destinationunreach        { yylval->h = 1; return NUM; }
icmp6-packettoobig              { yylval->h = 2; return NUM; }
icmp6-timeexceeded              { yylval->h = 3; return NUM; }
icmp6-parameterproblem          { yylval->h = 4; return NUM; }
icmp6-echo      { yylval->h = 128; return NUM; }
icmp6-echoreply { yylval->h = 129; return NUM; }
icmp6-multicastlistenerquery    { yylval->h = 130; return NUM; }
icmp6-multicastlistenerreportv1 { yylval->h = 131; return NUM; }
icmp6-multicastlistenerdone     { yylval->h = 132; return NUM; }
icmp6-routersolicit   { yylval->h = 133; return NUM; }
icmp6-routeradvert    { yylval->h = 134; return NUM; }
icmp6-neighborsolicit { yylval->h = 135; return NUM; }
icmp6-neighboradvert  { yylval->h = 136; return NUM; }
icmp6-redirect    { yylval->h = 137; return NUM; }
icmp6-routerrenum { yylval->h = 138; return NUM; }
icmp6-nodeinformationquery      { yylval->h = 139; return NUM; }
icmp6-nodeinformationresponse   { yylval->h = 140; return NUM; }
icmp6-ineighbordiscoverysolicit { yylval->h = 141; return NUM; }
icmp6-ineighbordiscoveryadvert  { yylval->h = 142; return NUM; }
icmp6-multicastlistenerreportv2 { yylval->h = 143; return NUM; }
icmp6-homeagentdiscoveryrequest { yylval->h = 144; return NUM; }
icmp6-homeagentdiscoveryreply   { yylval->h = 145; return NUM; }
icmp6-mobileprefixsolicit       { yylval->h = 146; return NUM; }
icmp6-mobileprefixadvert        { yylval->h = 147; return NUM; }
icmp6-certpathsolicit           { yylval->h = 148; return NUM; }
icmp6-certpathadvert            { yylval->h = 149; return NUM; }
icmp6-multicastrouteradvert     { yylval->h = 151; return NUM; }
icmp6-multicastroutersolicit    { yylval->h = 152; return NUM; }
icmp6-multicastrouterterm       { yylval->h = 153; return NUM; }

tcpflags                { yylval->h = 13; return NUM; }
tcp-fin                 { yylval->h = 0x01; return NUM; }
tcp-syn                 { yylval->h = 0x02; return NUM; }
tcp-rst                 { yylval->h = 0x04; return NUM; }
tcp-push                { yylval->h = 0x08; return NUM; }
tcp-ack                 { yylval->h = 0x10; return NUM; }
tcp-urg                 { yylval->h = 0x20; return NUM; }
tcp-ece                 { yylval->h = 0x40; return NUM; }
tcp-cwr                 { yylval->h = 0x80; return NUM; }
[A-Za-z0-9]([-_.A-Za-z0-9]*[.A-Za-z0-9])? {
                        yylval->s = sdup(yyextra, (char *)yytext); return ID; }
"\\"[^ !()\n\t]+        { yylval->s = sdup(yyextra, (char *)yytext + 1); return ID; }
                       { return LEX_ERROR; }
%%

/*
* Turn diagnostics back on, so we check the code that we've written.
*/
DIAG_ON_FLEX

stoulen_ret
stoulen(const char *string, size_t string_len, bpf_u_int32 *val,
   compiler_state_t *cstate)
{
       bpf_u_int32 n = 0;
       unsigned int digit;
       const char *s = string;

       /*
        * string is guaranteed either to be a string of decimal digits
        * or 0[xX] followed by a string of hex digits.
        */
       if (string_len >= 1 && *s == '0') {
               if (string_len >= 2  && (s[1] == 'x' || s[1] == 'X')) {
                       /*
                        * Begins with 0x or 0X, so hex.
                        * Guaranteed to be all hex digits following the
                        * prefix, so anything that's not 0-9 or a-f is
                        * A-F.
                        */
                       s += 2; /* skip the prefix */
                       string_len -= 2;
                       while (string_len != 0) {
                               digit = *s++;
                               string_len--;
                               if (digit >= '0' && digit <= '9')
                                       digit = digit - '0';
                               else if (digit >= 'a' && digit <= 'f')
                                       digit = digit - 'a' + 10;
                               else if (digit >= 'A' && digit <= 'F')
                                       digit = digit - 'A' + 10;
                               else {
                                       /*
                                        * Not a valid hex number.
                                        * Don't treat this as an error,
                                        * in case the caller wants to
                                        * interpret it as something else.
                                        */
                                       return STOULEN_NOT_HEX_NUMBER;
                               }

                               /*
                                * Check for overflow.
                                */
                               if (n > 0xFFFFFFFU) {
                                       /*
                                        * We have more than 28 bits of
                                        * number, and are about to
                                        * add 4 more; that won't fit
                                        * in 32 bits.
                                        */
                                       bpf_set_error(cstate,
                                           "number %.*s overflows 32 bits",
                                          (int)string_len, string);
                                       return STOULEN_ERROR;
                               }
                               n = (n << 4) + digit;
                       }
               } else {
                       /*
                        * Begins with 0, but not 0x or 0X, so octal.
                        * Guaranteed to be all *decimal* digits following
                        * the prefix, so we need to catch 8 and 9 and
                        * report an error.
                        */
                       s += 1;
                       string_len -= 1;
                       while (string_len != 0) {
                               digit = *s++;
                               string_len--;
                               if (digit >= '0' && digit <= '7')
                                       digit = digit - '0';
                               else {
                                       /*
                                        * Not a valid octal number.
                                        * Don't treat this as an error,
                                        * in case the caller wants to
                                        * interpret it as something else.
                                        */
                                       return STOULEN_NOT_OCTAL_NUMBER;
                               }
                               if (n > 03777777777U) {
                                       /*
                                        * We have more than 29 bits of
                                        * number, and are about to add
                                        * 3 more; that won't fit in
                                        * 32 bits.
                                        */
                                       bpf_set_error(cstate,
                                           "number %.*s overflows 32 bits",
                                          (int)string_len, string);
                                       return STOULEN_ERROR;
                               }
                               n = (n << 3) + digit;
                       }
               }
       } else {
               /*
                * Decimal.
                */
               while (string_len != 0) {
                       digit = *s++;
                       string_len--;
                       if (digit >= '0' && digit <= '9')
                               digit = digit - '0';
                       else {
                               /*
                                * Not a valid decimal number.
                                * Don't treat this as an error,
                                * in case the caller wants to
                                * interpret it as something else.
                                */
                               return STOULEN_NOT_DECIMAL_NUMBER;
                       }
#define CUTOFF_DEC      (0xFFFFFFFFU / 10U)
#define CUTLIM_DEC      (0xFFFFFFFFU % 10U)
                       if (n > CUTOFF_DEC ||
                           (n == CUTOFF_DEC && digit > CUTLIM_DEC)) {
                               /*
                                * Adding that digit will result in a
                                * number that won't fit in 32 bits.
                                */
                               bpf_set_error(cstate,
                                   "number %.*s overflows 32 bits",
                                  (int)string_len, string);
                               return STOULEN_ERROR;
                       }
                       n = (n * 10) + digit;
               }
       }

       *val = n;
       return STOULEN_OK;
}

/*
* Convert string to 32-bit unsigned integer.  Just like atoi(), but checks for
* preceding 0x or 0 and uses hex or octal instead of decimal.
*
* On success, sets yylval->h to the value and returns NUM.
* On failure, sets the BPF error string and returns LEX_ERROR, to force
* the parse to stop.
*/
static int
stou(const char *yytext_arg, YYSTYPE *yylval_arg, compiler_state_t *yyextra_arg)
{
       stoulen_ret ret;

       ret = stoulen(yytext_arg, strlen(yytext_arg), &yylval_arg->h,
           yyextra_arg);
       switch (ret) {

       case STOULEN_OK:
               return NUM;

       case STOULEN_NOT_OCTAL_NUMBER:
               bpf_set_error(yyextra_arg, "number %s contains non-octal digit",
                   yytext_arg);
               return LEX_ERROR;

       case STOULEN_NOT_HEX_NUMBER:
               bpf_set_error(yyextra_arg, "number %s contains non-hex digit",
                   yytext_arg);
               return LEX_ERROR;

       case STOULEN_NOT_DECIMAL_NUMBER:
               bpf_set_error(yyextra_arg, "number %s contains non-decimal digit",
                   yytext_arg);
               return LEX_ERROR;

       case STOULEN_ERROR:
               /* Error already set. */
               return LEX_ERROR;

       default:
               /* Should not happen */
               bpf_set_error(yyextra_arg, "stoulen returned %d - this should not happen", ret);
               return LEX_ERROR;
       }
}