зеркало из https://github.com/mozilla/pjs.git
part of xipidl compiler to generate java interfaces
This commit is contained in:
Родитель
8b36127530
Коммит
7c28c101fb
|
@ -0,0 +1,73 @@
|
|||
#
|
||||
# The contents of this file are subject to the Netscape Public
|
||||
# License Version 1.1 (the "License"); you may not use this file
|
||||
# except in compliance with the License. You may obtain a copy of
|
||||
# the License at http://www.mozilla.org/NPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS
|
||||
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
# implied. See the License for the specific language governing
|
||||
# rights and limitations under the License.
|
||||
#
|
||||
# The Original Code is mozilla.org code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape
|
||||
# Communications Corporation. Portions created by Netscape are
|
||||
# Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
DEPTH = ../../../..
|
||||
topsrcdir = ../../../..
|
||||
srcdir = .
|
||||
VPATH = .
|
||||
XPIDLDIR = $(DEPTH)/xpcom/typelib/xpidl
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
PROGRAM = xpidl$(BIN_SUFFIX)
|
||||
INTERNAL_TOOLS = 1
|
||||
|
||||
CSRCS = \
|
||||
$(XPIDLDIR)/xpidl.c \
|
||||
xpidl_idl.c \
|
||||
$(XPIDLDIR)/xpidl_util.c \
|
||||
$(XPIDLDIR)/xpidl_header.c \
|
||||
$(XPIDLDIR)/xpidl_typelib.c \
|
||||
$(XPIDLDIR)/xpidl_doc.c \
|
||||
xpidl_java.c \
|
||||
$(NULL)
|
||||
|
||||
|
||||
CFLAGS += $(LIBIDL_CFLAGS) -I$(XPIDLDIR)
|
||||
|
||||
ifdef CROSS_COMPILE
|
||||
HOST_PROGRAM = host_xpidl
|
||||
HOST_CSRCS = $(CSRCS)
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
|
||||
|
||||
# Compile directly against the static lib, so we can use xpidl during the build
|
||||
# without the shared library path being set.
|
||||
LIBS = $(DIST)/lib/libxpt.$(LIB_SUFFIX) $(LIBIDL_LIBS)
|
||||
|
||||
# Tell the $(PROGRAM) target that we need to be recompiled when libxpt changes.
|
||||
EXTRA_DEPS = $(wildcard $(DIST)/lib/libxpt.*)
|
||||
|
||||
ifdef CROSS_COMPILE
|
||||
HOST_CFLAGS += $(HOST_LIBIDL_CFLAGS)
|
||||
HOST_LIBS = $(DIST)/host/lib/libhostxpt.$(LIB_SUFFIX) $(HOST_LIBIDL_LIBS)
|
||||
HOST_EXTRA_DEPS = $(wildcard $(DIST)/host/lib/libhostxpt.*)
|
||||
|
||||
ifdef HOST_NSPR_MDCPUCFG
|
||||
HOST_CFLAGS += -DMDCPUCFG=$(HOST_NSPR_MDCPUCFG)
|
||||
endif
|
||||
endif
|
||||
|
||||
export:: install
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
#
|
||||
# The contents of this file are subject to the Netscape Public
|
||||
# License Version 1.1 (the "License"); you may not use this file
|
||||
# except in compliance with the License. You may obtain a copy of
|
||||
# the License at http://www.mozilla.org/NPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS
|
||||
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
# implied. See the License for the specific language governing
|
||||
# rights and limitations under the License.
|
||||
#
|
||||
# The Original Code is mozilla.org code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape
|
||||
# Communications Corporation. Portions created by Netscape are
|
||||
# Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
DEPTH = ../../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
XPIDLDIR = $(DEPTH)/xpcom/typelib/xpidl
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
PROGRAM = xpidl$(BIN_SUFFIX)
|
||||
INTERNAL_TOOLS = 1
|
||||
|
||||
CSRCS = \
|
||||
$(XPIDLDIR)/xpidl.c \
|
||||
xpidl_idl.c \
|
||||
$(XPIDLDIR)/xpidl_util.c \
|
||||
$(XPIDLDIR)/xpidl_header.c \
|
||||
$(XPIDLDIR)/xpidl_typelib.c \
|
||||
$(XPIDLDIR)/xpidl_doc.c \
|
||||
xpidl_java.c \
|
||||
$(NULL)
|
||||
|
||||
|
||||
CFLAGS += $(LIBIDL_CFLAGS) -I$(XPIDLDIR)
|
||||
|
||||
ifdef CROSS_COMPILE
|
||||
HOST_PROGRAM = host_xpidl
|
||||
HOST_CSRCS = $(CSRCS)
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
|
||||
|
||||
# Compile directly against the static lib, so we can use xpidl during the build
|
||||
# without the shared library path being set.
|
||||
LIBS = $(DIST)/lib/libxpt.$(LIB_SUFFIX) $(LIBIDL_LIBS)
|
||||
|
||||
# Tell the $(PROGRAM) target that we need to be recompiled when libxpt changes.
|
||||
EXTRA_DEPS = $(wildcard $(DIST)/lib/libxpt.*)
|
||||
|
||||
ifdef CROSS_COMPILE
|
||||
HOST_CFLAGS += $(HOST_LIBIDL_CFLAGS)
|
||||
HOST_LIBS = $(DIST)/host/lib/libhostxpt.$(LIB_SUFFIX) $(HOST_LIBIDL_LIBS)
|
||||
HOST_EXTRA_DEPS = $(wildcard $(DIST)/host/lib/libhostxpt.*)
|
||||
|
||||
ifdef HOST_NSPR_MDCPUCFG
|
||||
HOST_CFLAGS += -DMDCPUCFG=$(HOST_NSPR_MDCPUCFG)
|
||||
endif
|
||||
endif
|
||||
|
||||
export:: install
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
#!nmake
|
||||
#
|
||||
# The contents of this file are subject to the Netscape Public
|
||||
# License Version 1.1 (the "License"); you may not use this file
|
||||
# except in compliance with the License. You may obtain a copy of
|
||||
# the License at http://www.mozilla.org/NPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS
|
||||
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
# implied. See the License for the specific language governing
|
||||
# rights and limitations under the License.
|
||||
#
|
||||
# The Original Code is mozilla.org code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape
|
||||
# Communications Corporation. Portions created by Netscape are
|
||||
# Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
|
||||
DEPTH=..\..\..\..
|
||||
|
||||
MAKE_OBJ_TYPE = EXE
|
||||
PROGRAM = .\$(OBJDIR)\xpidl.exe
|
||||
#RESFILE = xpidl.res
|
||||
|
||||
# glib and libIDL link against the non-debug msvcrt
|
||||
MOZ_NO_DEBUG_RTL=1
|
||||
XPIDLDIR = $(DEPTH)\xpcom\typelib\xpidl
|
||||
|
||||
|
||||
OBJS = \
|
||||
$(XPIDLDIR)\$(OBJDIR)\xpidl.obj \
|
||||
.\$(OBJDIR)\xpidl_idl.obj \
|
||||
$(XPIDLDIR)\$(OBJDIR)\xpidl_util.obj \
|
||||
$(XPIDLDIR)\$(OBJDIR)\xpidl_header.obj \
|
||||
$(XPIDLDIR)\$(OBJDIR)\xpidl_typelib.obj \
|
||||
$(XPIDLDIR)\$(OBJDIR)\xpidl_doc.obj \
|
||||
.\$(OBJDIR)\xpidl_java.obj \
|
||||
$(NULL)
|
||||
|
||||
LINCS=-I$(PUBLIC)\xpcom \
|
||||
-I$(MOZ_TOOLS)\include \
|
||||
-I$(XPIDLDIR) \
|
||||
$(NULL)
|
||||
|
||||
LCFLAGS = -DEXPORT_XPT_API
|
||||
|
||||
MYDIR=C:\USR\LOCAL
|
||||
|
||||
LLIBS= \
|
||||
$(DIST)\lib\xpcomxpt_s.lib \
|
||||
$(MOZ_TOOLS)\lib\glib-1.2.lib \
|
||||
$(MOZ_TOOLS)\lib\libidl-0.6.lib \
|
||||
$(NULL)
|
||||
|
||||
LLFLAGS= $(LLFLAGS) -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRTD
|
||||
|
||||
include <$(DEPTH)\config\rules.mak>
|
||||
|
||||
export:: $(PROGRAM)
|
||||
$(MAKE_INSTALL) $(PROGRAM) $(DIST)\bin
|
||||
|
||||
clobber::
|
||||
rm -f $(DIST)\bin\xpidl.exe
|
||||
|
||||
$(PROGRAM):: $(OBJS) $(MYLIBS)
|
|
@ -0,0 +1,746 @@
|
|||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*/
|
||||
|
||||
/*
|
||||
* Common IDL-processing code.
|
||||
*/
|
||||
|
||||
#include "xpidl.h"
|
||||
|
||||
/*
|
||||
* The bulk of the generation happens here.
|
||||
*/
|
||||
gboolean
|
||||
xpidl_process_node(TreeState *state)
|
||||
{
|
||||
gint type;
|
||||
nodeHandler *dispatch, handler;
|
||||
|
||||
assert(state->tree);
|
||||
type = IDL_NODE_TYPE(state->tree);
|
||||
|
||||
if ((dispatch = state->dispatch) && (handler = dispatch[type]))
|
||||
return handler(state);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#if defined(XP_MAC) && defined(XPIDL_PLUGIN)
|
||||
extern void mac_warning(const char* warning_message);
|
||||
#endif
|
||||
|
||||
static int
|
||||
msg_callback(int level, int num, int line, const char *file,
|
||||
const char *message)
|
||||
{
|
||||
char *warning_message;
|
||||
|
||||
if (!file)
|
||||
file = "<unknown file>";
|
||||
warning_message = g_strdup_printf("%s:%d: %s\n", file, line, message);
|
||||
|
||||
#if defined(XP_MAC) && defined(XPIDL_PLUGIN)
|
||||
mac_warning(warning_message);
|
||||
#else
|
||||
fputs(warning_message, stderr);
|
||||
#endif
|
||||
|
||||
free(warning_message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* To keep track of the state associated with a given input file. The 'next'
|
||||
* field lets us maintain a stack of input files.
|
||||
*/
|
||||
typedef struct input_data {
|
||||
char *filename; /* where did I come from? */
|
||||
unsigned int lineno; /* last lineno processed */
|
||||
char *buf; /* contents of file */
|
||||
char *point; /* next char to feed to libIDL */
|
||||
char *max; /* 1 past last char in buf */
|
||||
struct input_data *next; /* file from which we were included */
|
||||
} input_data;
|
||||
|
||||
/*
|
||||
* Passed to us by libIDL. Holds global information and the current stack of
|
||||
* include files.
|
||||
*/
|
||||
typedef struct input_callback_state {
|
||||
struct input_data *input_stack; /* linked list of input_data */
|
||||
GHashTable *already_included; /* to prevent redundant includes */
|
||||
IncludePathEntry *include_path; /* search path for included files */
|
||||
GSList *base_includes; /* to accumulate #includes from *first* file;
|
||||
* for passing thru TreeState to
|
||||
* xpidl_header backend. */
|
||||
} input_callback_state;
|
||||
|
||||
static FILE *
|
||||
fopen_from_includes(const char *filename, const char *mode,
|
||||
IncludePathEntry *include_path)
|
||||
{
|
||||
IncludePathEntry *current_path = include_path;
|
||||
char *pathname;
|
||||
FILE *inputfile;
|
||||
if (!strcmp(filename, "-"))
|
||||
return stdin;
|
||||
|
||||
if (filename[0] != '/') {
|
||||
while (current_path) {
|
||||
pathname = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
|
||||
current_path->directory, filename);
|
||||
if (!pathname)
|
||||
return NULL;
|
||||
inputfile = fopen(pathname, mode);
|
||||
free(pathname);
|
||||
if (inputfile)
|
||||
return inputfile;
|
||||
current_path = current_path->next;
|
||||
}
|
||||
} else {
|
||||
inputfile = fopen(filename, mode);
|
||||
if (inputfile)
|
||||
return inputfile;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if defined(XP_MAC) && defined(XPIDL_PLUGIN)
|
||||
extern FILE* mac_fopen(const char* filename, const char *mode);
|
||||
#endif
|
||||
|
||||
static input_data *
|
||||
new_input_data(const char *filename, IncludePathEntry *include_path)
|
||||
{
|
||||
input_data *new_data;
|
||||
FILE *inputfile;
|
||||
char *buffer = NULL;
|
||||
size_t offset = 0;
|
||||
size_t buffer_size;
|
||||
#ifdef XP_MAC
|
||||
size_t i;
|
||||
#endif
|
||||
|
||||
#if defined(XP_MAC) && defined(XPIDL_PLUGIN)
|
||||
// on Mac, fopen knows how to find files.
|
||||
inputfile = fopen(filename, "r");
|
||||
#else
|
||||
inputfile = fopen_from_includes(filename, "r", include_path);
|
||||
#endif
|
||||
|
||||
if (!inputfile)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Rather than try to keep track of many different varieties of state
|
||||
* around the boundaries of a circular buffer, we just read in the entire
|
||||
* file.
|
||||
*
|
||||
* We iteratively grow the buffer here; an alternative would be to use
|
||||
* stat to find the exact buffer size we need, as xpt_dump does.
|
||||
*/
|
||||
for (buffer_size = 8191; ; buffer_size *= 2) {
|
||||
size_t just_read;
|
||||
buffer = realloc(buffer, buffer_size + 1); /* +1 for trailing nul */
|
||||
just_read = fread(buffer + offset, 1, buffer_size - offset, inputfile);
|
||||
if (ferror(inputfile))
|
||||
return NULL;
|
||||
|
||||
if (just_read < buffer_size - offset || just_read == 0) {
|
||||
/* Done reading. */
|
||||
offset += just_read;
|
||||
break;
|
||||
}
|
||||
offset += just_read;
|
||||
}
|
||||
fclose(inputfile);
|
||||
|
||||
#ifdef XP_MAC
|
||||
/*
|
||||
* libIDL doesn't speak '\r' properly - always make sure lines end with
|
||||
* '\n'.
|
||||
*/
|
||||
for (i = 0; i < offset; i++) {
|
||||
if (buffer[i] == '\r')
|
||||
buffer[i] = '\n';
|
||||
}
|
||||
#endif
|
||||
|
||||
new_data = xpidl_malloc(sizeof (struct input_data));
|
||||
new_data->point = new_data->buf = buffer;
|
||||
new_data->max = buffer + offset;
|
||||
*new_data->max = '\0';
|
||||
new_data->filename = xpidl_strdup(filename);
|
||||
/* libIDL expects the line number to be that of the *next* line */
|
||||
new_data->lineno = 2;
|
||||
new_data->next = NULL;
|
||||
|
||||
return new_data;
|
||||
}
|
||||
|
||||
/* process pending raw section */
|
||||
static int
|
||||
NextIsRaw(input_data *data, char **startp, int *lenp)
|
||||
{
|
||||
char *end, *start;
|
||||
|
||||
/*
|
||||
* XXXmccabe still needed: an in_raw flag to handle the case where we're in
|
||||
* a raw block, but haven't managed to copy it all to xpidl. This will
|
||||
* happen when we have a raw block larger than
|
||||
* IDL_input_data->fill.max_size (currently 8192.)
|
||||
*/
|
||||
if (!(data->point[0] == '%' && data->point[1] == '{'))
|
||||
return 0;
|
||||
|
||||
start = *startp = data->point;
|
||||
|
||||
end = NULL;
|
||||
while (start < data->max && (end = strstr(start, "%}"))) {
|
||||
if (end[-1] == '\r' ||
|
||||
end[-1] == '\n')
|
||||
break;
|
||||
start = end + 1;
|
||||
}
|
||||
|
||||
if (end && start < data->max) {
|
||||
*lenp = end - data->point + 2;
|
||||
return 1;
|
||||
} else {
|
||||
const char *filename;
|
||||
int lineno;
|
||||
|
||||
IDL_file_get(&filename, &lineno);
|
||||
msg_callback(IDL_ERROR, 0, lineno, filename,
|
||||
"unterminated %{ block");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* process pending comment */
|
||||
static int
|
||||
NextIsComment(input_data *data, char **startp, int *lenp)
|
||||
{
|
||||
char *end;
|
||||
|
||||
if (!(data->point[0] == '/' && data->point[1] == '*'))
|
||||
return 0;
|
||||
|
||||
end = strstr(data->point, "*/");
|
||||
*lenp = 0;
|
||||
if (end) {
|
||||
int skippedLines = 0;
|
||||
char *tempPoint;
|
||||
|
||||
/* get current lineno */
|
||||
IDL_file_get(NULL,(int *)&data->lineno);
|
||||
|
||||
/* get line count */
|
||||
for (tempPoint = data->point; tempPoint < end; tempPoint++) {
|
||||
if (*tempPoint == '\n')
|
||||
skippedLines++;
|
||||
}
|
||||
|
||||
data->lineno += skippedLines;
|
||||
IDL_file_set(data->filename, (int)data->lineno);
|
||||
|
||||
*startp = end + 2;
|
||||
|
||||
/* If it's a ** comment, tell libIDL about it. */
|
||||
if (data->point[2] == '*') {
|
||||
/* hack termination. +2 to get past '*' '/' */
|
||||
char t = *(end + 2);
|
||||
*(end + 2) = '\0';
|
||||
IDL_queue_new_ident_comment(data->point);
|
||||
*(end + 2) = t;
|
||||
}
|
||||
|
||||
data->point = *startp; /* XXXmccabe move this out of function? */
|
||||
return 1;
|
||||
} else {
|
||||
const char *filename;
|
||||
int lineno;
|
||||
|
||||
IDL_file_get(&filename, &lineno);
|
||||
msg_callback(IDL_ERROR, 0, lineno, filename,
|
||||
"unterminated comment");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
NextIsInclude(input_callback_state *callback_state, char **startp,
|
||||
int *lenp)
|
||||
{
|
||||
input_data *data = callback_state->input_stack;
|
||||
input_data *new_data;
|
||||
char *filename, *start, *end;
|
||||
const char *scratch;
|
||||
|
||||
/* process the #include that we're in now */
|
||||
if (strncmp(data->point, "#include \"", 10)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
filename = data->point + 10; /* skip #include " */
|
||||
assert(filename < data->max);
|
||||
end = filename;
|
||||
while (end < data->max) {
|
||||
if (*end == '\"' || *end == '\n' || *end == '\r')
|
||||
break;
|
||||
end++;
|
||||
}
|
||||
|
||||
if (*end != '\"') {
|
||||
/*
|
||||
* Didn't find end of include file. Scan 'til next whitespace to find
|
||||
* some reasonable approximation of the filename, and use it to report
|
||||
* an error.
|
||||
*/
|
||||
|
||||
end = filename;
|
||||
while (end < data->max) {
|
||||
if (*end == ' ' || *end == '\n' || *end == '\r' || *end == '\t')
|
||||
break;
|
||||
end++;
|
||||
}
|
||||
*end = '\0';
|
||||
|
||||
/* make sure we have accurate line info */
|
||||
IDL_file_get(&scratch, (int *)&data->lineno);
|
||||
fprintf(stderr,
|
||||
"%s:%d: didn't find end of quoted include name \"%s\n",
|
||||
scratch, data->lineno, filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*end = '\0';
|
||||
*startp = end + 1;
|
||||
|
||||
if (data->next == NULL) {
|
||||
/*
|
||||
* If we're in the initial file, add this filename to the list
|
||||
* of filenames to be turned into #include "filename.h"
|
||||
* directives in xpidl_header.c. We do it here rather than in the
|
||||
* block below so it still gets added to the list even if it's
|
||||
* already been recursively included from some other file.
|
||||
*/
|
||||
char *filename_cp = xpidl_strdup(filename);
|
||||
|
||||
/* note that g_slist_append accepts and likes null as list-start. */
|
||||
callback_state->base_includes =
|
||||
g_slist_append(callback_state->base_includes, filename_cp);
|
||||
}
|
||||
|
||||
/* store offset for when we pop, or if we skip this one */
|
||||
data->point = *startp;
|
||||
|
||||
if (!g_hash_table_lookup(callback_state->already_included, filename)) {
|
||||
filename = xpidl_strdup(filename);
|
||||
g_hash_table_insert(callback_state->already_included,
|
||||
filename, (void *)TRUE);
|
||||
new_data = new_input_data(filename, callback_state->include_path);
|
||||
if (!new_data) {
|
||||
char *error_message;
|
||||
IDL_file_get(&scratch, (int *)&data->lineno);
|
||||
error_message =
|
||||
g_strdup_printf("can't open included file %s for reading\n",
|
||||
filename);
|
||||
msg_callback(IDL_ERROR, 0,
|
||||
data->lineno, scratch, error_message);
|
||||
free(error_message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
new_data->next = data;
|
||||
/* tell libIDL to exclude this IDL from the toplevel tree */
|
||||
IDL_inhibit_push();
|
||||
IDL_file_get(&scratch, (int *)&data->lineno);
|
||||
callback_state->input_stack = new_data;
|
||||
IDL_file_set(new_data->filename, (int)new_data->lineno);
|
||||
}
|
||||
|
||||
*lenp = 0; /* this is magic, see the comment below */
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
FindSpecial(input_data *data, char **startp, int *lenp)
|
||||
{
|
||||
char *point = data->point;
|
||||
|
||||
/* magic sequences are:
|
||||
* "%{" raw block
|
||||
* "/\*" comment
|
||||
* "#include \"" include
|
||||
* The first and last want a newline [\r\n] before, or the start of the
|
||||
* file.
|
||||
*/
|
||||
|
||||
#define LINE_START(data, point) (point == data->buf || \
|
||||
(point > data->point && \
|
||||
(point[-1] == '\r' || point[-1] == '\n')))
|
||||
|
||||
while (point < data->max) {
|
||||
if (point[0] == '/' && point[1] == '*')
|
||||
break;
|
||||
if (LINE_START(data, point)) {
|
||||
if (point[0] == '%' && point[1] == '{')
|
||||
break;
|
||||
if (point[0] == '#' && !strncmp(point + 1, "include \"", 9))
|
||||
break;
|
||||
}
|
||||
point++;
|
||||
}
|
||||
|
||||
#undef LINE_START
|
||||
|
||||
*startp = data->point;
|
||||
*lenp = point - data->point;
|
||||
}
|
||||
|
||||
/* set this with a debugger to see exactly what libIDL sees */
|
||||
static FILE *tracefile;
|
||||
|
||||
static int
|
||||
input_callback(IDL_input_reason reason, union IDL_input_data *cb_data,
|
||||
gpointer user_data)
|
||||
{
|
||||
input_callback_state *callback_state = user_data;
|
||||
input_data *data = callback_state->input_stack;
|
||||
input_data *new_data = NULL;
|
||||
unsigned int len, copy;
|
||||
int rv;
|
||||
char *start;
|
||||
|
||||
switch(reason) {
|
||||
case IDL_INPUT_REASON_INIT:
|
||||
if (data == NULL || data->next == NULL) {
|
||||
/*
|
||||
* This is the first file being processed. As it's the target
|
||||
* file, we only look for it in the first entry in the include
|
||||
* path, which we assume to be the current directory.
|
||||
*/
|
||||
|
||||
/* XXXmccabe proper assumption? Do we handle files in other
|
||||
directories? */
|
||||
|
||||
IncludePathEntry first_entry;
|
||||
|
||||
first_entry.directory = callback_state->include_path->directory;
|
||||
first_entry.next = NULL;
|
||||
|
||||
new_data = new_input_data(cb_data->init.filename,
|
||||
&first_entry);
|
||||
} else {
|
||||
new_data = new_input_data(cb_data->init.filename,
|
||||
callback_state->include_path);
|
||||
}
|
||||
|
||||
if (!new_data)
|
||||
return -1;
|
||||
|
||||
IDL_file_set(new_data->filename, (int)new_data->lineno);
|
||||
callback_state->input_stack = new_data;
|
||||
return 0;
|
||||
|
||||
case IDL_INPUT_REASON_FILL:
|
||||
start = NULL;
|
||||
len = 0;
|
||||
|
||||
while (data->point >= data->max) {
|
||||
if (!data->next)
|
||||
return 0;
|
||||
|
||||
/* Current file is done; revert to including file */
|
||||
callback_state->input_stack = data->next;
|
||||
free(data->filename);
|
||||
free(data->buf);
|
||||
free(data);
|
||||
data = callback_state->input_stack;
|
||||
|
||||
IDL_file_set(data->filename, (int)data->lineno);
|
||||
IDL_inhibit_pop();
|
||||
}
|
||||
|
||||
/*
|
||||
* Now we scan for sequences which require special attention:
|
||||
* \n#include begins an include statement
|
||||
* \n%{ begins a raw-source block
|
||||
* /\* begins a comment
|
||||
*
|
||||
* We used to be fancier here, so make sure that we sent the most
|
||||
* data possible at any given time. To that end, we skipped over
|
||||
* \n%{ raw \n%} blocks and then _continued_ the search for special
|
||||
* sequences like \n#include or /\* comments .
|
||||
*
|
||||
* It was really ugly, though -- liberal use of goto! lots of implicit
|
||||
* state! what fun! -- so now we just do this:
|
||||
*
|
||||
* if (special at start) {
|
||||
* process that special -
|
||||
* - raw: send it to libIDL, and don't look inside for specials
|
||||
* - comments: adjust point and start over
|
||||
* - includes: push new input_data struct for included file, and
|
||||
* start over
|
||||
* } else {
|
||||
* scan for next special
|
||||
* send data up to that special to libIDL
|
||||
* }
|
||||
*
|
||||
* If len is set to zero, it is a sentinel value indicating we a comment
|
||||
* or include was found, and parsing should start over.
|
||||
*
|
||||
* XXX const string foo = "/\*" will just screw us horribly.
|
||||
* Hm but. We could treat strings as we treat raw blocks, eh?
|
||||
*/
|
||||
|
||||
/*
|
||||
* Order is important, so that you can have /\* comments and
|
||||
* #includes within raw sections, and so that you can comment out
|
||||
* #includes.
|
||||
*/
|
||||
rv = NextIsRaw(data, &start, (int *)&len);
|
||||
if (rv == -1) return -1;
|
||||
if (!rv) {
|
||||
/*
|
||||
* When NextIsComment succeeds, it returns a 0 len (requesting a
|
||||
* restart) and adjusts data->point to pick up after the comment.
|
||||
*/
|
||||
rv = NextIsComment(data, &start, (int *)&len);
|
||||
if (rv == -1) return -1;
|
||||
if (!rv) {
|
||||
/*
|
||||
* NextIsInclude might push a new input_data struct; if so, it
|
||||
* will return a 0 len, letting the callback pick up the new
|
||||
* file the next time around.
|
||||
*/
|
||||
rv = NextIsInclude(callback_state, &start, (int *)&len);
|
||||
if (rv == -1) return -1;
|
||||
if (!rv)
|
||||
FindSpecial(data, &start, (int *)&len);
|
||||
}
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
/*
|
||||
* len == 0 is a sentinel value that means we found a comment or
|
||||
* include. If we found a comment, point has been adjusted to
|
||||
* point past the comment. If we found an include, a new input_data
|
||||
* has been pushed. In both cases, calling the input_callback again
|
||||
* will pick up the new state.
|
||||
*/
|
||||
return input_callback(reason, cb_data, user_data);
|
||||
}
|
||||
|
||||
copy = MIN(len, (unsigned int) cb_data->fill.max_size);
|
||||
memcpy(cb_data->fill.buffer, start, copy);
|
||||
data->point = start + copy;
|
||||
|
||||
if (tracefile)
|
||||
fwrite(cb_data->fill.buffer, copy, 1, tracefile);
|
||||
|
||||
return copy;
|
||||
|
||||
case IDL_INPUT_REASON_ABORT:
|
||||
case IDL_INPUT_REASON_FINISH:
|
||||
while (data != NULL) {
|
||||
input_data *next;
|
||||
|
||||
next = data->next;
|
||||
free(data->filename);
|
||||
free(data->buf);
|
||||
free(data);
|
||||
data = next;
|
||||
}
|
||||
return 0;
|
||||
|
||||
default:
|
||||
g_error("unknown input reason %d!", reason);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
free_ghash_key(gpointer key, gpointer value, gpointer user_data)
|
||||
{
|
||||
/* We're only storing TRUE in the value... */
|
||||
free(key);
|
||||
}
|
||||
|
||||
static void
|
||||
free_gslist_data(gpointer data, gpointer user_data)
|
||||
{
|
||||
free(data);
|
||||
}
|
||||
|
||||
/* Pick up unlink. */
|
||||
#ifdef XP_UNIX
|
||||
#include <unistd.h>
|
||||
#elif XP_WIN
|
||||
/* We get it from stdio.h. */
|
||||
#endif
|
||||
|
||||
int
|
||||
xpidl_process_idl(char *filename, IncludePathEntry *include_path,
|
||||
char *file_basename, ModeData *mode)
|
||||
{
|
||||
char *tmp, *outname, *mode_outname = NULL;
|
||||
IDL_tree top;
|
||||
TreeState state;
|
||||
int rv;
|
||||
input_callback_state callback_state;
|
||||
gboolean ok;
|
||||
backend *emitter;
|
||||
|
||||
callback_state.input_stack = NULL;
|
||||
callback_state.base_includes = NULL;
|
||||
callback_state.include_path = include_path;
|
||||
callback_state.already_included = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
|
||||
if (!callback_state.already_included) {
|
||||
fprintf(stderr, "failed to create hashtable. out of memory?\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
state.basename = xpidl_strdup(filename);
|
||||
|
||||
/* if basename has an .extension, truncate it. */
|
||||
tmp = strrchr(state.basename, '.');
|
||||
if (tmp)
|
||||
*tmp = '\0';
|
||||
|
||||
if (!file_basename)
|
||||
outname = xpidl_strdup(state.basename);
|
||||
else
|
||||
outname = xpidl_strdup(file_basename);
|
||||
|
||||
/* so we don't include it again! */
|
||||
g_hash_table_insert(callback_state.already_included,
|
||||
xpidl_strdup(filename), (void *)TRUE);
|
||||
|
||||
rv = IDL_parse_filename_with_input(filename, input_callback, &callback_state,
|
||||
msg_callback, &top,
|
||||
&state.ns,
|
||||
IDLF_IGNORE_FORWARDS |
|
||||
IDLF_XPIDL,
|
||||
enable_warnings ? IDL_WARNING1 :
|
||||
IDL_ERROR);
|
||||
if (rv != IDL_SUCCESS) {
|
||||
if (rv == -1) {
|
||||
g_warning("Parse of %s failed: %s", filename, g_strerror(errno));
|
||||
} else {
|
||||
g_warning("Parse of %s failed", filename);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
state.basename = xpidl_strdup(filename);
|
||||
tmp = strrchr(state.basename, '.');
|
||||
if (tmp)
|
||||
*tmp = '\0';
|
||||
|
||||
/* so xpidl_header.c can use it to generate a list of #include directives */
|
||||
state.base_includes = callback_state.base_includes;
|
||||
|
||||
emitter = mode->factory();
|
||||
state.dispatch = emitter->dispatch_table;
|
||||
|
||||
if (strcmp(outname, "-")) {
|
||||
// don't open file if the mode is "java"
|
||||
if (strcmp(mode->mode, "java")) {
|
||||
const char *fopen_mode;
|
||||
mode_outname = g_strdup_printf("%s.%s", outname, mode->suffix);
|
||||
/* Use binary write for typelib mode */
|
||||
fopen_mode = (strcmp(mode->mode, "typelib")) ? "w" : "wb";
|
||||
state.file = fopen(mode_outname, fopen_mode);
|
||||
if (!state.file) {
|
||||
perror("error opening output file");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
state.file = NULL;
|
||||
}
|
||||
} else {
|
||||
state.file = stdout;
|
||||
}
|
||||
state.tree = top;
|
||||
|
||||
if (emitter->emit_prolog)
|
||||
emitter->emit_prolog(&state);
|
||||
ok = xpidl_process_node(&state);
|
||||
if (emitter->emit_epilog)
|
||||
emitter->emit_epilog(&state);
|
||||
|
||||
if (state.file && state.file != stdout)
|
||||
fclose(state.file);
|
||||
free(state.basename);
|
||||
free(outname);
|
||||
g_hash_table_foreach(callback_state.already_included, free_ghash_key, NULL);
|
||||
g_hash_table_destroy(callback_state.already_included);
|
||||
g_slist_foreach(callback_state.base_includes, free_gslist_data, NULL);
|
||||
|
||||
IDL_ns_free(state.ns);
|
||||
IDL_tree_free(top);
|
||||
|
||||
if (mode_outname != NULL) {
|
||||
/*
|
||||
* Delete partial output file on failure. (Mac does this in the plugin
|
||||
* driver code, if the compiler returns failure.)
|
||||
*/
|
||||
#if defined(XP_UNIX) || defined(XP_WIN)
|
||||
if (!ok)
|
||||
unlink(mode_outname);
|
||||
#endif
|
||||
free(mode_outname);
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
/*
|
||||
* Our own version of IDL_tree_warning, which we use when IDL_tree_warning
|
||||
* would crash on us.
|
||||
*/
|
||||
void
|
||||
xpidl_tree_warning(IDL_tree p, int level, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char *msg, *file;
|
||||
int lineno;
|
||||
|
||||
/* XXX need to check against __IDL_max_msg_level, no accessor */
|
||||
va_start(ap, fmt);
|
||||
msg = g_strdup_vprintf(fmt, ap);
|
||||
|
||||
if (p) {
|
||||
file = p->_file;
|
||||
lineno = p->_line;
|
||||
} else {
|
||||
file = NULL;
|
||||
lineno = 0;
|
||||
}
|
||||
|
||||
/* call our message callback, like IDL_tree_warning would */
|
||||
msg_callback(level, 0, lineno, file, msg);
|
||||
|
||||
va_end(ap);
|
||||
}
|
|
@ -0,0 +1,859 @@
|
|||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Sun Microsystems,
|
||||
* Inc. Portions created by Sun are
|
||||
* Copyright (C) 1999 Sun Microsystems, Inc. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Michael Allen (michael.allen@sun.com)
|
||||
* Frank Mitchell (frank.mitchell@sun.com)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Generate Java interfaces from XPIDL.
|
||||
*/
|
||||
|
||||
#include "xpidl.h"
|
||||
#include <ctype.h>
|
||||
#include <glib.h>
|
||||
|
||||
|
||||
/*
|
||||
* Write a one-line comment containing IDL
|
||||
* source decompiled from state->tree.
|
||||
*/
|
||||
void write_comment(TreeState *state);
|
||||
|
||||
struct java_priv_data {
|
||||
GHashTable *typedefTable;
|
||||
FILE *file;
|
||||
};
|
||||
|
||||
#define TYPEDEFS(state) (((struct java_priv_data *)state->priv)->typedefTable)
|
||||
#define FILENAME(state) (((struct java_priv_data *)state->priv)->file)
|
||||
|
||||
static gboolean
|
||||
write_classname_iid_define(FILE *file, const char *className)
|
||||
{
|
||||
const char *iidName;
|
||||
if (className[0] == 'n' && className[1] == 's') {
|
||||
/* backcompat naming styles */
|
||||
fputs("NS_", file);
|
||||
iidName = className + 2;
|
||||
} else {
|
||||
iidName = className;
|
||||
}
|
||||
|
||||
while (*iidName) {
|
||||
fputc(toupper(*iidName++), file);
|
||||
}
|
||||
|
||||
fputs("_IID", file);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
java_prolog(TreeState *state)
|
||||
{
|
||||
state->priv = calloc(1, sizeof(struct java_priv_data));
|
||||
if (!state->priv)
|
||||
return FALSE;
|
||||
TYPEDEFS(state) = 0;
|
||||
TYPEDEFS(state) = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
if (!TYPEDEFS(state)) {
|
||||
/* XXX report error */
|
||||
free(state->priv);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
java_epilog(TreeState *state)
|
||||
{
|
||||
/* points to other elements of the tree, so just destroy the table */
|
||||
g_hash_table_destroy(TYPEDEFS(state));
|
||||
free(state->priv);
|
||||
state->priv = NULL;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
forward_declaration(TreeState *state)
|
||||
{
|
||||
/*
|
||||
* Java doesn't need forward declarations unless the declared
|
||||
* class resides in a different package.
|
||||
*/
|
||||
#if 0
|
||||
IDL_tree iface = state->tree;
|
||||
const char *className = IDL_IDENT(IDL_FORWARD_DCL(iface).ident).str;
|
||||
const char *pkgName = "org.mozilla.xpcom";
|
||||
if (!className)
|
||||
return FALSE;
|
||||
/* XXX: Get package name and compare */
|
||||
fprintf(FILENAME(state), "import %s.%s;\n", pkgName, className);
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
interface_declaration(TreeState *state)
|
||||
{
|
||||
|
||||
char *outname;
|
||||
IDL_tree interface = state->tree;
|
||||
IDL_tree iterator = NULL;
|
||||
char *interface_name = IDL_IDENT(IDL_INTERFACE(interface).ident).str;
|
||||
const char *iid = NULL;
|
||||
GSList *doc_comments = IDL_IDENT(IDL_INTERFACE(interface).ident).comments;
|
||||
char *prefix = IDL_GENTREE(IDL_NS(state->ns).current)._cur_prefix;
|
||||
|
||||
/*
|
||||
* Each interface decl is a single file
|
||||
*/
|
||||
outname = g_strdup_printf("%s.%s", interface_name, "java");
|
||||
FILENAME(state) = fopen(outname, "w");
|
||||
if (!FILENAME(state)) {
|
||||
perror("error opening output file");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
fputs("/*\n * ************* DO NOT EDIT THIS FILE ***********\n",
|
||||
FILENAME(state));
|
||||
|
||||
fprintf(FILENAME(state),
|
||||
" *\n * This file was automatically generated from %s.idl.\n",
|
||||
state->basename);
|
||||
|
||||
fputs(" */\n\n", FILENAME(state));
|
||||
|
||||
if (prefix) {
|
||||
if (strlen(prefix))
|
||||
fprintf(FILENAME(state), "\npackage %s;\n\n", prefix);
|
||||
fputs("import org.mozilla.xpcom.*;\n\n", FILENAME(state));
|
||||
} else {
|
||||
fputs("\npackage org.mozilla.xpcom;\n\n", FILENAME(state));
|
||||
}
|
||||
|
||||
/*
|
||||
* Write out JavaDoc comment
|
||||
*/
|
||||
|
||||
fprintf(FILENAME(state), "\n/**\n * Interface %s\n", interface_name);
|
||||
|
||||
#ifndef LIBIDL_MAJOR_VERSION
|
||||
iid = IDL_tree_property_get(interface, "uuid");
|
||||
#else
|
||||
iid = IDL_tree_property_get(IDL_INTERFACE(interface).ident, "uuid");
|
||||
#endif
|
||||
|
||||
if (iid != NULL) {
|
||||
fprintf(FILENAME(state), " *\n * IID: 0x%s\n */\n\n", iid);
|
||||
} else {
|
||||
fputs(" */\n\n", FILENAME(state));
|
||||
}
|
||||
|
||||
if (doc_comments != NULL)
|
||||
printlist(FILENAME(state), doc_comments);
|
||||
|
||||
/*
|
||||
* Write "public interface <foo>"
|
||||
*/
|
||||
|
||||
fprintf(FILENAME(state), "public interface %s ", interface_name);
|
||||
|
||||
/*
|
||||
* Check for inheritence, and iterator over the inherited names,
|
||||
* if any.
|
||||
*/
|
||||
|
||||
if ((iterator = IDL_INTERFACE(interface).inheritance_spec)) {
|
||||
fputs("extends ", FILENAME(state));
|
||||
|
||||
do {
|
||||
|
||||
fprintf(FILENAME(state), "%s",
|
||||
IDL_IDENT(IDL_LIST(iterator).data).str);
|
||||
|
||||
if (IDL_LIST(iterator).next) {
|
||||
fputs(", ", FILENAME(state));
|
||||
}
|
||||
} while ((iterator = IDL_LIST(iterator).next));
|
||||
|
||||
}
|
||||
|
||||
fputs("\n{\n", FILENAME(state));
|
||||
|
||||
if (iid) {
|
||||
/*
|
||||
* Write interface constants for IID
|
||||
*/
|
||||
|
||||
/* fputs(" public static final String ", FILENAME(state)); */
|
||||
|
||||
/* XXX s.b just "IID" ? */
|
||||
/* if (!write_classname_iid_define(FILENAME(state), interface_name)) { */
|
||||
/* return FALSE; */
|
||||
/* } */
|
||||
|
||||
/* fprintf(FILENAME(state), "_STRING =\n \"%s\";\n\n", iid); */
|
||||
|
||||
/* fputs(" public static final nsID ", FILENAME(state)); */
|
||||
|
||||
/* XXX s.b just "IID" ? */
|
||||
/* if (!write_classname_iid_define(FILENAME(state), interface_name)) { */
|
||||
/* return FALSE; */
|
||||
/* } */
|
||||
|
||||
/* fprintf(FILENAME(state), " =\n new nsID(\"%s\");\n\n", iid); */
|
||||
fprintf(FILENAME(state), " public static final String IID =\n \"%s\";\n\n", iid);
|
||||
}
|
||||
|
||||
/*
|
||||
* Advance the state of the tree, go on to process more
|
||||
*/
|
||||
|
||||
state->tree = IDL_INTERFACE(interface).body;
|
||||
|
||||
if (state->tree && !xpidl_process_node(state)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
fputs("\n}\n", FILENAME(state));
|
||||
fprintf(FILENAME(state), "\n/*\n * end\n */\n");
|
||||
fclose(FILENAME(state));
|
||||
free(outname);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
process_list(TreeState *state)
|
||||
{
|
||||
IDL_tree iter;
|
||||
gint type;
|
||||
for (iter = state->tree; iter; iter = IDL_LIST(iter).next) {
|
||||
state->tree = IDL_LIST(iter).data;
|
||||
type = IDL_NODE_TYPE(state->tree);
|
||||
if (!xpidl_process_node(state))
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
xpcom_to_java_type (TreeState *state)
|
||||
{
|
||||
if (!state->tree) {
|
||||
fputs("Object", FILENAME(state));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
switch(IDL_NODE_TYPE(state->tree)) {
|
||||
|
||||
case IDLN_TYPE_INTEGER: {
|
||||
|
||||
switch(IDL_TYPE_INTEGER(state->tree).f_type) {
|
||||
|
||||
case IDL_INTEGER_TYPE_SHORT:
|
||||
fputs("short", FILENAME(state));
|
||||
break;
|
||||
|
||||
case IDL_INTEGER_TYPE_LONG:
|
||||
fputs("int", FILENAME(state));
|
||||
break;
|
||||
|
||||
case IDL_INTEGER_TYPE_LONGLONG:
|
||||
fputs("long", FILENAME(state));
|
||||
break;
|
||||
|
||||
default:
|
||||
g_error(" Unknown integer type: %d\n",
|
||||
IDL_TYPE_INTEGER(state->tree).f_type);
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case IDLN_TYPE_CHAR:
|
||||
case IDLN_TYPE_WIDE_CHAR:
|
||||
fputs("char", FILENAME(state));
|
||||
break;
|
||||
|
||||
case IDLN_TYPE_WIDE_STRING:
|
||||
case IDLN_TYPE_STRING:
|
||||
fputs("String", FILENAME(state));
|
||||
break;
|
||||
|
||||
case IDLN_TYPE_BOOLEAN:
|
||||
fputs("boolean", FILENAME(state));
|
||||
break;
|
||||
|
||||
case IDLN_TYPE_OCTET:
|
||||
fputs("byte", FILENAME(state));
|
||||
break;
|
||||
|
||||
case IDLN_TYPE_FLOAT:
|
||||
switch(IDL_TYPE_FLOAT(state->tree).f_type) {
|
||||
|
||||
case IDL_FLOAT_TYPE_FLOAT:
|
||||
fputs("float", FILENAME(state));
|
||||
break;
|
||||
|
||||
case IDL_FLOAT_TYPE_DOUBLE:
|
||||
fputs("double", FILENAME(state));
|
||||
break;
|
||||
|
||||
default:
|
||||
g_error(" Unknown floating point typ: %d\n",
|
||||
IDL_NODE_TYPE(state->tree));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case IDLN_IDENT:
|
||||
if (IDL_NODE_UP(state->tree) &&
|
||||
IDL_NODE_TYPE(IDL_NODE_UP(state->tree)) == IDLN_NATIVE) {
|
||||
const char *user_type = IDL_NATIVE(IDL_NODE_UP(state->tree)).user_type;
|
||||
const char *ident_str = IDL_IDENT(IDL_NATIVE(IDL_NODE_UP(state->tree)).ident).str;
|
||||
if (strcmp(user_type, "void") == 0) {
|
||||
fputs("Object", FILENAME(state));
|
||||
}
|
||||
else if (strcmp(user_type, "nsID") == 0 ||
|
||||
strcmp(user_type, "nsIID") == 0 ||
|
||||
strcmp(user_type, "nsCID") == 0) {
|
||||
/* XXX: s.b test for "iid" attribute */
|
||||
/* XXX: special class for nsIDs */
|
||||
fputs("IID", FILENAME(state));
|
||||
}
|
||||
else {
|
||||
/* XXX: special class for opaque types */
|
||||
fputs("OpaqueValue", FILENAME(state));
|
||||
}
|
||||
} else {
|
||||
const char *ident_str = IDL_IDENT(state->tree).str;
|
||||
|
||||
/* XXX: big kludge; s.b. way to match to typedefs */
|
||||
if (strcmp(ident_str, "PRInt8") == 0 ||
|
||||
strcmp(ident_str, "PRUint8") == 0) {
|
||||
fputs("byte", FILENAME(state));
|
||||
}
|
||||
else if (strcmp(ident_str, "PRInt16") == 0 ||
|
||||
strcmp(ident_str, "PRUint16") == 0) {
|
||||
fputs("short", FILENAME(state));
|
||||
}
|
||||
else if (strcmp(ident_str, "PRInt32") == 0 ||
|
||||
strcmp(ident_str, "PRUint32") == 0) {
|
||||
fputs("int", FILENAME(state));
|
||||
}
|
||||
else if (strcmp(ident_str, "PRInt64") == 0 ||
|
||||
strcmp(ident_str, "PRUint64") == 0) {
|
||||
fputs("long", FILENAME(state));
|
||||
}
|
||||
else if (strcmp(ident_str, "PRBool") == 0) {
|
||||
fputs("boolean", FILENAME(state));
|
||||
}
|
||||
else if (strcmp(ident_str, "nsrefcnt") == 0) {
|
||||
fputs("int", FILENAME(state));
|
||||
}
|
||||
else {
|
||||
IDL_tree real_type =
|
||||
g_hash_table_lookup(TYPEDEFS(state), ident_str);
|
||||
|
||||
if (real_type) {
|
||||
IDL_tree orig_tree = state->tree;
|
||||
|
||||
state->tree = real_type;
|
||||
xpcom_to_java_type(state);
|
||||
|
||||
state->tree = orig_tree;
|
||||
}
|
||||
else {
|
||||
fputs(ident_str, FILENAME(state));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case IDLN_TYPE_ENUM:
|
||||
case IDLN_TYPE_OBJECT:
|
||||
default:
|
||||
g_error(" Unknown type: %d\n",
|
||||
IDL_TYPE_FLOAT(state->tree).f_type);
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
static gboolean
|
||||
xpcom_to_java_param(TreeState *state)
|
||||
{
|
||||
IDL_tree param = state->tree;
|
||||
state->tree = IDL_PARAM_DCL(param).param_type_spec;
|
||||
|
||||
/*
|
||||
* Put in type of parameter
|
||||
*/
|
||||
|
||||
if (!xpcom_to_java_type(state)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the parameter is out or inout, make it a Java array of the
|
||||
* appropriate type
|
||||
*/
|
||||
|
||||
if (IDL_PARAM_DCL(param).attr != IDL_PARAM_IN) {
|
||||
fputs("[]", FILENAME(state));
|
||||
}
|
||||
|
||||
/*
|
||||
* If the parameter is an array make it a Java array
|
||||
*/
|
||||
if (IDL_tree_property_get(IDL_PARAM_DCL(param).simple_declarator, "array"))
|
||||
fputs("[]", FILENAME(state));
|
||||
|
||||
/*
|
||||
* Put in name of parameter
|
||||
*/
|
||||
|
||||
fputc(' ', FILENAME(state));
|
||||
|
||||
fputs(IDL_IDENT(IDL_PARAM_DCL(param).simple_declarator).str, FILENAME(state));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
type_declaration(TreeState *state)
|
||||
{
|
||||
/*
|
||||
* Unlike C, Java has no type declaration directive.
|
||||
* Instead, we record the mapping, and look up the actual type
|
||||
* when needed.
|
||||
*/
|
||||
IDL_tree type = IDL_TYPE_DCL(state->tree).type_spec;
|
||||
IDL_tree dcls = IDL_TYPE_DCL(state->tree).dcls;
|
||||
|
||||
/* XXX: check for illegal types */
|
||||
|
||||
g_hash_table_insert(TYPEDEFS(state),
|
||||
IDL_IDENT(IDL_LIST(dcls).data).str,
|
||||
type);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
method_declaration(TreeState *state)
|
||||
{
|
||||
/* IDL_tree method_tree = state->tree; */
|
||||
const char* array = NULL;
|
||||
GSList *doc_comments = IDL_IDENT(IDL_OP_DCL(state->tree).ident).comments;
|
||||
struct _IDL_OP_DCL *method = &IDL_OP_DCL(state->tree);
|
||||
gboolean method_notxpcom =
|
||||
(IDL_tree_property_get(method->ident, "notxpcom") != NULL);
|
||||
gboolean method_noscript =
|
||||
(IDL_tree_property_get(method->ident, "noscript") != NULL);
|
||||
IDL_tree iterator = NULL;
|
||||
IDL_tree retval_param = NULL;
|
||||
const char *method_name = IDL_IDENT(method->ident).str;
|
||||
|
||||
if (doc_comments != NULL) {
|
||||
fputs(" ", FILENAME(state));
|
||||
printlist(FILENAME(state), doc_comments);
|
||||
}
|
||||
|
||||
if (method_notxpcom || method_noscript)
|
||||
return TRUE;
|
||||
|
||||
if (!verify_method_declaration(state->tree))
|
||||
return FALSE;
|
||||
|
||||
fputc('\n', FILENAME(state));
|
||||
write_comment(state);
|
||||
|
||||
/*
|
||||
* Write beginning of method declaration
|
||||
*/
|
||||
fputs(" ", FILENAME(state));
|
||||
if (!method_noscript) {
|
||||
/* Nonscriptable methods become package-protected */
|
||||
fputs("public ", FILENAME(state));
|
||||
}
|
||||
|
||||
/*
|
||||
* Write return type
|
||||
* Unlike C++ headers, Java interfaces return the declared
|
||||
* return value; an exception indicates XPCOM method failure.
|
||||
*/
|
||||
if (method_notxpcom || method->op_type_spec) {
|
||||
state->tree = method->op_type_spec;
|
||||
if (!xpcom_to_java_type(state)) {
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
|
||||
/* Check for retval attribute */
|
||||
for (iterator = method->parameter_dcls; iterator != NULL;
|
||||
iterator = IDL_LIST(iterator).next) {
|
||||
|
||||
IDL_tree original_tree = state->tree;
|
||||
|
||||
state->tree = IDL_LIST(iterator).data;
|
||||
|
||||
if (IDL_tree_property_get(IDL_PARAM_DCL(state->tree).simple_declarator,
|
||||
"retval")) {
|
||||
retval_param = iterator;
|
||||
|
||||
array =
|
||||
IDL_tree_property_get(IDL_PARAM_DCL(state->tree).simple_declarator,
|
||||
"array");
|
||||
state->tree = IDL_PARAM_DCL(state->tree).param_type_spec;
|
||||
/*
|
||||
* Put in type of parameter
|
||||
*/
|
||||
if (!xpcom_to_java_type(state)) {
|
||||
return FALSE;
|
||||
}
|
||||
if (array)
|
||||
fputs("[]", FILENAME(state));
|
||||
|
||||
}
|
||||
|
||||
state->tree = original_tree;
|
||||
}
|
||||
|
||||
if (retval_param == NULL) {
|
||||
fputs("void", FILENAME(state));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Write method name
|
||||
*/
|
||||
fprintf(FILENAME(state), " %c%s(", tolower(method_name[0]), method_name + 1);
|
||||
|
||||
/*
|
||||
* Write parameters
|
||||
*/
|
||||
for (iterator = method->parameter_dcls; iterator != NULL;
|
||||
iterator = IDL_LIST(iterator).next) {
|
||||
|
||||
/* Skip "retval" */
|
||||
if (iterator == retval_param) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (iterator != method->parameter_dcls) {
|
||||
fputs(", ", FILENAME(state));
|
||||
}
|
||||
|
||||
state->tree = IDL_LIST(iterator).data;
|
||||
if (!xpcom_to_java_param(state)) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
fputs(")", FILENAME(state));
|
||||
|
||||
if (method->raises_expr) {
|
||||
IDL_tree iter = method->raises_expr;
|
||||
IDL_tree dataNode = IDL_LIST(iter).data;
|
||||
|
||||
fputs(" throws ", FILENAME(state));
|
||||
fputs(IDL_IDENT(dataNode).str, FILENAME(state));
|
||||
iter = IDL_LIST(iter).next;
|
||||
|
||||
while (iter) {
|
||||
dataNode = IDL_LIST(iter).data;
|
||||
fprintf(FILENAME(state), ", %s", IDL_IDENT(dataNode).str);
|
||||
iter = IDL_LIST(iter).next;
|
||||
}
|
||||
}
|
||||
|
||||
fputs(";\n", FILENAME(state));
|
||||
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
constant_declaration(TreeState *state)
|
||||
{
|
||||
/*
|
||||
* The C++ header XPIDL module only allows for shorts and longs (ints)
|
||||
* to be constants, so we will follow the same convention
|
||||
*/
|
||||
|
||||
struct _IDL_CONST_DCL *declaration = &IDL_CONST_DCL(state->tree);
|
||||
const char *name = IDL_IDENT(declaration->ident).str;
|
||||
|
||||
gboolean success;
|
||||
gboolean isshort = FALSE;
|
||||
GSList *doc_comments = IDL_IDENT(declaration->ident).comments;
|
||||
|
||||
/*
|
||||
* Consts must be in an interface
|
||||
*/
|
||||
|
||||
if (!IDL_NODE_UP(IDL_NODE_UP(state->tree)) ||
|
||||
IDL_NODE_TYPE(IDL_NODE_UP(IDL_NODE_UP(state->tree))) !=
|
||||
IDLN_INTERFACE) {
|
||||
|
||||
XPIDL_WARNING((state->tree, IDL_WARNING1,
|
||||
"A constant \"%s\" was declared outside an interface."
|
||||
" It was ignored.", name));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure this is a numeric short or long constant.
|
||||
*/
|
||||
|
||||
success = (IDLN_TYPE_INTEGER == IDL_NODE_TYPE(declaration->const_type));
|
||||
|
||||
if (success) {
|
||||
/*
|
||||
* We aren't successful yet, we know it's an integer, but what *kind*
|
||||
* of integer?
|
||||
*/
|
||||
|
||||
switch(IDL_TYPE_INTEGER(declaration->const_type).f_type) {
|
||||
|
||||
case IDL_INTEGER_TYPE_SHORT:
|
||||
/*
|
||||
* We're OK
|
||||
*/
|
||||
isshort = TRUE;
|
||||
break;
|
||||
|
||||
case IDL_INTEGER_TYPE_LONG:
|
||||
/*
|
||||
* We're OK
|
||||
*/
|
||||
break;
|
||||
|
||||
default:
|
||||
/*
|
||||
* Whoops, it's some other kind of number
|
||||
*/
|
||||
|
||||
success = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (doc_comments != NULL) {
|
||||
fputs(" ", FILENAME(state));
|
||||
printlist(FILENAME(state), doc_comments);
|
||||
}
|
||||
|
||||
if (success) {
|
||||
fputc('\n', FILENAME(state));
|
||||
write_comment(state);
|
||||
|
||||
fprintf(FILENAME(state), " public static final %s %s = %d;\n",
|
||||
(isshort ? "short" : "int"),
|
||||
name, (int) IDL_INTEGER(declaration->const_exp).value);
|
||||
} else {
|
||||
XPIDL_WARNING((state->tree, IDL_WARNING1,
|
||||
"A constant \"%s\" was not of type short or long."
|
||||
" It was ignored.", name));
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
#define ATTR_IDENT(tree) (IDL_IDENT(IDL_LIST(IDL_ATTR_DCL((tree)).simple_declarations).data))
|
||||
#define ATTR_PROPS(tree) (IDL_LIST(IDL_ATTR_DCL((tree)).simple_declarations).data)
|
||||
#define ATTR_TYPE_DECL(tree) (IDL_ATTR_DCL((tree)).param_type_spec)
|
||||
|
||||
|
||||
static gboolean
|
||||
attribute_declaration(TreeState *state)
|
||||
{
|
||||
gboolean read_only = IDL_ATTR_DCL(state->tree).f_readonly;
|
||||
char *attribute_name = ATTR_IDENT(state->tree).str;
|
||||
|
||||
gboolean method_noscript =
|
||||
(IDL_tree_property_get(ATTR_PROPS(state->tree), "noscript") != NULL);
|
||||
GSList *doc_comments =
|
||||
IDL_IDENT(IDL_LIST(IDL_ATTR_DCL
|
||||
(state->tree).simple_declarations).data).comments;
|
||||
|
||||
if (doc_comments != NULL) {
|
||||
fputs(" ", FILENAME(state));
|
||||
printlist(FILENAME(state), doc_comments);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Disabled here because I can't verify this check against possible
|
||||
* users of the java xpidl backend.
|
||||
*/
|
||||
if (!verify_attribute_declaration(state->tree))
|
||||
return FALSE;
|
||||
#endif
|
||||
|
||||
/* Comment */
|
||||
fputc('\n', FILENAME(state));
|
||||
write_comment(state);
|
||||
|
||||
state->tree = ATTR_TYPE_DECL(state->tree);
|
||||
|
||||
/*
|
||||
* Write access permission ("public" unless nonscriptable)
|
||||
*/
|
||||
fputs(" ", FILENAME(state));
|
||||
if (!method_noscript) {
|
||||
fputs("public ", FILENAME(state));
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the proper Java return value for the get operation
|
||||
*/
|
||||
if (!xpcom_to_java_type(state)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the name of the accessor ("get") method.
|
||||
*/
|
||||
fprintf(FILENAME(state), " get%c%s();\n",
|
||||
toupper(attribute_name[0]), attribute_name + 1);
|
||||
|
||||
|
||||
if (!read_only) {
|
||||
/* Nonscriptable methods become package-protected */
|
||||
fputs(" ", FILENAME(state));
|
||||
if (!method_noscript) {
|
||||
fputs("public ", FILENAME(state));
|
||||
}
|
||||
|
||||
/*
|
||||
* Write attribute access method name and return type
|
||||
*/
|
||||
fprintf(FILENAME(state), "void set%c%s(",
|
||||
toupper(attribute_name[0]),
|
||||
attribute_name+1);
|
||||
|
||||
/*
|
||||
* Write the proper Java type for the set operation
|
||||
*/
|
||||
if (!xpcom_to_java_type(state)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the name of the formal parameter.
|
||||
*/
|
||||
fputs(" value);\n", FILENAME(state));
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
enum_declaration(TreeState *state)
|
||||
{
|
||||
XPIDL_WARNING((state->tree, IDL_WARNING1,
|
||||
"enums not supported, enum \'%s\' ignored",
|
||||
IDL_IDENT(IDL_TYPE_ENUM(state->tree).ident).str));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
module_declaration(TreeState *state)
|
||||
{
|
||||
// do not use modules yet
|
||||
#if 0
|
||||
IDL_tree scope =
|
||||
IDL_tree_get_scope(state->tree);
|
||||
|
||||
char *module_name = IDL_IDENT(IDL_MODULE(state->tree).ident).str;
|
||||
printf("\n\n I've go a module declared!!! \n name: %s \n\n",
|
||||
module_name);
|
||||
|
||||
fprintf(FILENAME(state), "package %s;\n", module_name);
|
||||
state->tree = IDL_MODULE(state->tree).definition_list;
|
||||
|
||||
type = IDL_NODE_TYPE(state->tree);
|
||||
printf("\n type: %d\n\n", type);
|
||||
|
||||
return process_list(state);
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
backend *
|
||||
xpidl_java_dispatch(void)
|
||||
{
|
||||
static backend result;
|
||||
static nodeHandler table[IDLN_LAST];
|
||||
static gboolean initialized = FALSE;
|
||||
|
||||
result.emit_prolog = java_prolog;
|
||||
result.emit_epilog = java_epilog;
|
||||
|
||||
if (!initialized) {
|
||||
table[IDLN_INTERFACE] = interface_declaration;
|
||||
table[IDLN_LIST] = process_list;
|
||||
|
||||
table[IDLN_OP_DCL] = method_declaration;
|
||||
table[IDLN_ATTR_DCL] = attribute_declaration;
|
||||
table[IDLN_CONST_DCL] = constant_declaration;
|
||||
|
||||
table[IDLN_TYPE_DCL] = type_declaration;
|
||||
/* table[IDLN_FORWARD_DCL] = forward_declaration;*/
|
||||
|
||||
table[IDLN_TYPE_ENUM] = enum_declaration;
|
||||
/* table[IDLN_MODULE] = module_declaration;*/
|
||||
|
||||
initialized = TRUE;
|
||||
}
|
||||
|
||||
result.dispatch_table = table;
|
||||
return &result;
|
||||
}
|
||||
|
||||
void write_comment(TreeState *state)
|
||||
{
|
||||
fprintf(FILENAME(state), " /* ");
|
||||
IDL_tree_to_IDL(state->tree, state->ns, FILENAME(state),
|
||||
IDLF_OUTPUT_NO_NEWLINES |
|
||||
IDLF_OUTPUT_NO_QUALIFY_IDENTS |
|
||||
IDLF_OUTPUT_PROPERTIES);
|
||||
fputs(" */\n", FILENAME(state));
|
||||
}
|
Загрузка…
Ссылка в новой задаче