VirtualBox

Changeset 108284 in vbox


Ignore:
Timestamp:
Feb 19, 2025 10:50:10 AM (2 months ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
167627
Message:

libs/xpcom18a4/xpidl-new: Start with parsing IDL files, bugref:10321

Location:
trunk/src/libs/xpcom18a4/xpcom/typelib/xpidl-new
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/libs/xpcom18a4/xpcom/typelib/xpidl-new/xpidl.c

    r108268 r108284  
    4545static ModeData modes[] = {
    4646    {"header",  "Generate C++ header",         "h",    xpidl_header_dispatch},
    47     {"typelib", "Generate XPConnect typelib",  "xpt",  xpidl_typelib_dispatch},
     47/*    {"typelib", "Generate XPConnect typelib",  "xpt",  xpidl_typelib_dispatch},*/
    4848    {0,         0,                             0,      0}
    4949};
     
    6060}
    6161
    62 gboolean enable_debug               = FALSE;
    63 gboolean enable_warnings            = FALSE;
    64 gboolean verbose_mode               = FALSE;
    65 gboolean emit_typelib_annotations   = FALSE;
    66 gboolean explicit_output_filename   = FALSE;
     62bool enable_debug               = false;
     63bool enable_warnings            = false;
     64bool verbose_mode               = false;
     65bool emit_typelib_annotations   = false;
     66bool explicit_output_filename   = false;
    6767
    6868/* The following globals are explained in xpt_struct.h */
     
    9898
    9999    int i;
    100     IncludePathEntry *inc, *inc_head, **inc_tail;
     100    RTLISTANCHOR LstIncludePaths;
    101101    char *file_basename = NULL;
    102102    ModeData *mode = NULL;
    103     gboolean create_old_typelib = FALSE;
    104 
    105     /* turn this on for extra checking of our code */
    106 /*    IDL_check_cast_enable(TRUE); */
    107 
    108     inc_head = xpidl_malloc(sizeof *inc);
    109     inc_head->directory = ".";
    110     inc_head->next = NULL;
    111     inc_tail = &inc_head->next;
     103
     104    RTListInit(&LstIncludePaths);
     105
     106    PXPIDLINCLUDEDIR pInc = (PXPIDLINCLUDEDIR)xpidl_malloc(sizeof(*pInc));
     107    pInc->pszPath = ".";
     108    RTListAppend(&LstIncludePaths, &pInc->NdIncludes);
    112109
    113110    for (i = 1; i < argc; i++) {
     
    121118            goto done_options;
    122119          case 'a':
    123             emit_typelib_annotations = TRUE;
     120            emit_typelib_annotations = true;
    124121            break;
    125122          case 'w':
    126             enable_warnings = TRUE;
     123            enable_warnings = true;
    127124            break;
    128125          case 'v':
    129             verbose_mode = TRUE;
     126            verbose_mode = true;
    130127            break;
    131128          case 't':
     
    141138            if (i + 1 == argc) {
    142139                fprintf(stderr, "ERROR: missing version number after -t\n");
    143                 xpidl_usage(argc, argv);
    144                 return 1;
    145             }
    146 
    147             /* Do not allow more than one "-t" definition */
    148             if (create_old_typelib) {
    149                 fprintf(stderr,
    150                         "ERROR: -t argument used twice. "
    151                         "Cannot specify more than one version\n");
    152140                xpidl_usage(argc, argv);
    153141                return 1;
     
    164152                break;
    165153              case XPT_VERSION_OLD:
    166                 create_old_typelib = TRUE;
    167                 break;
    168154              case XPT_VERSION_UNSUPPORTED:
    169155                fprintf(stderr, "ERROR: version \"%s\" not supported.\n",
     
    186172                return 1;
    187173            }
    188             inc = xpidl_malloc(sizeof *inc);
     174            pInc = (PXPIDLINCLUDEDIR)xpidl_malloc(sizeof(*pInc));
    189175            if (argv[i][2] == '\0') {
    190176                /* is it the -I foo form? */
    191                 inc->directory = argv[++i];
     177                pInc->pszPath = argv[++i];
    192178            } else {
    193179                /* must be the -Ifoo form.  Don't preincrement i. */
    194                 inc->directory = argv[i] + 2;
    195             }
    196 #ifdef DEBUG_shaver_includes
    197             fprintf(stderr, "adding %s to include path\n", inc->directory);
    198 #endif
    199             inc->next = NULL;
    200             *inc_tail = inc;
    201             inc_tail = &inc->next;
     180                pInc->pszPath = argv[i] + 2;
     181            }
     182
     183            RTListAppend(&LstIncludePaths, &pInc->NdIncludes);
    202184            break;
    203185          case 'o':
     
    208190            }
    209191            file_basename = argv[++i];
    210             explicit_output_filename = FALSE;
     192            explicit_output_filename = false;
    211193            break;
    212194          case 'e':
     
    217199            }
    218200            file_basename = argv[++i];
    219             explicit_output_filename = TRUE;
     201            explicit_output_filename = true;
    220202            break;
    221203          case 'm':
     
    260242     * multiply.
    261243     */
    262     if (xpidl_process_idl(argv[i], inc_head, file_basename, mode))
     244    if (xpidl_process_idl(argv[i], &LstIncludePaths, file_basename, mode))
    263245        return 0;
     246
     247    /** @todo Free include paths. */
    264248
    265249    return 1;
  • trunk/src/libs/xpcom18a4/xpcom/typelib/xpidl-new/xpidl.h

    r108268 r108284  
    4343#define __xpidl_h
    4444
     45#include <iprt/errcore.h>
     46#include <iprt/list.h>
     47#include <iprt/script.h>
     48
    4549#include <errno.h>
    4650#include <stddef.h>
    4751#include <stdio.h>
    4852#include <stdlib.h>
    49 #include <glib.h>
    50 #include <string.h> /* After glib.h to avoid warnings about shadowing 'index'. */
    51 
    52 #ifndef XP_MAC
    53 #include <libIDL/IDL.h>
    54 #else
    55 #include <IDL.h>
    56 #endif
     53#include <string.h>
    5754
    5855#include <xpt_struct.h>
    5956
    60 #define XPIDL_WARNING(x) IDL_tree_warning x
     57
     58/**
     59 * An include path.
     60 */
     61typedef struct XPIDLINCLUDEDIR
     62{
     63    /** Node for the list of include paths. */
     64    RTLISTNODE          NdIncludes;
     65    /** The zero terminated include path. */
     66    const char          *pszPath;
     67} XPIDLINCLUDEDIR;
     68/** Pointer to an include path. */
     69typedef XPIDLINCLUDEDIR *PXPIDLINCLUDEDIR;
     70/** Pointer to a const include path. */
     71typedef const XPIDLINCLUDEDIR *PCXPIDLINCLUDEDIR;
     72
     73
     74/**
     75 * The input stream.
     76 */
     77typedef struct XPIDLINPUT
     78{
     79    /** Node for the list of inputs. */
     80    RTLISTNODE          NdInput;
     81    /** The list of includes this input generated. */
     82    RTLISTANCHOR        LstIncludes;
     83    /** The basename for this input. */
     84    char                *pszBasename;
     85    /** The filename for this input. */
     86    char                *pszFilename;
     87    /** The lexer instance for this input. */
     88    RTSCRIPTLEX         hIdlLex;
     89} XPIDLINPUT;
     90/** Pointer to an input stream. */
     91typedef XPIDLINPUT *PXPIDLINPUT;
     92/** Pointer to a const input stream. */
     93typedef const XPIDLINPUT *PCXPIDLINPUT;
     94
     95
     96/**
     97 * IDL node type.
     98 */
     99typedef enum XPIDLNDTYPE
     100{
     101    kXpidlNdType_Invalid = 0,
     102    kXpidlNdType_RawBlock,
     103    kXpidlNdType_Typedef,
     104    kXpidlNdType_Native,
     105    kXpidlNdType_Interface,
     106    kXpidlNdType_Forward_Decl
     107} XPIDLNDTYPE;
     108
     109
     110/**
     111 * A node attribute.
     112 */
     113typedef struct XPIDLATTR
     114{
     115    /** The attribute name. */
     116    const char          *pszName;
     117    /** The value assigned if any. */
     118    const char          *pszVal;
     119} XPIDLATTR;
     120/** Pointer to an attribute. */
     121typedef XPIDLATTR *PXPIDLATTR;
     122/** Pointer to a const attribute. */
     123typedef const XPIDLATTR *PCXPIDLATTR;
     124
     125
     126/** Pointer to an IDL node. */
     127typedef struct XPIDLNODE *PXPIDLNODE;
     128/** Pointer to a const IDL node. */
     129typedef const struct XPIDLNODE *PCXPIDLNODE;
     130
     131/**
     132 * IDL node.
     133 */
     134typedef struct XPIDLNODE
     135{
     136    /** Node for the list this node is in. */
     137    RTLISTNODE          NdLst;
     138    /** The parent node (if any). */
     139    PCXPIDLNODE         pParent;
     140    /** The input stream this node was generated from (via #include's). */
     141    PCXPIDLINPUT        pInput;
     142    /** The node type. */
     143    XPIDLNDTYPE         enmType;
     144    /** Node type dependent data. */
     145    union
     146    {
     147        struct
     148        {
     149            const char *pszRaw;
     150            size_t     cchRaw;
     151        } RawBlock;
     152    } u;
     153} XPIDLNODE;
     154
     155
     156/**
     157 * The IDL parsing state.
     158 */
     159typedef struct XPIDLPARSE
     160{
     161    /** List of input files. */
     162    RTLISTANCHOR        LstInputs;
     163    /** The list of XPIDL nodes from the root. */
     164    RTLISTANCHOR        LstNodes;
     165    /** Extended error info. */
     166    RTERRINFOSTATIC     ErrInfo;
     167} XPIDLPARSE;
     168/** Pointer to an IDL parsing state. */
     169typedef XPIDLPARSE *PXPIDLPARSE;
     170/** Pointer to a const IDL parsing state. */
     171typedef const XPIDLPARSE *PCXPIDLPARSE;
     172
    61173
    62174/*
    63175 * Internal operation flags.
    64176 */
    65 extern gboolean enable_debug;
    66 extern gboolean enable_warnings;
    67 extern gboolean verbose_mode;
    68 extern gboolean emit_typelib_annotations;
    69 extern gboolean explicit_output_filename;
     177extern bool enable_debug;
     178extern bool enable_warnings;
     179extern bool verbose_mode;
     180extern bool emit_typelib_annotations;
     181extern bool explicit_output_filename;
    70182
    71183extern PRUint8  major_version;
     
    77189 * A function to handle an IDL_tree type.
    78190 */
    79 typedef gboolean (*nodeHandler)(TreeState *);
     191typedef bool (*nodeHandler)(TreeState *);
    80192
    81193/*
     
    93205extern backend *xpidl_header_dispatch(void);
    94206extern backend *xpidl_typelib_dispatch(void);
    95 extern backend *xpidl_doc_dispatch(void);
    96 extern backend *xpidl_java_dispatch(void);
    97207
    98208typedef struct ModeData {
     
    103213} ModeData;
    104214
    105 typedef struct IncludePathEntry {
    106     char                    *directory;
    107     struct IncludePathEntry *next;
    108 } IncludePathEntry;
    109215
    110216struct TreeState {
     
    112218    /* Maybe supplied by -o. Not related to (g_)basename from string.h or glib */
    113219    char             *basename;
    114     IDL_ns           ns;
    115     IDL_tree         tree;
    116     GSList           *base_includes;
     220    RTLISTANCHOR     *base_includes;
    117221    nodeHandler      *dispatch;
    118222    void             *priv;     /* mode-private data */
     
    124228 */
    125229int
    126 xpidl_process_idl(char *filename, IncludePathEntry *include_path,
     230xpidl_process_idl(char *filename, PRTLISTANCHOR pLstIncludePaths,
    127231                  char *file_basename, ModeData *mode);
    128 
    129 /*
    130  * Iterate over an IDLN_LIST -- why is this not part of libIDL?
    131  */
    132 void
    133 xpidl_list_foreach(IDL_tree p, IDL_tree_func foreach, gpointer user_data);
    134232
    135233/*
     
    152250 * Process an XPIDL node and its kids, if any.
    153251 */
    154 gboolean
     252bool
    155253xpidl_process_node(TreeState *state);
    156254
     
    177275 * UUID_LENGTH bytes.
    178276 */
    179 gboolean
     277bool
    180278xpidl_sprint_iid(nsID *iid, char iidbuf[]);
    181279
     
    184282 * so we re-implement nsID::Parse here.
    185283 */
    186 gboolean
     284bool
    187285xpidl_parse_iid(nsID *id, const char *str);
    188286
    189287
     288#if 0
    190289/* Try to common a little node-handling stuff. */
    191290
     
    253352void
    254353printlist(FILE *outfile, GSList *slist);
     354#endif
    255355
    256356#endif /* __xpidl_h */
  • trunk/src/libs/xpcom18a4/xpcom/typelib/xpidl-new/xpidl_header.c

    r108268 r108284  
    4747#define AS_IMPL 2
    4848
    49 static gboolean write_method_signature(IDL_tree method_tree, FILE *outfile,
     49#if 0
     50static bool write_method_signature(IDL_tree method_tree, FILE *outfile,
    5051                                       int mode, const char *className);
    51 static gboolean write_attr_accessor(IDL_tree attr_tree, FILE * outfile,
    52                                     gboolean getter,
     52static bool write_attr_accessor(IDL_tree attr_tree, FILE * outfile,
     53                                    bool getter,
    5354                                    int mode, const char *className);
    5455
     
    5859}
    5960
    60 static gboolean
     61static bool
    6162header_prolog(TreeState *state)
    6263{
     
    115116}
    116117
    117 static gboolean
     118static bool
    118119header_epilog(TreeState *state)
    119120{
     
    140141}
    141142
    142 static gboolean
     143static bool
    143144interface(TreeState *state)
    144145{
     
    147148    char *classNameUpper = NULL;
    148149    char *cp;
    149     gboolean ok = TRUE;
    150     gboolean keepvtable;
     150    bool ok = TRUE;
     151    bool keepvtable;
    151152    const char *iid;
    152153    const char *name_space;
     
    488489}
    489490
    490 static gboolean
     491static bool
    491492list(TreeState *state)
    492493{
     
    500501}
    501502
    502 static gboolean
    503 write_type(IDL_tree type_tree, gboolean is_out, FILE *outfile)
     503static bool
     504write_type(IDL_tree type_tree, bool is_out, FILE *outfile)
    504505{
    505506    if (!type_tree) {
     
    510511    switch (IDL_NODE_TYPE(type_tree)) {
    511512      case IDLN_TYPE_INTEGER: {
    512         gboolean sign = IDL_TYPE_INTEGER(type_tree).f_signed;
     513        bool sign = IDL_TYPE_INTEGER(type_tree).f_signed;
    513514        switch (IDL_TYPE_INTEGER(type_tree).f_type) {
    514515          case IDL_INTEGER_TYPE_SHORT:
     
    610611 *  AS_CALL writes 'foo(bar, sil)'
    611612 */
    612 static gboolean
     613static bool
    613614write_attr_accessor(IDL_tree attr_tree, FILE * outfile,
    614                     gboolean getter, int mode, const char *className)
     615                    bool getter, int mode, const char *className)
    615616{
    616617    char *attrname = ATTR_IDENT(attr_tree).str;
     
    650651}
    651652
    652 static gboolean
     653static bool
    653654attr_dcl(TreeState *state)
    654655{
     
    696697}
    697698
    698 static gboolean
     699static bool
    699700do_enum(TreeState *state)
    700701{
     
    704705}
    705706
    706 static gboolean
     707static bool
    707708do_const_dcl(TreeState *state)
    708709{
    709710    struct _IDL_CONST_DCL *dcl = &IDL_CONST_DCL(state->tree);
    710711    const char *name = IDL_IDENT(dcl->ident).str;
    711     gboolean is_signed;
     712    bool is_signed;
    712713    GSList *doc_comments = IDL_IDENT(dcl->ident).comments;
    713714    IDL_tree real_type;
     
    736737}
    737738
    738 static gboolean
     739static bool
    739740do_typedef(TreeState *state)
    740741{
     
    795796
    796797/* If notype is true, just write the param name. */
    797 static gboolean
     798static bool
    798799write_param(IDL_tree param_tree, FILE *outfile)
    799800{
    800801    IDL_tree param_type_spec = IDL_PARAM_DCL(param_tree).param_type_spec;
    801     gboolean is_in = IDL_PARAM_DCL(param_tree).attr == IDL_PARAM_IN;
     802    bool is_in = IDL_PARAM_DCL(param_tree).attr == IDL_PARAM_IN;
    802803    /* in string, wstring, nsid, domstring, utf8string, cstring and
    803804     * astring any explicitly marked [const] are const
     
    850851 * A forward declaration, usually an interface.
    851852 */
    852 static gboolean
     853static bool
    853854forward_dcl(TreeState *state)
    854855{
     
    871872 *  AS_CALL writes 'foo(bar, sil)'
    872873 */
    873 static gboolean
     874static bool
    874875write_method_signature(IDL_tree method_tree, FILE *outfile, int mode,
    875876                       const char *className)
    876877{
    877878    struct _IDL_OP_DCL *op = &IDL_OP_DCL(method_tree);
    878     gboolean no_generated_args = TRUE;
    879     gboolean op_notxpcom =
     879    bool no_generated_args = TRUE;
     880    bool op_notxpcom =
    880881        (IDL_tree_property_get(op->ident, "notxpcom") != NULL);
    881882    const char *name;
     
    969970 * I blame Elliot.
    970971 */
    971 static gboolean
     972static bool
    972973op_dcl(TreeState *state)
    973974{
     
    10041005}
    10051006
    1006 static gboolean
     1007static bool
    10071008codefrag(TreeState *state)
    10081009{
     
    10301031    return TRUE;
    10311032}
     1033#endif
    10321034
    10331035backend *
     
    10351037{
    10361038    static backend result;
    1037     static nodeHandler table[IDLN_LAST];
    1038     static gboolean initialized = FALSE;
     1039    static nodeHandler table[10 /*IDLN_LAST*/];
     1040    static bool initialized = false;
    10391041   
    1040     result.emit_prolog = header_prolog;
    1041     result.emit_epilog = header_epilog;
    1042 
     1042    result.emit_prolog = NULL; //header_prolog;
     1043    result.emit_epilog = NULL; //header_epilog;
     1044
     1045#if 0
    10431046    if (!initialized) {
    1044         table[IDLN_LIST] = list;
    1045         table[IDLN_ATTR_DCL] = attr_dcl;
    1046         table[IDLN_OP_DCL] = op_dcl;
    1047         table[IDLN_FORWARD_DCL] = forward_dcl;
    1048         table[IDLN_TYPE_ENUM] = do_enum;
    1049         table[IDLN_INTERFACE] = interface;
    1050         table[IDLN_CODEFRAG] = codefrag;
    1051         table[IDLN_TYPE_DCL] = do_typedef;
    1052         table[IDLN_CONST_DCL] = do_const_dcl;
    1053         table[IDLN_NATIVE] = check_native;
    1054         initialized = TRUE;
    1055     }
     1047        table[IDLN_LIST] = NULL; //list;
     1048        table[IDLN_ATTR_DCL] = NULL; //attr_dcl;
     1049        table[IDLN_OP_DCL] = NULL; //op_dcl;
     1050        table[IDLN_FORWARD_DCL] = NULL; //forward_dcl;
     1051        table[IDLN_TYPE_ENUM] = NULL; //do_enum;
     1052        table[IDLN_INTERFACE] = NULL; //interface;
     1053        table[IDLN_CODEFRAG] = NULL; //codefrag;
     1054        table[IDLN_TYPE_DCL] = NULL; //do_typedef;
     1055        table[IDLN_CONST_DCL] = NULL; //do_const_dcl;
     1056        table[IDLN_NATIVE]    = NULL; //check_native;
     1057        initialized = true;
     1058    }
     1059#endif
    10561060
    10571061    result.dispatch_table = table;
  • trunk/src/libs/xpcom18a4/xpcom/typelib/xpidl-new/xpidl_idl.c

    r108268 r108284  
    1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
    2 /* ***** BEGIN LICENSE BLOCK *****
    3  * Version: NPL 1.1/GPL 2.0/LGPL 2.1
    4  *
    5  * The contents of this file are subject to the Netscape Public License
    6  * Version 1.1 (the "License"); you may not use this file except in
    7  * compliance with the License. You may obtain a copy of the License at
    8  * http://www.mozilla.org/NPL/
    9  *
    10  * Software distributed under the License is distributed on an "AS IS" basis,
    11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
    12  * for the specific language governing rights and limitations under the
     1/* $Id$ */
     2/** @file
     3 * VBox xpidl clone - IDL parsing.
     4 */
     5
     6/*
     7 * Copyright (C) 2025 Oracle and/or its affiliates.
     8 *
     9 * This file is part of VirtualBox base platform packages, as
     10 * available from https://www.virtualbox.org.
     11 *
     12 * This program is free software; you can redistribute it and/or
     13 * modify it under the terms of the GNU General Public License
     14 * as published by the Free Software Foundation, in version 3 of the
    1315 * License.
    1416 *
    15  * The Original Code is mozilla.org code.
    16  *
    17  * The Initial Developer of the Original Code is
    18  * Netscape Communications Corporation.
    19  * Portions created by the Initial Developer are Copyright (C) 1998
    20  * the Initial Developer. All Rights Reserved.
    21  *
    22  * Contributor(s):
    23  *       Michael Ang <[email protected]>
    24  *
    25  * Alternatively, the contents of this file may be used under the terms of
    26  * either the GNU General Public License Version 2 or later (the "GPL"), or
    27  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
    28  * in which case the provisions of the GPL or the LGPL are applicable instead
    29  * of those above. If you wish to allow use of your version of this file only
    30  * under the terms of either the GPL or the LGPL, and not to allow others to
    31  * use your version of this file under the terms of the NPL, indicate your
    32  * decision by deleting the provisions above and replace them with the notice
    33  * and other provisions required by the GPL or the LGPL. If you do not delete
    34  * the provisions above, a recipient may use your version of this file under
    35  * the terms of any one of the NPL, the GPL or the LGPL.
    36  *
    37  * ***** END LICENSE BLOCK ***** */
    38 
    39 /*
    40  * Common IDL-processing code.
     17 * This program is distributed in the hope that it will be useful, but
     18 * WITHOUT ANY WARRANTY; without even the implied warranty of
     19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     20 * General Public License for more details.
     21 *
     22 * You should have received a copy of the GNU General Public License
     23 * along with this program; if not, see <https://www.gnu.org/licenses>.
     24 *
     25 * SPDX-License-Identifier: GPL-3.0-only
    4126 */
    4227#include <iprt/errcore.h>
    4328#include <iprt/file.h>
    4429#include <iprt/mem.h>
     30#include <iprt/message.h>
     31#include <iprt/path.h>
     32#include <iprt/stream.h>
     33#include <iprt/string.h>
    4534
    4635#include "xpidl.h"
    4736
    48 static gboolean parsed_empty_file;
    49 
    50 /*
    51  * The bulk of the generation happens here.
     37
     38typedef enum XPIDLKEYWORD
     39{
     40    kXpidlKeyword_Invalid = 0,
     41    kXpidlKeyword_Include,
     42    kXpidlKeyword_Typedef,
     43    kXpidlKeyword_32Bit_Hack = 0x7fffffff
     44} XPIDLKEYWORD;
     45
     46static DECLCALLBACK(int) xpidlIdlLexParseNumberIdentifierOrUuid(RTSCRIPTLEX hScriptLex, char ch, PRTSCRIPTLEXTOKEN pToken, void *pvUser);
     47
     48
     49static const char *s_aszSingleStart[] =
     50{
     51    "//",
     52    NULL
     53};
     54
     55
     56static const char *s_aszMultiStart[] =
     57{
     58    "/*",
     59    "%{C++",
     60    NULL
     61};
     62
     63
     64static const char *s_aszMultiEnd[] =
     65{
     66    "*/",
     67    "%}",
     68    NULL
     69};
     70
     71
     72static const RTSCRIPTLEXTOKMATCH s_aMatches[] =
     73{
     74    { RT_STR_TUPLE("#include"),                 RTSCRIPTLEXTOKTYPE_KEYWORD,    true,  kXpidlKeyword_Include },
     75    { RT_STR_TUPLE("uuid"),                     RTSCRIPTLEXTOKTYPE_KEYWORD,    true,  0 },
     76    { RT_STR_TUPLE("ptr"),                      RTSCRIPTLEXTOKTYPE_KEYWORD,    true,  0 },
     77    { RT_STR_TUPLE("ref"),                      RTSCRIPTLEXTOKTYPE_KEYWORD,    true,  0 },
     78    { RT_STR_TUPLE("in"),                       RTSCRIPTLEXTOKTYPE_KEYWORD,    true,  0 },
     79    { RT_STR_TUPLE("out"),                      RTSCRIPTLEXTOKTYPE_KEYWORD,    true,  0 },
     80    { RT_STR_TUPLE("scriptable"),               RTSCRIPTLEXTOKTYPE_KEYWORD,    true,  0 },
     81    { RT_STR_TUPLE("noscript"),                 RTSCRIPTLEXTOKTYPE_KEYWORD,    true,  0 },
     82    { RT_STR_TUPLE("array"),                    RTSCRIPTLEXTOKTYPE_KEYWORD,    true,  0 },
     83    { RT_STR_TUPLE("size_is"),                  RTSCRIPTLEXTOKTYPE_KEYWORD,    true,  0 },
     84    { RT_STR_TUPLE("readonly"),                 RTSCRIPTLEXTOKTYPE_KEYWORD,    true,  0 },
     85    { RT_STR_TUPLE("attribute"),                RTSCRIPTLEXTOKTYPE_KEYWORD,    true,  0 },
     86    { RT_STR_TUPLE("retval"),                   RTSCRIPTLEXTOKTYPE_KEYWORD,    true,  0 },
     87    { RT_STR_TUPLE("interface"),                RTSCRIPTLEXTOKTYPE_KEYWORD,    true,  0 },
     88    { RT_STR_TUPLE("const"),                    RTSCRIPTLEXTOKTYPE_KEYWORD,    true,  0 },
     89    { RT_STR_TUPLE("native"),                   RTSCRIPTLEXTOKTYPE_KEYWORD,    true,  0 },
     90    { RT_STR_TUPLE("nsid"),                     RTSCRIPTLEXTOKTYPE_KEYWORD,    true,  0 },
     91    { RT_STR_TUPLE("typedef"),                  RTSCRIPTLEXTOKTYPE_KEYWORD,    true,  kXpidlKeyword_Typedef },
     92
     93    { RT_STR_TUPLE(","),                        RTSCRIPTLEXTOKTYPE_PUNCTUATOR, false, ',' },
     94    { RT_STR_TUPLE("["),                        RTSCRIPTLEXTOKTYPE_PUNCTUATOR, false, '[' },
     95    { RT_STR_TUPLE("]"),                        RTSCRIPTLEXTOKTYPE_PUNCTUATOR, false, ']' },
     96    { RT_STR_TUPLE("{"),                        RTSCRIPTLEXTOKTYPE_PUNCTUATOR, false, '{' },
     97    { RT_STR_TUPLE("}"),                        RTSCRIPTLEXTOKTYPE_PUNCTUATOR, false, '}' },
     98    { RT_STR_TUPLE("("),                        RTSCRIPTLEXTOKTYPE_PUNCTUATOR, false, '(' },
     99    { RT_STR_TUPLE(")"),                        RTSCRIPTLEXTOKTYPE_PUNCTUATOR, false, ')' },
     100    { RT_STR_TUPLE(";"),                        RTSCRIPTLEXTOKTYPE_PUNCTUATOR, false, ';' },
     101    { RT_STR_TUPLE("="),                        RTSCRIPTLEXTOKTYPE_PUNCTUATOR, false, '=' },
     102    { RT_STR_TUPLE(":"),                        RTSCRIPTLEXTOKTYPE_PUNCTUATOR, false, ':' },
     103    { NULL, 0,                                  RTSCRIPTLEXTOKTYPE_INVALID,    false, 0 }
     104};
     105
     106
     107static const RTSCRIPTLEXRULE s_aRules[] =
     108{
     109    { '\"', '\"',  RTSCRIPT_LEX_RULE_CONSUME, RTScriptLexScanStringLiteralC,          NULL}, /** @todo This is not correct. */
     110    { '0',  '9',   RTSCRIPT_LEX_RULE_DEFAULT, xpidlIdlLexParseNumberIdentifierOrUuid, NULL},
     111    { 'a',  'z',   RTSCRIPT_LEX_RULE_DEFAULT, xpidlIdlLexParseNumberIdentifierOrUuid, NULL},
     112    { 'A',  'Z',   RTSCRIPT_LEX_RULE_DEFAULT, xpidlIdlLexParseNumberIdentifierOrUuid, NULL},
     113    { '_',  '_',   RTSCRIPT_LEX_RULE_DEFAULT, RTScriptLexScanIdentifier,              NULL},
     114    { '\0', '\0',  RTSCRIPT_LEX_RULE_DEFAULT, NULL,                                   NULL}
     115};
     116
     117
     118static const RTSCRIPTLEXCFG g_IdlLexCfg =
     119{
     120    /** pszName */
     121    "IDL",
     122    /** pszDesc */
     123    "IDL lexer",
     124    /** fFlags */
     125    RTSCRIPT_LEX_CFG_F_COMMENTS_AS_TOKENS,
     126    /** pszWhitespace */
     127    NULL,
     128    /** pszNewline */
     129    NULL,
     130    /** papszCommentMultiStart */
     131    s_aszMultiStart,
     132    /** papszCommentMultiEnd */
     133    s_aszMultiEnd,
     134    /** papszCommentSingleStart */
     135    s_aszSingleStart,
     136    /** paTokMatches */
     137    s_aMatches,
     138    /** paRules */
     139    s_aRules,
     140    /** pfnProdDef */
     141    NULL,
     142    /** pfnProdDefUser */
     143    NULL
     144};
     145
     146
     147static bool g_fRequiredUuid = false;
     148
     149static int xpidlParseIdl(PXPIDLPARSE pThis, PXPIDLINPUT pInput, PRTLISTANCHOR pLstIncludePaths);
     150
     151
     152static DECLCALLBACK(int) xpidlIdlLexParseNumberIdentifierOrUuid(RTSCRIPTLEX hScriptLex, char ch, PRTSCRIPTLEXTOKEN pToken, void *pvUser)
     153{
     154    RT_NOREF(pvUser);
     155    if (g_fRequiredUuid)
     156    {
     157        g_fRequiredUuid = false;
     158        /* Scan as an identifier. */
     159        static const char *g_aszIdeCharSetUuid = "abcdefABCDEF01234567809-";
     160        RTScriptLexConsumeCh(hScriptLex);
     161        return RTScriptLexScanIdentifier(hScriptLex, ch, pToken, (void *)g_aszIdeCharSetUuid);
     162    }
     163    else if (ch >= '0' && ch <= '9')
     164        return RTScriptLexScanNumber(hScriptLex, 0 /*uBase*/, false /*fAllowReal*/, pToken);
     165
     166    RTScriptLexConsumeCh(hScriptLex);
     167    return RTScriptLexScanIdentifier(hScriptLex, ch, pToken, NULL);
     168}
     169
     170
     171/**
     172 * Create a new lexer from the given filename, possibly searching the include paths.
     173 *
     174 * @returns IPRT status code.
     175 * @param   pszFilename             The filename to read.
     176 * @param   pLstIncludePaths        The list of include paths to search for relative filenames.
     177 * @param   phIdlLex                Where to store the handle to the lexer on success.
    52178 */
    53 gboolean
    54 xpidl_process_node(TreeState *state)
    55 {
    56     gint type;
    57     nodeHandler *dispatch, handler;
    58 
    59     XPT_ASSERT(state->tree);
    60     type = IDL_NODE_TYPE(state->tree);
    61 
    62     if ((dispatch = state->dispatch) && (handler = dispatch[type]))
    63         return handler(state);
    64     return TRUE;
    65 }
    66 
    67 static int
    68 msg_callback(int level, int num, int line, const char *file,
    69              const char *message)
    70 {
    71     char *warning_message;
    72 
    73     /*
    74      * Egregious hack to permit empty files.
    75      * XXX libIDL needs an API to detect this case robustly.
    76      */
    77     if (0 == strcmp(message, "File empty after optimization")) {
    78         parsed_empty_file = TRUE;
    79         return 1;
    80     }
    81 
    82     if (!file)
    83         file = "<unknown file>";
    84     warning_message = g_strdup_printf("%s:%d: %s\n", file, line, message);
    85 
    86     fputs(warning_message, stderr);
    87     g_free(warning_message);
    88     return 1;
    89 }
    90 
    91 /*
    92  * To keep track of the state associated with a given input file.  The 'next'
    93  * field lets us maintain a stack of input files.
    94  */
    95 typedef struct input_data {
    96     char *filename;             /* where did I come from? */
    97     unsigned int lineno;        /* last lineno processed */
    98     char *buf;                  /* contents of file */
    99     char *point;                /* next char to feed to libIDL */
    100     char *max;                  /* 1 past last char in buf */
    101     struct input_data *next;    /* file from which we were included */
    102 } input_data;
    103 
    104 /*
    105  * Passed to us by libIDL.  Holds global information and the current stack of
    106  * include files.
    107  */
    108 typedef struct input_callback_state {
    109     struct input_data *input_stack; /* linked list of input_data */
    110     GHashTable *already_included;   /* to prevent redundant includes */
    111     IncludePathEntry *include_path; /* search path for included files */
    112     GSList *base_includes;          /* to accumulate #includes from *first* file;
    113                                      * for passing thru TreeState to
    114                                      * xpidl_header backend. */
    115 } input_callback_state;
    116 
    117 static void *
    118 file_read_from_includes(const char *filename, IncludePathEntry *include_path, size_t *pcbFile)
    119 {
    120     IncludePathEntry *current_path = include_path;
    121     char *pathname;
    122 
    123     if (filename[0] != '/') {
    124         while (current_path) {
    125             pathname = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
    126                                        current_path->directory, filename);
    127             if (!pathname)
    128                 return NULL;
    129             void *pvFile = NULL;
    130             int vrc = RTFileReadAll(pathname, &pvFile, pcbFile);
    131             g_free(pathname);
    132             if (RT_SUCCESS(vrc))
    133                 return pvFile;
    134             current_path = current_path->next;
    135         }
    136     } else {
    137         void *pvFile = NULL;
    138         int vrc = RTFileReadAll(filename, &pvFile, pcbFile);
    139         if (RT_SUCCESS(vrc))
    140             return pvFile;
    141     }
    142     return NULL;
    143 }
    144 
    145 #if defined(XP_MAC) && defined(XPIDL_PLUGIN)
    146 extern FILE* mac_fopen(const char* filename, const char *mode);
    147 #endif
    148 
    149 static input_data *
    150 new_input_data(const char *filename, IncludePathEntry *include_path)
    151 {
    152     input_data *new_data;
    153 
    154     /*
    155      * Rather than try to keep track of many different varieties of state
    156      * around the boundaries of a circular buffer, we just read in the entire
    157      * file.
    158      */
    159     size_t cbFile = 0;
    160     void *pvFile = file_read_from_includes(filename, include_path, &cbFile);
    161     if (!pvFile)
    162         return NULL;
    163 
    164     /* Need to copy the data over into a new buffer in order to be able to append a zero terminator. */
    165     char *pbBuf = (char *)RTMemDupEx(pvFile, cbFile, 1 /* for the zero terminator */);
    166     if (!pbBuf)
    167     {
    168         RTFileReadAllFree(pvFile, cbFile);
    169         return NULL;
    170     }
    171 
    172     memcpy(pbBuf, pvFile, cbFile);
    173     RTFileReadAllFree(pvFile, cbFile);
    174 
    175     new_data = xpidl_malloc(sizeof (struct input_data));
    176     if (!new_data)
    177     {
    178         RTMemFree(pbBuf);
    179         return NULL;
    180     }
    181 
    182     new_data->point = new_data->buf = pbBuf;
    183     new_data->max = pbBuf + cbFile;
    184     *new_data->max = '\0';
    185     new_data->filename = xpidl_strdup(filename);
    186     /* libIDL expects the line number to be that of the *next* line */
    187     new_data->lineno = 2;
    188     new_data->next = NULL;
    189     return new_data;
    190 }
    191 
    192 /* process pending raw section */
    193 static int
    194 NextIsRaw(input_data *data, char **startp, int *lenp)
    195 {
    196     char *end, *start;
    197 
    198     /*
    199      * XXXmccabe still needed: an in_raw flag to handle the case where we're in
    200      * a raw block, but haven't managed to copy it all to xpidl.  This will
    201      * happen when we have a raw block larger than
    202      * IDL_input_data->fill.max_size (currently 8192.)
    203      */
    204     if (!(data->point[0] == '%' && data->point[1] == '{'))
    205         return 0;
    206 
    207     start = *startp = data->point;
    208 
    209     end = NULL;
    210     while (start < data->max && (end = strstr(start, "%}"))) {
    211         if (end[-1] == '\r' ||
    212             end[-1] == '\n')
    213             break;
    214         start = end + 1;
    215     }
    216 
    217     if (end && start < data->max) {
    218         *lenp = end - data->point + 2;
    219         return 1;
    220     } else {
    221         const char *filename;
    222         int lineno;
    223 
    224         IDL_file_get(&filename, &lineno);
    225         msg_callback(IDL_ERROR, 0, lineno, filename,
    226                      "unterminated %{ block");
    227         return -1;
    228     }
    229 }
    230 
    231 /* process pending comment */
    232 static int
    233 NextIsComment(input_data *data, char **startp, int *lenp)
    234 {
    235     char *end;
    236 
    237     if (!(data->point[0] == '/' && data->point[1] == '*'))
    238         return 0;
    239 
    240     end = strstr(data->point, "*/");
    241     *lenp = 0;
    242     if (end) {
    243         int skippedLines = 0;
    244         char *tempPoint;
    245 
    246         /* get current lineno */
    247         IDL_file_get(NULL,(int *)&data->lineno);
    248 
    249         /* get line count */
    250         for (tempPoint = data->point; tempPoint < end; tempPoint++) {
    251             if (*tempPoint == '\n')
    252                 skippedLines++;
    253         }
    254 
    255         data->lineno += skippedLines;
    256         IDL_file_set(data->filename, (int)data->lineno);
    257 
    258         *startp = end + 2;
    259 
    260         /* If it's a ** comment, tell libIDL about it. */
    261         if (data->point[2] == '*') {
    262             /* hack termination.  +2 to get past '*' '/' */
    263             char t = *(end + 2);
    264             *(end + 2) = '\0';
    265             IDL_queue_new_ident_comment(data->point);
    266             *(end + 2) = t;
    267         }
    268 
    269         data->point = *startp; /* XXXmccabe move this out of function? */
    270         return 1;
    271     } else {
    272         const char *filename;
    273         int lineno;
    274 
    275         IDL_file_get(&filename, &lineno);
    276         msg_callback(IDL_ERROR, 0, lineno, filename,
    277                      "unterminated comment");
    278         return -1;
    279     }
    280 }
    281 
    282 static int
    283 NextIsInclude(input_callback_state *callback_state, char **startp,
    284               int *lenp)
    285 {
    286     input_data *data = callback_state->input_stack;
    287     input_data *new_data;
    288     char *filename, *end;
    289     const char *scratch;
    290 
    291     /* process the #include that we're in now */
    292     if (strncmp(data->point, "#include \"", 10)) {
    293         return 0;
    294     }
    295 
    296     filename = data->point + 10; /* skip #include " */
    297     XPT_ASSERT(filename < data->max);
    298     end = filename;
    299     while (end < data->max) {
    300         if (*end == '\"' || *end == '\n' || *end == '\r')
    301             break;
    302         end++;
    303     }
    304 
    305     if (*end != '\"') {
    306         /*
    307          * Didn't find end of include file.  Scan 'til next whitespace to find
    308          * some reasonable approximation of the filename, and use it to report
    309          * an error.
    310          */
    311 
    312         end = filename;
    313         while (end < data->max) {
    314             if (*end == ' ' || *end == '\n' || *end == '\r' || *end == '\t')
    315                 break;
    316             end++;
    317         }
    318         *end = '\0';
    319 
    320         /* make sure we have accurate line info */
    321         IDL_file_get(&scratch, (int *)&data->lineno);
    322         fprintf(stderr,
    323                 "%s:%u: didn't find end of quoted include name \"%s\n",
    324                 scratch, data->lineno, filename);
    325         return -1;
    326     }
    327 
    328     *end = '\0';
    329     *startp = end + 1;
    330 
    331     if (data->next == NULL) {
    332         /*
    333          * If we're in the initial file, add this filename to the list
    334          * of filenames to be turned into #include "filename.h"
    335          * directives in xpidl_header.c.  We do it here rather than in the
    336          * block below so it still gets added to the list even if it's
    337          * already been recursively included from some other file.
    338          */
    339         char *filename_cp = xpidl_strdup(filename);
    340 
    341         /* note that g_slist_append accepts and likes null as list-start. */
    342         callback_state->base_includes =
    343             g_slist_append(callback_state->base_includes, filename_cp);
    344     }
    345 
    346     /* store offset for when we pop, or if we skip this one */
    347     data->point = *startp;
    348 
    349     if (!g_hash_table_lookup(callback_state->already_included, filename)) {
    350         filename = xpidl_strdup(filename);
    351         g_hash_table_insert(callback_state->already_included,
    352                             filename, (void *)TRUE);
    353         new_data = new_input_data(filename, callback_state->include_path);
    354         if (!new_data) {
    355             char *error_message;
    356             IDL_file_get(&scratch, (int *)&data->lineno);
    357             error_message =
    358                 g_strdup_printf("can't open included file %s for reading\n",
    359                                 filename);
    360             msg_callback(IDL_ERROR, 0,
    361                          data->lineno, scratch, error_message);
    362             g_free(error_message);
    363             return -1;
    364         }
    365 
    366         new_data->next = data;
    367         /* tell libIDL to exclude this IDL from the toplevel tree */
    368         IDL_inhibit_push();
    369         IDL_file_get(&scratch, (int *)&data->lineno);
    370         callback_state->input_stack = new_data;
    371         IDL_file_set(new_data->filename, (int)new_data->lineno);
    372     }
    373 
    374     *lenp = 0;               /* this is magic, see the comment below */
    375     return 1;
    376 }
    377 
    378 static void
    379 FindSpecial(input_data *data, char **startp, int *lenp)
    380 {
    381     char *point = data->point;
    382 
    383     /* magic sequences are:
    384      * "%{"               raw block
    385      * "/\*"              comment
    386      * "#include \""      include
    387      * The first and last want a newline [\r\n] before, or the start of the
    388      * file.
    389      */
    390 
    391 #define LINE_START(data, point) (point == data->buf ||                       \
    392                                  (point > data->point &&                     \
    393                                   (point[-1] == '\r' || point[-1] == '\n')))
    394 
    395     while (point < data->max) {
    396         if (point[0] == '/' && point[1] == '*')
    397             break;
    398         if (LINE_START(data, point)) {
    399             if (point[0] == '%' && point[1] == '{')
    400                 break;
    401             if (point[0] == '#' && !strncmp(point + 1, "include \"", 9))
    402                 break;
    403         }
    404         point++;
    405     }
    406 
    407 #undef LINE_START
    408 
    409     *startp = data->point;
    410     *lenp = point - data->point;
    411 }
    412 
    413 #ifndef VBOX
    414 /* set this with a debugger to see exactly what libIDL sees */
    415 static FILE *tracefile = NULL;
    416 #endif
    417 
    418 static int
    419 input_callback(IDL_input_reason reason, union IDL_input_data *cb_data,
    420                gpointer user_data)
    421 {
    422     input_callback_state *callback_state = user_data;
    423     input_data *data = callback_state->input_stack;
    424     input_data *new_data = NULL;
    425     unsigned int len, copy;
    426     int rv;
    427     char *start;
    428 
    429     switch(reason) {
    430       case IDL_INPUT_REASON_INIT:
    431         if (data == NULL || data->next == NULL) {
    432             /*
    433              * This is the first file being processed.  As it's the target
    434              * file, we only look for it in the first entry in the include
    435              * path, which we assume to be the current directory.
    436              */
    437 
    438             /* XXXmccabe proper assumption?  Do we handle files in other
    439                directories? */
    440 
    441             IncludePathEntry first_entry;
    442 
    443             first_entry.directory = callback_state->include_path->directory;
    444             first_entry.next = NULL;
    445 
    446             new_data = new_input_data(cb_data->init.filename,
    447                                                &first_entry);
    448         } else {
    449             new_data = new_input_data(cb_data->init.filename,
    450                                                callback_state->include_path);
    451         }
    452 
    453         if (!new_data)
    454             return -1;
    455 
    456         IDL_file_set(new_data->filename, (int)new_data->lineno);
    457         callback_state->input_stack = new_data;
    458         return 0;
    459 
    460       case IDL_INPUT_REASON_FILL:
    461         start = NULL;
    462         len = 0;
    463 
    464         while (data->point >= data->max) {
    465             if (!data->next)
    466                 return 0;
    467 
    468             /* Current file is done; revert to including file */
    469             callback_state->input_stack = data->next;
    470             free(data->filename);
    471             RTMemFree(data->buf);
    472             free(data);
    473             data = callback_state->input_stack;
    474 
    475             IDL_file_set(data->filename, (int)data->lineno);
    476             IDL_inhibit_pop();
    477         }
    478 
    479         /*
    480          * Now we scan for sequences which require special attention:
    481          *   \n#include                   begins an include statement
    482          *   \n%{                         begins a raw-source block
    483          *   /\*                          begins a comment
    484          *
    485          * We used to be fancier here, so make sure that we sent the most
    486          * data possible at any given time.  To that end, we skipped over
    487          * \n%{ raw \n%} blocks and then _continued_ the search for special
    488          * sequences like \n#include or /\* comments .
    489          *
    490          * It was really ugly, though -- liberal use of goto!  lots of implicit
    491          * state!  what fun! -- so now we just do this:
    492          *
    493          * if (special at start) {
    494          *     process that special -
    495          *         - raw: send it to libIDL, and don't look inside for specials
    496          *         - comments: adjust point and start over
    497          *         - includes: push new input_data struct for included file, and
    498          *           start over
    499          * } else {
    500          *     scan for next special
    501          *     send data up to that special to libIDL
    502          * }
    503          *
    504          * If len is set to zero, it is a sentinel value indicating we a comment
    505          * or include was found, and parsing should start over.
    506          *
    507          * XXX const string foo = "/\*" will just screw us horribly.
    508          * Hm but.  We could treat strings as we treat raw blocks, eh?
    509          */
    510 
    511         /*
    512          * Order is important, so that you can have /\* comments and
    513          * #includes within raw sections, and so that you can comment out
    514          * #includes.
    515          */
    516         rv = NextIsRaw(data, &start, (int *)&len);
    517         if (rv == -1) return -1;
    518         if (!rv) {
    519             /*
    520              * When NextIsComment succeeds, it returns a 0 len (requesting a
    521              * restart) and adjusts data->point to pick up after the comment.
    522              */
    523             rv = NextIsComment(data, &start, (int *)&len);
    524             if (rv == -1) return -1;
    525             if (!rv) {
    526                 /*
    527                  * NextIsInclude might push a new input_data struct; if so, it
    528                  * will return a 0 len, letting the callback pick up the new
    529                  * file the next time around.
    530                  */
    531                 rv = NextIsInclude(callback_state, &start, (int *)&len);
    532                 if (rv == -1) return -1;
    533                 if (!rv)
    534                     FindSpecial(data, &start, (int *)&len);
     179static int xpidlCreateLexerFromFilename(const char *pszFilename, PRTLISTANCHOR pLstIncludePaths,
     180                                        PRTSCRIPTLEX phIdlLex)
     181{
     182    char szPath[RTPATH_MAX];
     183
     184    if (pszFilename[0] != '/')
     185    {
     186        PCXPIDLINCLUDEDIR pIt;
     187        RTListForEach(pLstIncludePaths, pIt, XPIDLINCLUDEDIR, NdIncludes)
     188        {
     189            ssize_t cch = RTStrPrintf2(&szPath[0], sizeof(szPath), "%s%c%s",
     190                                       pIt->pszPath, RTPATH_SLASH, pszFilename);
     191            if (cch <= 0)
     192                return VERR_BUFFER_OVERFLOW;
     193
     194            if (RTFileExists(szPath))
     195            {
     196                pszFilename = szPath;
     197                break;
    535198            }
    536199        }
    537 
    538         if (len == 0) {
    539             /*
    540              * len == 0 is a sentinel value that means we found a comment or
    541              * include.  If we found a comment, point has been adjusted to
    542              * point past the comment.  If we found an include, a new input_data
    543              * has been pushed.  In both cases, calling the input_callback again
    544              * will pick up the new state.
    545              */
    546             return input_callback(reason, cb_data, user_data);
     200    }
     201
     202    return RTScriptLexCreateFromFile(phIdlLex, pszFilename, NULL /*phStrCacheId*/,
     203                                     NULL /*phStrCacheStringLit*/, NULL /*phStrCacheComments*/,
     204                                     &g_IdlLexCfg);
     205}
     206
     207
     208static int xpidlParseError(PXPIDLPARSE pThis, PXPIDLINPUT pInput, PCRTSCRIPTLEXTOKEN pTok, int rc, const char *pszFmt, ...)
     209{
     210    va_list Args;
     211    va_start(Args, pszFmt);
     212    RT_NOREF(pTok);
     213    rc = RTErrInfoSetV(&pThis->ErrInfo.Core, rc, pszFmt, Args);
     214    va_end(Args);
     215    return rc;
     216}
     217
     218
     219static int xpidlLexerConsumeIfStringLit(PXPIDLPARSE pThis, PXPIDLINPUT pInput, const char **ppszStrLit)
     220{
     221    PCRTSCRIPTLEXTOKEN pTok;
     222    int rc = RTScriptLexQueryToken(pInput->hIdlLex, &pTok);
     223    if (RT_FAILURE(rc))
     224        return xpidlParseError(pThis, pInput, pTok, rc, "Lexer: Failed to query string literal token with %Rrc", rc);
     225
     226    if (pTok->enmType == RTSCRIPTLEXTOKTYPE_STRINGLIT)
     227    {
     228        *ppszStrLit = pTok->Type.StringLit.pszString;
     229        RTScriptLexConsumeToken(pInput->hIdlLex);
     230        return VINF_SUCCESS;
     231    }
     232
     233    return VINF_SUCCESS;
     234}
     235
     236
     237#define XPIDL_PARSE_STRING_LIT(a_pszStrLit) \
     238    const char *a_pszStrLit = NULL; \
     239    do { \
     240        int rc2 = xpidlLexerConsumeIfStringLit(pThis, pInput, &a_pszStrLit); \
     241        if (RT_FAILURE(rc2)) \
     242            return rc2; \
     243        if (!a_pszStrLit) \
     244            return xpidlParseError(pThis, pInput, NULL, VERR_INVALID_PARAMETER, "Parser: Expected a string literal"); \
     245    } while(0)
     246
     247
     248static PXPIDLINPUT xpidlInputCreate(const char *pszFilename, PRTLISTANCHOR pLstIncludePaths)
     249{
     250    RTSCRIPTLEX hIdlLex = NULL;
     251    int rc = xpidlCreateLexerFromFilename(pszFilename, pLstIncludePaths, &hIdlLex);
     252    if (RT_FAILURE(rc))
     253        return NULL;
     254
     255    PXPIDLINPUT pInput = (PXPIDLINPUT)xpidl_malloc(sizeof (*pInput));
     256    if (!pInput)
     257    {
     258        RTScriptLexDestroy(hIdlLex);
     259        return NULL;
     260    }
     261
     262    RTListInit(&pInput->LstIncludes);
     263    pInput->hIdlLex     = hIdlLex;
     264    pInput->pszFilename = xpidl_strdup(pszFilename);
     265    return pInput;
     266}
     267
     268
     269static PXPIDLNODE xpidlNodeCreate(PXPIDLPARSE pThis, PXPIDLNODE pParent, PXPIDLINPUT pInput, XPIDLNDTYPE enmType)
     270{
     271    PXPIDLNODE pNode = (PXPIDLNODE)RTMemAllocZ(sizeof(*pNode));
     272    if (pNode)
     273    {
     274        pNode->pParent = pParent;
     275        pNode->pInput  = pInput;
     276        pNode->enmType = enmType;
     277    }
     278    else
     279        xpidlParseError(pThis, pInput, NULL, VERR_NO_MEMORY, "Failed to allocate node of type %u\n", enmType);
     280
     281    return pNode;
     282}
     283
     284
     285static int xpidlParseKeyword(PXPIDLPARSE pThis, PXPIDLINPUT pInput, PRTLISTANCHOR pLstIncludePaths,
     286                             PCRTSCRIPTLEXTOKMATCH pKeyword)
     287{
     288    RT_NOREF(pThis, pInput, pLstIncludePaths);
     289    int rc;
     290    switch (pKeyword->u64Val)
     291    {
     292        case kXpidlKeyword_Include:
     293        {
     294            XPIDL_PARSE_STRING_LIT(pszFilename);
     295            PXPIDLINPUT pInput = xpidlInputCreate(pszFilename, pLstIncludePaths);
     296            if (!pInput)
     297                return xpidlParseError(pThis, pInput, NULL, VERR_INVALID_PARAMETER, "Failed opening include file '%s'",
     298                                       pszFilename);
     299
     300            RTListAppend(&pThis->LstInputs, &pInput->NdInput);
     301            rc = xpidlParseIdl(pThis, pInput, pLstIncludePaths);
     302            break;
    547303        }
    548 
    549         copy = MIN(len, (unsigned int) cb_data->fill.max_size);
    550         memcpy(cb_data->fill.buffer, start, copy);
    551         data->point = start + copy;
    552 
    553 #ifndef VBOX
    554         if (tracefile)
    555             fwrite(cb_data->fill.buffer, copy, 1, tracefile);
    556 #endif
    557 
    558         return copy;
    559 
    560       case IDL_INPUT_REASON_ABORT:
    561       case IDL_INPUT_REASON_FINISH:
    562         while (data != NULL) {
    563             input_data *next;
    564 
    565             next = data->next;
    566             free(data->filename);
    567             RTMemFree(data->buf);
    568             free(data);
    569             data = next;
     304        case kXpidlKeyword_Typedef:
     305        {
     306            /** @todo */
     307            break;
     308        }
     309        default:
     310            rc = xpidlParseError(pThis, pInput, NULL, VERR_INVALID_PARAMETER, "Unexpected keyword '%s' found",
     311                                 pKeyword->pszMatch);
     312    }
     313    return rc;
     314}
     315
     316
     317static int xpidlParseAttributes(PXPIDLPARSE pThis, PXPIDLINPUT pInput)
     318{
     319    RT_NOREF(pThis, pInput);
     320    return VERR_NOT_IMPLEMENTED;
     321}
     322
     323
     324static int xpidlParseIdl(PXPIDLPARSE pThis, PXPIDLINPUT pInput, PRTLISTANCHOR pLstIncludePaths)
     325{
     326    /* Parse IDL file. */
     327    int rc;
     328    for (;;)
     329    {
     330        PCRTSCRIPTLEXTOKEN pTok;
     331        rc = RTScriptLexQueryToken(pInput->hIdlLex, &pTok);
     332        if (RT_FAILURE(rc))
     333            return xpidlParseError(pThis, pInput, NULL, rc, "Parser: Failed to query next token with %Rrc", rc);
     334
     335        if (pTok->enmType == RTSCRIPTLEXTOKTYPE_EOS)
     336            break;
     337
     338        /*
     339         * In this outer loop we can either get comments, keywords or [] for
     340         * attributes of following nodes.
     341         */
     342        switch (pTok->enmType)
     343        {
     344            case RTSCRIPTLEXTOKTYPE_COMMENT_SINGLE_LINE:
     345                RTScriptLexConsumeToken(pInput->hIdlLex); /* These get ignored entirely. */
     346                break;
     347            case RTSCRIPTLEXTOKTYPE_COMMENT_MULTI_LINE:
     348            {
     349                /* Could be a raw block, check that the string starts with %{C++. */
     350                if (!strncmp(pTok->Type.Comment.pszComment, RT_STR_TUPLE("%{C++")))
     351                {
     352                    /* Create a new raw block node. */
     353                    PXPIDLNODE pNode = xpidlNodeCreate(pThis, NULL, pInput, kXpidlNdType_RawBlock);
     354                    if (pNode)
     355                    {
     356                        pNode->u.RawBlock.pszRaw = pTok->Type.Comment.pszComment + 5;
     357                        pNode->u.RawBlock.cchRaw = pTok->Type.Comment.cchComment - (5 + 2 + 1); /* Start + end + zero terminator. */
     358                        RTListAppend(&pThis->LstNodes, &pNode->NdLst);
     359                    }
     360                    else
     361                        rc = VERR_NO_MEMORY;
     362                }
     363                /* else: Regular multi line comment, gets ignored. */
     364                RTScriptLexConsumeToken(pInput->hIdlLex);
     365                break;
     366            }
     367            case RTSCRIPTLEXTOKTYPE_KEYWORD:
     368            {
     369                PCRTSCRIPTLEXTOKMATCH pKeyword = pTok->Type.Keyword.pKeyword;
     370                RTScriptLexConsumeToken(pInput->hIdlLex);
     371                rc = xpidlParseKeyword(pThis, pInput, pLstIncludePaths, pKeyword); /** @todo This allows too much */
     372                break;
     373            }
     374            case RTSCRIPTLEXTOKTYPE_PUNCTUATOR:
     375            {
     376                if (pTok->Type.Punctuator.pPunctuator->u64Val == '[')
     377                {
     378                    RTScriptLexConsumeToken(pInput->hIdlLex);
     379                    rc = xpidlParseAttributes(pThis, pInput);
     380                }
     381                else
     382                    rc = xpidlParseError(pThis, pInput, pTok, VERR_INVALID_PARAMETER, "Unexpected punctuator found, expected '[', got '%c'",
     383                                         (char)pTok->Type.Punctuator.pPunctuator->u64Val);
     384                break;
     385            }
     386            case RTSCRIPTLEXTOKTYPE_ERROR:
     387                rc = xpidlParseError(pThis, pInput, pTok, VERR_INTERNAL_ERROR, "Internal lexer error: %s", pTok->Type.Error.pErr->pszMsg);
     388                break;
     389            default:
     390                rc = xpidlParseError(pThis, pInput, pTok, VERR_INVALID_PARAMETER, "Unexpected keyword found, expected raw block, keyword or '['");
     391                break;
    570392        }
    571         callback_state->input_stack = NULL;
    572         return 0;
    573 
    574       default:
    575         g_error("unknown input reason %d!", reason);
    576         return -1;
    577     }
    578 }
    579 
    580 static void
    581 free_ghash_key(gpointer key, gpointer value, gpointer user_data)
    582 {
    583     /* We're only storing TRUE in the value... */
    584     free(key);
    585 }
    586 
    587 static void
    588 free_gslist_data(gpointer data, gpointer user_data)
    589 {
    590     free(data);
    591 }
    592 
    593 /* Pick up unlink. */
    594 #include <unistd.h>
    595 
    596 int
    597 xpidl_process_idl(char *filename, IncludePathEntry *include_path,
    598                   char *file_basename, ModeData *mode)
    599 {
    600     char *tmp, *outname, *real_outname = NULL;
    601     IDL_tree top;
    602     TreeState state;
    603     int rv;
    604     input_callback_state callback_state;
    605     gboolean ok = TRUE;
    606     backend *emitter;
    607 
    608     callback_state.input_stack = NULL;
    609     callback_state.base_includes = NULL;
    610     callback_state.include_path = include_path;
    611     callback_state.already_included = g_hash_table_new(g_str_hash, g_str_equal);
    612 
    613     if (!callback_state.already_included) {
    614         fprintf(stderr, "failed to create hashtable.  out of memory?\n");
    615         return 0;
    616     }
    617 
    618     state.basename = xpidl_strdup(filename);
    619 
    620     /* if basename has an .extension, truncate it. */
    621     tmp = strrchr(state.basename, '.');
    622     if (tmp)
    623         *tmp = '\0';
    624 
    625     if (!file_basename)
    626         outname = xpidl_strdup(state.basename);
     393
     394        if (RT_FAILURE(rc))
     395            break;
     396    }
     397
     398    return rc;
     399}
     400
     401
     402int xpidl_process_idl(char *filename, PRTLISTANCHOR pLstIncludePaths,
     403                      char *file_basename, ModeData *mode)
     404{
     405    XPIDLPARSE ParseState;
     406    RTListInit(&ParseState.LstInputs);
     407    RTListInit(&ParseState.LstNodes);
     408    RTErrInfoInitStatic(&ParseState.ErrInfo);
     409
     410    PXPIDLINPUT pInput = xpidlInputCreate(filename, pLstIncludePaths);
     411    if (!pInput)
     412        return VERR_NO_MEMORY;
     413
     414    RTListAppend(&ParseState.LstInputs, &pInput->NdInput);
     415    int rc = xpidlParseIdl(&ParseState, pInput, pLstIncludePaths);
     416    if (RT_SUCCESS(rc))
     417    {
     418        /** @todo Output. */
     419    }
    627420    else
    628         outname = xpidl_strdup(file_basename);
    629 
    630     /* so we don't include it again! */
    631     g_hash_table_insert(callback_state.already_included,
    632                         xpidl_strdup(filename), (void *)TRUE);
    633 
    634     parsed_empty_file = FALSE;
    635 
    636     rv = IDL_parse_filename_with_input(filename, input_callback, &callback_state,
    637                                        msg_callback, &top,
    638                                        &state.ns,
    639                                        IDLF_IGNORE_FORWARDS |
    640                                        IDLF_XPIDL,
    641                                        enable_warnings ? IDL_WARNING1 :
    642                                        IDL_ERROR);
    643     if (parsed_empty_file) {
    644         /*
    645          * If we've detected (via hack in msg_callback) that libIDL returned
    646          * failure because it found a file with no IDL, set the parse tree to
    647          * null and proceed.  Allowing this is useful to permit .idl files that
    648          * collect #includes.
    649          */
    650         top = NULL;
    651         state.ns = NULL;
    652     } else if (rv != IDL_SUCCESS) {
    653         if (rv == -1) {
    654             g_warning("Parse of %s failed: %s", filename, g_strerror(errno));
    655         } else {
    656             g_warning("Parse of %s failed", filename);
    657         }
    658         free(outname);
    659         return 0;
    660     }
    661 
    662     state.basename = xpidl_strdup(filename);
    663     tmp = strrchr(state.basename, '.');
    664     if (tmp)
    665         *tmp = '\0';
    666 
    667     /* so xpidl_header.c can use it to generate a list of #include directives */
    668     state.base_includes = callback_state.base_includes;
    669 
    670     emitter = mode->factory();
    671     state.dispatch = emitter->dispatch_table;
    672 
    673     if (strcmp(outname, "-")) {
    674         const char *fopen_mode;
    675         char *out_basename;
    676 
    677         /* explicit_output_filename can't be true without a filename */
    678         if (explicit_output_filename) {
    679             real_outname = g_strdup(outname);
    680         } else {
    681 
    682             if (!file_basename) {
    683                 out_basename = xpidl_basename(outname);
    684             } else {
    685                 out_basename = outname;
    686             }
    687 
    688             real_outname = g_strdup_printf("%s.%s", out_basename, mode->suffix);
    689             if (out_basename != outname)
    690                 g_free(out_basename);
    691         }
    692 
    693         /* Use binary write for typelib mode */
    694         fopen_mode = (strcmp(mode->mode, "typelib")) ? "w" : "wb";
    695         state.file = fopen(real_outname, fopen_mode);
    696         if (!state.file) {
    697             perror("error opening output file");
    698             free(outname);
    699             return 0;
    700         }
    701     } else {
    702         state.file = stdout;
    703     }
    704     state.tree = top;
    705 
    706     if (emitter->emit_prolog)
    707         emitter->emit_prolog(&state);
    708     if (state.tree) /* Only if we have a tree to process. */
    709         ok = xpidl_process_node(&state);
    710     if (emitter->emit_epilog)
    711         emitter->emit_epilog(&state);
    712 
    713     if (state.file != stdout)
    714         fclose(state.file);
    715     free(state.basename);
    716     free(outname);
    717     g_hash_table_foreach(callback_state.already_included, free_ghash_key, NULL);
    718     g_hash_table_destroy(callback_state.already_included);
    719     g_slist_foreach(callback_state.base_includes, free_gslist_data, NULL);
    720 
    721     if (state.ns)
    722         IDL_ns_free(state.ns);
    723     if (top)
    724         IDL_tree_free(top);
    725 
    726     if (real_outname != NULL) {
    727         /*
    728          * Delete partial output file on failure.  (Mac does this in the plugin
    729          * driver code, if the compiler returns failure.)
    730          */
    731         if (!ok)
    732             unlink(real_outname);
    733 
    734         g_free(real_outname);
    735     }
    736 
    737     return ok;
    738 }
     421        RTMsgError(ParseState.ErrInfo.Core.pszMsg);
     422
     423    return rc;
     424}
  • trunk/src/libs/xpcom18a4/xpcom/typelib/xpidl-new/xpidl_util.c

    r103505 r108284  
    7373}
    7474
     75#if 0
    7576void
    7677xpidl_write_comment(TreeState *state, int indent)
     
    8384    fputs(" */\n", state->file);
    8485}
     86#endif
    8587
    8688/*
     
    8890 * UUID_LENGTH bytes.
    8991 */
    90 gboolean
     92bool
    9193xpidl_sprint_iid(nsID *id, char iidbuf[])
    9294{
     
    116118 * so we re-implement nsID::Parse here.
    117119 */
    118 gboolean
     120bool
    119121xpidl_parse_iid(nsID *id, const char *str)
    120122{
     
    126128   
    127129    if (strlen(str) != 36) {
    128         return FALSE;
     130        return false;
    129131    }
    130132     
     
    152154    }
    153155#endif
    154     return (gboolean)(count == 11);
    155 }
    156 
     156    return (count == 11);
     157}
     158
     159#if 0
    157160gboolean
    158161verify_const_declaration(IDL_tree const_tree) {
     
    847850    return result;
    848851}
     852#endif
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette