Fix for bug 84186. r=dbradley, jag. sr=jband. Added support for CStrings, UTF8String, and AStrings to XPIDL. Also added the -t cmd line flag to XPIDL and XPTLINK that allows us to generate output for a specific XPT version. The XPT version number is being upped from 1.1 to 1.2 with this checkin.

This commit is contained in:
nisheeth%netscape.com 2002-02-26 01:41:42 +00:00
parent 86c5368302
commit 46db685f9a
21 changed files with 831 additions and 81 deletions

View File

@ -99,9 +99,9 @@ static uint8 xpc_reflectable_flags[XPC_FLAG_COUNT] = {
XPC_MK_FLAG( 0 , 1 , 0 , 1 ), /* T_ARRAY */
XPC_MK_FLAG( 0 , 1 , 0 , 1 ), /* T_PSTRING_SIZE_IS */
XPC_MK_FLAG( 0 , 1 , 0 , 1 ), /* T_PWSTRING_SIZE_IS */
XPC_MK_FLAG( 0 , 0 , 0 , 0 ), /* 23 - reserved */
XPC_MK_FLAG( 0 , 0 , 0 , 0 ), /* 24 - reserved */
XPC_MK_FLAG( 0 , 0 , 0 , 0 ), /* 25 - reserved */
XPC_MK_FLAG( 0 , 1 , 0 , 0 ), /* T_UTF8STRING */
XPC_MK_FLAG( 0 , 1 , 0 , 0 ), /* T_CSTRING */
XPC_MK_FLAG( 0 , 1 , 0 , 0 ), /* T_ASTRING */
XPC_MK_FLAG( 0 , 0 , 0 , 0 ), /* 26 - reserved */
XPC_MK_FLAG( 0 , 0 , 0 , 0 ), /* 27 - reserved */
XPC_MK_FLAG( 0 , 0 , 0 , 0 ), /* 28 - reserved */
@ -110,6 +110,8 @@ static uint8 xpc_reflectable_flags[XPC_FLAG_COUNT] = {
XPC_MK_FLAG( 0 , 0 , 0 , 0 ) /* 31 - reserved */
};
static intN sXPCOMUCStringFinalizerIndex = -1;
/***********************************************************/
// static
@ -199,6 +201,40 @@ JAM_DOUBLE(JSContext *cx, double v, jsdouble *dbl)
#define FIT_U32(cx,i,d) ((i) <= JSVAL_INT_MAX ? \
INT_TO_JSVAL(i) : JAM_DOUBLE(cx,i,d))
JS_STATIC_DLL_CALLBACK(void)
FinalizeXPCOMUCString(JSContext *cx, JSString *str)
{
NS_ASSERTION(sXPCOMUCStringFinalizerIndex != -1,
"XPCConvert: XPCOM Unicode string finalizer called uninitialized!");
PRUnichar* buffer = JS_GetStringChars(str);
nsMemory::Free(buffer);
}
static JSBool
AddXPCOMUCStringFinalizer()
{
sXPCOMUCStringFinalizerIndex =
JS_AddExternalStringFinalizer(FinalizeXPCOMUCString);
if (sXPCOMUCStringFinalizerIndex == -1)
{
return JS_FALSE;
}
return JS_TRUE;
}
//static
void
XPCConvert::RemoveXPCOMUCStringFinalizer()
{
JS_RemoveExternalStringFinalizer(FinalizeXPCOMUCString);
sXPCOMUCStringFinalizerIndex = -1;
}
// static
JSBool
XPCConvert::NativeData2JS(XPCCallContext& ccx, jsval* d, const void* s,
@ -283,6 +319,9 @@ XPCConvert::NativeData2JS(XPCCallContext& ccx, jsval* d, const void* s,
break;
}
case nsXPTType::T_ASTRING:
// Fall through to T_DOMSTRING case
case nsXPTType::T_DOMSTRING:
{
const nsAReadableString* p = *((const nsAReadableString**)s);
@ -337,6 +376,69 @@ XPCConvert::NativeData2JS(XPCCallContext& ccx, jsval* d, const void* s,
*d = STRING_TO_JSVAL(str);
break;
}
case nsXPTType::T_UTF8STRING:
{
const nsAReadableCString* cString = *((const nsAReadableCString**)s);
if(!cString)
break;
if(!cString->IsVoid())
{
// XXX There is an extra copy happening here. When the
// UTF8String implementation lands, it should contain
// a mechanism to avoid this extra copy. Jag will change
// this code to use that new mechanism when he lands the
// UTF8String changes.
NS_ConvertUTF8toUCS2 unicodeString(*cString);
JSString* jsString = JS_NewUCStringCopyN(cx,
NS_CONST_CAST(jschar*,
unicodeString.get()),
unicodeString.Length());
if(!jsString)
return JS_FALSE;
*d = STRING_TO_JSVAL(jsString);
}
break;
}
case nsXPTType::T_CSTRING:
{
const nsAReadableCString* cString = *((const nsAReadableCString**)s);
if(!cString)
break;
if(!cString->IsVoid())
{
PRUnichar* unicodeString = ToNewUnicode(*cString);
if(!unicodeString)
return JS_FALSE;
if(sXPCOMUCStringFinalizerIndex == -1 &&
!AddXPCOMUCStringFinalizer())
return JS_FALSE;
JSString* jsString = JS_NewExternalString(cx,
unicodeString,
cString->Length(),
sXPCOMUCStringFinalizerIndex);
if(!jsString)
{
nsMemory::Free(unicodeString);
return JS_FALSE;
}
*d = STRING_TO_JSVAL(jsString);
}
break;
}
case nsXPTType::T_INTERFACE:
case nsXPTType::T_INTERFACE_IS:
@ -379,6 +481,7 @@ XPCConvert::NativeData2JS(XPCCallContext& ccx, jsval* d, const void* s,
}
/***************************************************************************/
// static
JSBool
XPCConvert::JSData2Native(XPCCallContext& ccx, void* d, jsval s,
@ -393,6 +496,7 @@ XPCConvert::JSData2Native(XPCCallContext& ccx, void* d, jsval s,
int32 ti;
uint32 tu;
jsdouble td;
JSBool isDOMString = JS_TRUE;
if(pErr)
*pErr = NS_ERROR_XPC_BAD_CONVERT_JS;
@ -549,6 +653,11 @@ XPCConvert::JSData2Native(XPCCallContext& ccx, void* d, jsval s,
return JS_TRUE;
}
case nsXPTType::T_ASTRING:
{
isDOMString = JS_FALSE;
// Fall through to T_DOMSTRING case.
}
case nsXPTType::T_DOMSTRING:
{
static const NS_NAMED_LITERAL_STRING(sEmptyString, "");
@ -560,10 +669,18 @@ XPCConvert::JSData2Native(XPCCallContext& ccx, void* d, jsval s,
PRUint32 length;
if(JSVAL_IS_VOID(s))
{
if(isDOMString)
{
chars = sVoidString.get();
length = sVoidString.Length();
}
else
{
chars = sEmptyString.get();
length = 0;
}
}
else if(!JSVAL_IS_NULL(s))
{
str = JS_ValueToString(cx, s);
@ -623,7 +740,7 @@ XPCConvert::JSData2Native(XPCCallContext& ccx, void* d, jsval s,
{
nsAWritableString* ws = *((nsAWritableString**)d);
if(JSVAL_IS_NULL(s))
if(JSVAL_IS_NULL(s) || (!isDOMString && JSVAL_IS_VOID(s)))
{
ws->Truncate();
ws->SetIsVoid(PR_TRUE);
@ -726,6 +843,116 @@ XPCConvert::JSData2Native(XPCCallContext& ccx, void* d, jsval s,
return JS_TRUE;
}
case nsXPTType::T_UTF8STRING:
{
jschar* chars;
PRUint32 length;
JSString* str;
if(JSVAL_IS_NULL(s) || JSVAL_IS_VOID(s))
{
if(useAllocator)
{
nsACString *rs = new nsCString();
if(!rs)
return JS_FALSE;
rs->SetIsVoid(PR_TRUE);
*((nsACString**)d) = rs;
}
else
{
nsCString* rs = *((nsCString**)d);
rs->Truncate();
rs->SetIsVoid(PR_TRUE);
}
return JS_TRUE;
}
// The JS val is neither null nor void...
if(!(str = JS_ValueToString(cx, s))||
!(chars = JS_GetStringChars(str)))
{
return JS_FALSE;
}
length = JS_GetStringLength(str);
if(useAllocator)
{
nsAReadableCString *rs = new NS_ConvertUCS2toUTF8(chars, length);
if(!rs)
return JS_FALSE;
*((nsAReadableCString**)d) = rs;
}
else
{
nsCString* rs = *((nsCString**)d);
// XXX This code needs to change when Jag lands the new
// UTF8String implementation. Adopt() is a method that
// shouldn't be used by string consumers.
rs->Adopt(ToNewUTF8String(nsDependentString(chars, length)));
}
return JS_TRUE;
}
case nsXPTType::T_CSTRING:
{
const char* chars;
PRUint32 length;
JSString* str;
if(JSVAL_IS_NULL(s) || JSVAL_IS_VOID(s))
{
if(useAllocator)
{
nsACString *rs = new nsCString();
if(!rs)
return JS_FALSE;
rs->SetIsVoid(PR_TRUE);
*((nsACString**)d) = rs;
}
else
{
nsACString* rs = *((nsACString**)d);
rs->Truncate();
rs->SetIsVoid(PR_TRUE);
}
return JS_TRUE;
}
// The JS val is neither null nor void...
if(!(str = JS_ValueToString(cx, s)) ||
!(chars = JS_GetStringBytes(str)))
{
return JS_FALSE;
}
length = JS_GetStringLength(str);
if(useAllocator)
{
nsAReadableCString *rs = new nsCString(chars, length);
if(!rs)
return JS_FALSE;
*((nsAReadableCString**)d) = rs;
}
else
{
nsACString* rs = *((nsACString**)d);
rs->Assign(nsDependentCString(chars, length));
}
return JS_TRUE;
}
case nsXPTType::T_INTERFACE:
case nsXPTType::T_INTERFACE_IS:
{
@ -1372,6 +1599,9 @@ XPCConvert::NativeArray2JS(XPCCallContext& ccx,
case nsXPTType::T_WCHAR_STR : POPULATE(jschar*); break;
case nsXPTType::T_INTERFACE : POPULATE(nsISupports*); break;
case nsXPTType::T_INTERFACE_IS : POPULATE(nsISupports*); break;
case nsXPTType::T_UTF8STRING : NS_ASSERTION(0,"bad type"); goto failure;
case nsXPTType::T_CSTRING : NS_ASSERTION(0,"bad type"); goto failure;
case nsXPTType::T_ASTRING : NS_ASSERTION(0,"bad type"); goto failure;
default : NS_ASSERTION(0,"bad type"); goto failure;
}
@ -1501,6 +1731,9 @@ fill_array:
case nsXPTType::T_WCHAR_STR : POPULATE(fr, jschar*); break;
case nsXPTType::T_INTERFACE : POPULATE(re, nsISupports*); break;
case nsXPTType::T_INTERFACE_IS : POPULATE(re, nsISupports*); break;
case nsXPTType::T_UTF8STRING : NS_ASSERTION(0,"bad type"); goto failure;
case nsXPTType::T_CSTRING : NS_ASSERTION(0,"bad type"); goto failure;
case nsXPTType::T_ASTRING : NS_ASSERTION(0,"bad type"); goto failure;
default : NS_ASSERTION(0,"bad type"); goto failure;
}

View File

@ -718,6 +718,8 @@ XPCJSRuntime::~XPCJSRuntime()
// unwire the readable/JSString sharing magic
XPCStringConvert::ShutdownDOMStringFinalizer();
XPCConvert::RemoveXPCOMUCStringFinalizer();
}
XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect,

View File

@ -2244,6 +2244,8 @@ public:
nsISupports* data,
nsIException** exception);
static void RemoveXPCOMUCStringFinalizer();
private:
XPCConvert(); // not implemented

View File

@ -1789,6 +1789,9 @@ XPCWrappedNative::CallMethod(XPCCallContext& ccx,
useAllocator = JS_TRUE;
break;
case nsXPTType::T_ASTRING:
// Fall through to the T_DOMSTRING case
case nsXPTType::T_DOMSTRING:
if(paramInfo.IsDipper())
{
@ -1823,6 +1826,25 @@ XPCWrappedNative::CallMethod(XPCCallContext& ccx,
dp->SetValIsDOMString();
useAllocator = JS_TRUE;
break;
case nsXPTType::T_UTF8STRING:
// Fall through to the C string case for now...
case nsXPTType::T_CSTRING:
dp->SetValIsCString();
if(paramInfo.IsDipper())
{
// Is an 'out' CString.
if(!(dp->val.p = new nsCString()))
{
JS_ReportOutOfMemory(ccx);
goto done;
}
continue;
}
// else ...
// Is an 'in' CString.
useAllocator = JS_TRUE;
break;
}
}
@ -2167,6 +2189,10 @@ done:
((nsISupports*)p)->Release();
else if(dp->IsValDOMString())
delete (nsAString*)p;
else if(dp->IsValUTF8String())
delete (nsCString*) p;
else if(dp->IsValCString())
delete (nsCString*) p;
}
}

View File

@ -122,6 +122,58 @@ NS_IMETHODIMP xpctestEcho::EchoIn2OutOneDOMString(const nsAReadableString & inpu
return NS_OK;
}
/* AString In2OutOneAString (in AString input); */
NS_IMETHODIMP xpctestEcho::In2OutOneAString(const nsAString & input,
nsAString & _retval)
{
_retval.Assign(input);
return NS_OK;
}
/* AString EchoIn2OutOneAString (in AString input); */
NS_IMETHODIMP xpctestEcho::EchoIn2OutOneAString(const nsAString & input, nsAString & _retval)
{
if(mReceiver)
return mReceiver->EchoIn2OutOneAString(input, _retval);
return NS_OK;
}
/* UTF8String In2OutOneUTF8String (in UTF8String input); */
NS_IMETHODIMP xpctestEcho::In2OutOneUTF8String(const nsACString & input,
nsACString & _retval)
{
_retval.Assign(input);
return NS_OK;
}
/* UTF8String EchoIn2OutOneUTF8String (in UTF8String input); */
NS_IMETHODIMP xpctestEcho::EchoIn2OutOneUTF8String(const nsACString & input,
nsACString & _retval)
{
if(mReceiver)
return mReceiver->EchoIn2OutOneUTF8String(input, _retval);
return NS_OK;
}
/* CString In2OutOneCString (in CString input); */
NS_IMETHODIMP xpctestEcho::In2OutOneCString(const nsACString & input,
nsACString & _retval)
{
_retval.Assign(input);
return NS_OK;
}
/* CString EchoIn2OutOneCString (in CString input); */
NS_IMETHODIMP xpctestEcho::EchoIn2OutOneCString(const nsACString & input,
nsACString & _retval)
{
if(mReceiver)
return mReceiver->EchoIn2OutOneCString(input, _retval);
return NS_OK;
}
NS_IMETHODIMP xpctestEcho::In2OutAddTwoInts(int input1,
int input2,
int* output1,

View File

@ -66,7 +66,6 @@ interface nsITestXPCFoo2 : nsITestXPCFoo {
[scriptable, uuid(CD2F2F40-C5D9-11d2-9838-006008962422)]
interface nsIEcho : nsISupports {
void SetReceiver(in nsIEcho aReceiver);
void SendOneString(in string str);
long In2OutOneInt(in long input);
@ -79,6 +78,15 @@ interface nsIEcho : nsISupports {
DOMString In2OutOneDOMString(in DOMString input);
DOMString EchoIn2OutOneDOMString(in DOMString input);
AString In2OutOneAString(in AString input);
AString EchoIn2OutOneAString(in AString input);
AUTF8String In2OutOneUTF8String(in AUTF8String input);
AUTF8String EchoIn2OutOneUTF8String(in AUTF8String input);
ACString In2OutOneCString(in ACString input);
ACString EchoIn2OutOneCString(in ACString input);
void SimpleCallNoEcho();
void SendManyTypes(in octet p1,
in short p2,

View File

@ -76,6 +76,24 @@ receiver.EchoIn2OutOneDOMString = function(input)
return input;
};
receiver.EchoIn2OutOneAString = function(input)
{
// print("EchoIn2OutOneAString called with: "+input);
return input;
};
receiver.EchoIn2OutOneUTF8String = function(input)
{
// print("EchoIn2OutOneUTF8String called with: "+input);
return input;
}
receiver.EchoIn2OutOneCString = function(input)
{
// print("EchoIn2OutOneCString called with: "+input);
return input;
}
echo.SetReceiver(receiver);
////////////////////
@ -224,6 +242,7 @@ if(all_ok)
print("SendInOutManyTypes - passed");
////////////////////
// Test DOMString
var test_string3 = "And this is yet again some other string 3";
var test_string4 = "And this is yet again some other string 4";
@ -248,6 +267,78 @@ print("EchoIn2OutOneDOMString of undefined - "+(
echo.EchoIn2OutOneDOMString(this.propertyThatDoesNotExist) == "undefined"
? "passed" : "failed"));
/////////////////////
// Test AString
print("In2OutOneAString - "+(
echo.In2OutOneAString(test_string3) == test_string3
? "passed" : "failed"));
print("EchoIn2OutOneAString - "+(
echo.EchoIn2OutOneAString(test_string4) == test_string4
? "passed" : "failed"));
print("EchoIn2OutOneAString of empty string - "+(
echo.EchoIn2OutOneAString("") == ""
? "passed" : "failed"));
print("EchoIn2OutOneAString of null - "+(
echo.EchoIn2OutOneAString(null) == null
? "passed" : "failed"));
print("EchoIn2OutOneAString of undefined - "+(
echo.EchoIn2OutOneAString(this.propertyThatDoesNotExist) == ""
? "passed" : "failed"));
/////////////////////
// Test AUTF8String
var test_utf8String =
"Non-Ascii 1 byte chars: éâäàåç, 2 byte chars: \u1234 \u1235 \u1236";
print("In2OutOneUTF8String - "+(
echo.In2OutOneUTF8String(test_utf8String) == test_utf8String
? "passed" : "failed"));
print("EchoIn2OutOneUTF8String - "+(
echo.EchoIn2OutOneUTF8String(test_utf8String) == test_utf8String
? "passed" : "failed"));
print("EchoIn2OutOneUTF8String of empty string - "+(
echo.EchoIn2OutOneUTF8String("") == ""
? "passed" : "failed"));
print("EchoIn2OutOneUTF8String of null - "+(
echo.EchoIn2OutOneUTF8String(null) == null
? "passed" : "failed"));
print("EchoIn2OutOneUTF8String of undefined - "+(
echo.EchoIn2OutOneUTF8String(this.propertyThatDoesNotExist) == ""
? "passed" : "failed"));
/////////////////////
// Test ACString
print("In2OutOneCString - "+(
echo.In2OutOneCString(test_string3) == test_string3
? "passed" : "failed"));
print("EchoIn2OutOneCString - "+(
echo.EchoIn2OutOneCString(test_string4) == test_string4
? "passed" : "failed"));
print("EchoIn2OutOneCString of empty string - "+(
echo.EchoIn2OutOneCString("") == ""
? "passed" : "failed"));
print("EchoIn2OutOneCString of null - "+(
echo.EchoIn2OutOneCString(null) == null
? "passed" : "failed"));
print("EchoIn2OutOneCString of undefined - "+(
echo.EchoIn2OutOneCString(this.propertyThatDoesNotExist) == ""
? "passed" : "failed"));
////////////////////
// check exceptions on xpcom error code

View File

@ -102,9 +102,17 @@ typedef unsigned long size_t;
[ref, domstring] native DOMStringRef(ignored);
[ptr, domstring] native DOMStringPtr(ignored);
[ref, domstring] native AString(ignored);
[ref, domstring] native AStringRef(ignored);
[ptr, domstring] native AStringPtr(ignored);
[ref, utf8string] native AUTF8String(ignored);
[ref, utf8string] native AUTF8StringRef(ignored);
[ptr, utf8string] native AUTF8StringPtr(ignored);
[ref, cstring] native ACString(ignored);
[ref, cstring] native ACStringRef(ignored);
[ptr, cstring] native ACStringPtr(ignored);
[ref, astring] native AString(ignored);
[ref, astring] native AStringRef(ignored);
[ptr, astring] native AStringPtr(ignored);
%{C++
/*

View File

@ -117,7 +117,9 @@ struct nsXPTCVariant : public nsXPTCMiniVariant
VAL_IS_ALLOCD = 0x2, // val.p holds alloc'd ptr that must be freed
VAL_IS_IFACE = 0x4, // val.p holds interface ptr that must be released
VAL_IS_ARRAY = 0x8, // val.p holds a pointer to an array needing cleanup
VAL_IS_DOMSTR= 0x10 // val.p holds a pointer to domstring needing cleanup
VAL_IS_DOMSTR = 0x10, // val.p holds a pointer to domstring needing cleanup
VAL_IS_UTF8STR = 0x20, // val.p holds a pointer to utf8string needing cleanup
VAL_IS_CSTR = 0x40 // val.p holds a pointer to cstring needing cleanup
};
void ClearFlags() {flags = 0;}
@ -126,12 +128,16 @@ struct nsXPTCVariant : public nsXPTCMiniVariant
void SetValIsInterface() {flags |= VAL_IS_IFACE;}
void SetValIsArray() {flags |= VAL_IS_ARRAY;}
void SetValIsDOMString() {flags |= VAL_IS_DOMSTR;}
void SetValIsUTF8String() {flags |= VAL_IS_UTF8STR;}
void SetValIsCString() {flags |= VAL_IS_CSTR;}
PRBool IsPtrData() const {return 0 != (flags & PTR_IS_DATA);}
PRBool IsValAllocated() const {return 0 != (flags & VAL_IS_ALLOCD);}
PRBool IsValInterface() const {return 0 != (flags & VAL_IS_IFACE);}
PRBool IsValArray() const {return 0 != (flags & VAL_IS_ARRAY);}
PRBool IsValDOMString() const {return 0 != (flags & VAL_IS_DOMSTR);}
PRBool IsValUTF8String() const {return 0 != (flags & VAL_IS_UTF8STR);}
PRBool IsValCString() const {return 0 != (flags & VAL_IS_CSTR);}
void Init(const nsXPTCMiniVariant& mv, const nsXPTType& t, PRUint8 f)
{
@ -170,6 +176,8 @@ struct nsXPTCVariant : public nsXPTCMiniVariant
case nsXPTType::T_ARRAY: /* fall through */
case nsXPTType::T_PSTRING_SIZE_IS: /* fall through */
case nsXPTType::T_PWSTRING_SIZE_IS: /* fall through */
case nsXPTType::T_UTF8STRING: /* fall through */
case nsXPTType::T_CSTRING: /* fall through */
default: val.p = mv.val.p; break;
}
}

View File

@ -75,6 +75,9 @@ TypesArray dd t_Int4Bytes ; nsXPTType::T_I8
dd t_Int4Bytes ; TD_ARRAY
dd t_Int4Bytes ; TD_PSTRING_SIZE_IS
dd t_Int4Bytes ; TD_PWSTRING_SIZE_IS
dd t_Int4Bytes ; TD_UTF8STRING
dd t_Int4Bytes ; TD_CSTRING
dd t_Int4Bytes ; TD_ASTRING
; All other values default to 4 byte int/ptr

View File

@ -176,7 +176,10 @@ public:
T_INTERFACE_IS = TD_INTERFACE_IS_TYPE,
T_ARRAY = TD_ARRAY ,
T_PSTRING_SIZE_IS = TD_PSTRING_SIZE_IS ,
T_PWSTRING_SIZE_IS = TD_PWSTRING_SIZE_IS
T_PWSTRING_SIZE_IS = TD_PWSTRING_SIZE_IS ,
T_UTF8STRING = TD_UTF8STRING ,
T_CSTRING = TD_CSTRING ,
T_ASTRING = TD_ASTRING
};
// NO DATA - this a flyweight wrapper
};

View File

@ -66,12 +66,17 @@ gboolean verbose_mode = FALSE;
gboolean emit_typelib_annotations = FALSE;
gboolean explicit_output_filename = FALSE;
/* The following globals are explained in xpt_struct.h */
PRUint8 major_version = XPT_MAJOR_VERSION;
PRUint8 minor_version = XPT_MINOR_VERSION;
static char xpidl_usage_str[] =
"Usage: %s [-m mode] [-w] [-v]\n"
"Usage: %s [-m mode] [-w] [-v] [-t version number]\n"
" [-I path] [-o basename | -e filename.ext] filename.idl\n"
" -a emit annotations to typelib\n"
" -w turn on warnings (recommended)\n"
" -v verbose mode (NYI)\n"
" -t create a typelib of a specific version number\n"
" -I add entry to start of include path for ``#include \"nsIThing.idl\"''\n"
" -o use basename (e.g. ``/tmp/nsIThing'') for output\n"
" -e use explicit output filename\n"
@ -99,6 +104,7 @@ int main(int argc, char *argv[])
IncludePathEntry *inc, *inc_head, **inc_tail;
char *file_basename = NULL;
ModeData *mode = NULL;
gboolean create_old_typelib = FALSE;
/* turn this on for extra checking of our code */
/* IDL_check_cast_enable(TRUE); */
@ -130,6 +136,58 @@ int main(int argc, char *argv[])
case 'v':
verbose_mode = TRUE;
break;
case 't':
{
/* Parse for "-t version number" and store it into global boolean
* and string variables.
*/
const gchar* typelib_version_string = NULL;
/*
* If -t is the last argument on the command line, we have a problem
*/
if (i + 1 == argc) {
fprintf(stderr, "ERROR: missing version number after -t\n");
xpidl_usage(argc, argv);
return 1;
}
/* Do not allow more than one "-t" definition */
if (create_old_typelib) {
fprintf(stderr,
"ERROR: -t argument used twice. "
"Cannot specify more than one version\n");
xpidl_usage(argc, argv);
return 1;
}
/*
* Assume that the argument after "-t" is the version number string
* and search for it in our internal list of acceptable version
* numbers.
*/
switch (XPT_ParseVersionString(argv[++i], &major_version,
&minor_version)) {
case XPT_VERSION_CURRENT:
break;
case XPT_VERSION_OLD:
create_old_typelib = TRUE;
break;
case XPT_VERSION_UNSUPPORTED:
fprintf(stderr, "ERROR: version \"%s\" not supported.\n",
argv[i]);
xpidl_usage(argc, argv);
return 1;
case XPT_VERSION_UNKNOWN:
default:
fprintf(stderr, "ERROR: version \"%s\" not recognised.\n",
argv[i]);
xpidl_usage(argc, argv);
return 1;
}
break;
}
case 'I':
if (argv[i][2] == '\0' && i == argc) {
fputs("ERROR: missing path after -I\n", stderr);
@ -170,7 +228,7 @@ int main(int argc, char *argv[])
explicit_output_filename = TRUE;
break;
case 'm':
if (i == argc) {
if (i + 1 == argc) {
fprintf(stderr, "ERROR: missing modename after -m\n");
xpidl_usage(argc, argv);
return 1;
@ -190,7 +248,6 @@ int main(int argc, char *argv[])
return 1;
}
break;
default:
fprintf(stderr, "unknown option %s\n", argv[i]);
xpidl_usage(argc, argv);

View File

@ -55,6 +55,8 @@
#include <IDL.h>
#endif
#include <xpt_struct.h>
/*
* IDL_tree_warning bombs on libIDL version 6.5, and I don't want to not write
* warnings... so I define a versioned one here. Thanks to Mike Shaver for the
@ -84,6 +86,9 @@ extern gboolean verbose_mode;
extern gboolean emit_typelib_annotations;
extern gboolean explicit_output_filename;
extern PRUint8 major_version;
extern PRUint8 minor_version;
typedef struct TreeState TreeState;
/*
@ -178,7 +183,6 @@ xpidl_write_comment(TreeState *state, int indent);
/*
* Functions for parsing and printing UUIDs.
*/
#include <xpt_struct.h>
/*
* How large should the buffer supplied to xpidl_sprint_IID be?
@ -219,7 +223,10 @@ xpidl_parse_iid(nsID *id, const char *str);
UP_IS_AGGREGATE(node)))
#define DIPPER_TYPE(node) \
(NULL != IDL_tree_property_get(node, "domstring"))
(NULL != IDL_tree_property_get(node, "domstring") || \
NULL != IDL_tree_property_get(node, "utf8string") || \
NULL != IDL_tree_property_get(node, "cstring") || \
NULL != IDL_tree_property_get(node, "astring"))
/*
* Find the underlying type of an identifier typedef. Returns NULL

View File

@ -682,8 +682,13 @@ write_type(IDL_tree type_tree, gboolean is_out, FILE *outfile)
break;
case IDLN_IDENT:
if (UP_IS_NATIVE(type_tree)) {
if (IDL_tree_property_get(type_tree, "domstring")) {
if (IDL_tree_property_get(type_tree, "domstring") ||
IDL_tree_property_get(type_tree, "astring")) {
fputs("nsAString", outfile);
} else if (IDL_tree_property_get(type_tree, "utf8string")) {
fputs("nsACString", outfile);
} else if (IDL_tree_property_get(type_tree, "cstring")) {
fputs("nsACString", outfile);
} else {
fputs(IDL_NATIVE(IDL_NODE_UP(type_tree)).user_type, outfile);
}
@ -740,13 +745,17 @@ write_attr_accessor(IDL_tree attr_tree, FILE * outfile,
getter ? 'G' : 'S',
toupper(*attrname), attrname + 1);
if (mode == AS_DECL || mode == AS_IMPL) {
/* Setters for string, wstring, nsid, and domstring get const.
/* Setters for string, wstring, nsid, domstring, utf8string,
* cstring and astring get const.
*/
if (!getter &&
(IDL_NODE_TYPE(ATTR_TYPE_DECL(attr_tree)) == IDLN_TYPE_STRING ||
IDL_NODE_TYPE(ATTR_TYPE_DECL(attr_tree)) == IDLN_TYPE_WIDE_STRING ||
IDL_tree_property_get(ATTR_TYPE_DECL(attr_tree), "nsid") ||
IDL_tree_property_get(ATTR_TYPE_DECL(attr_tree), "domstring")))
IDL_tree_property_get(ATTR_TYPE_DECL(attr_tree), "domstring") ||
IDL_tree_property_get(ATTR_TYPE_DECL(attr_tree), "utf8string") ||
IDL_tree_property_get(ATTR_TYPE_DECL(attr_tree), "cstring") ||
IDL_tree_property_get(ATTR_TYPE_DECL(attr_tree), "astring")))
{
fputs("const ", outfile);
}
@ -911,8 +920,8 @@ write_param(IDL_tree param_tree, FILE *outfile)
{
IDL_tree param_type_spec = IDL_PARAM_DCL(param_tree).param_type_spec;
gboolean is_in = IDL_PARAM_DCL(param_tree).attr == IDL_PARAM_IN;
/* in string, wstring, nsid, domstring, and any
* explicitly marked [const] are const
/* in string, wstring, nsid, domstring, utf8string, cstring and
* astring any explicitly marked [const] are const
*/
if (is_in &&
@ -921,7 +930,10 @@ write_param(IDL_tree param_tree, FILE *outfile)
IDL_tree_property_get(IDL_PARAM_DCL(param_tree).simple_declarator,
"const") ||
IDL_tree_property_get(param_type_spec, "nsid") ||
IDL_tree_property_get(param_type_spec, "domstring"))) {
IDL_tree_property_get(param_type_spec, "domstring") ||
IDL_tree_property_get(param_type_spec, "utf8string") ||
IDL_tree_property_get(param_type_spec, "cstring") ||
IDL_tree_property_get(param_type_spec, "astring"))) {
fputs("const ", outfile);
}
else if (IDL_PARAM_DCL(param_tree).attr == IDL_PARAM_OUT &&

View File

@ -371,7 +371,8 @@ typelib_prolog(TreeState *state)
/* find all interfaces, top-level and referenced by others */
IDL_tree_walk_in_order(state->tree, find_interfaces, state);
ARENA(state) = XPT_NewArena(1024, sizeof(double), "main xpidl arena");
HEADER(state) = XPT_NewHeader(ARENA(state), IFACES(state));
HEADER(state) = XPT_NewHeader(ARENA(state), IFACES(state),
major_version, minor_version);
/* fill IDEs from hash table */
IFACES(state) = 0;
@ -861,6 +862,18 @@ handle_iid_is:
td->prefix.flags = TD_DOMSTRING | XPT_TDP_POINTER;
if (IDL_tree_property_get(type, "ref"))
td->prefix.flags |= XPT_TDP_REFERENCE;
} else if (IDL_tree_property_get(type, "astring")) {
td->prefix.flags = TD_ASTRING | XPT_TDP_POINTER;
if (IDL_tree_property_get(type, "ref"))
td->prefix.flags |= XPT_TDP_REFERENCE;
} else if (IDL_tree_property_get(type, "utf8string")) {
td->prefix.flags = TD_UTF8STRING | XPT_TDP_POINTER;
if (IDL_tree_property_get(type, "ref"))
td->prefix.flags |= XPT_TDP_REFERENCE;
} else if (IDL_tree_property_get(type, "cstring")) {
td->prefix.flags = TD_CSTRING | XPT_TDP_POINTER;
if (IDL_tree_property_get(type, "ref"))
td->prefix.flags |= XPT_TDP_REFERENCE;
} else {
td->prefix.flags = TD_VOID | XPT_TDP_POINTER;
}

View File

@ -220,6 +220,32 @@ verify_const_declaration(IDL_tree const_tree) {
}
/*
* This method consolidates error checking needed when coercing the XPIDL compiler
* via the -t flag to generate output for a specific version of XPConnect.
*/
static gboolean
verify_type_fits_version(IDL_tree in_tree, IDL_tree error_tree)
{
if (major_version == 1 && minor_version == 1)
{
/* XPIDL Version 1.1 checks */
/* utf8string, cstring, and astring types are not supported */
if (IDL_tree_property_get(in_tree, "utf8string") != NULL ||
IDL_tree_property_get(in_tree, "cstring") != NULL ||
IDL_tree_property_get(in_tree, "astring") != NULL)
{
IDL_tree_error(error_tree,
"Cannot use [utf8string], [cstring] and [astring] "
"types when generating version 1.1 typelibs\n");
return FALSE;
}
}
return TRUE;
}
gboolean
verify_attribute_declaration(IDL_tree attr_tree)
{
@ -274,8 +300,8 @@ verify_attribute_declaration(IDL_tree attr_tree)
return TRUE;
/*
* If it should be scriptable, check that the type is non-native. nsid and
* domstring are exempted.
* If it should be scriptable, check that the type is non-native. nsid,
* domstring, utf8string, cstring, astring are exempted.
*/
attr_type = IDL_ATTR_DCL(attr_tree).param_type_spec;
@ -283,7 +309,10 @@ verify_attribute_declaration(IDL_tree attr_tree)
{
if (UP_IS_NATIVE(attr_type) &&
IDL_tree_property_get(attr_type, "nsid") == NULL &&
IDL_tree_property_get(attr_type, "domstring") == NULL)
IDL_tree_property_get(attr_type, "domstring") == NULL &&
IDL_tree_property_get(attr_type, "utf8string") == NULL &&
IDL_tree_property_get(attr_type, "cstring") == NULL &&
IDL_tree_property_get(attr_type, "astring") == NULL)
{
IDL_tree_error(attr_tree,
"attributes in [scriptable] interfaces that are "
@ -310,6 +339,14 @@ verify_attribute_declaration(IDL_tree attr_tree)
"and must be read-only\n");
return FALSE;
}
/*
* Run additional error checks on the attribute type if targetting an
* older version of XPConnect.
*/
if (!verify_type_fits_version(attr_type, attr_tree))
return FALSE;
}
if (IDL_LIST(IDL_ATTR_DCL(attr_tree).simple_declarations).next != NULL)
@ -528,13 +565,17 @@ verify_method_declaration(IDL_tree method_tree)
/*
* Reject this method if it should be scriptable and some parameter is
* native that isn't marked with either nsid, domstring, or iid_is.
* native that isn't marked with either nsid, domstring, utf8string,
* cstring, astring or iid_is.
*/
if (scriptable_method &&
UP_IS_NATIVE(param_type) &&
IDL_tree_property_get(param_type, "nsid") == NULL &&
IDL_tree_property_get(simple_decl, "iid_is") == NULL &&
IDL_tree_property_get(param_type, "domstring") == NULL)
IDL_tree_property_get(param_type, "domstring") == NULL &&
IDL_tree_property_get(param_type, "utf8string") == NULL &&
IDL_tree_property_get(param_type, "cstring") == NULL &&
IDL_tree_property_get(param_type, "astring") == NULL)
{
IDL_tree_error(method_tree,
"methods in [scriptable] interfaces that are "
@ -589,7 +630,7 @@ verify_method_declaration(IDL_tree method_tree)
/*
* Confirm that [shared] attributes are only used with string, wstring,
* or native (but not nsid or domstring)
* or native (but not nsid, domstring, utf8string, cstring or astring)
* and can't be used with [array].
*/
if (IDL_tree_property_get(simple_decl, "shared") != NULL) {
@ -608,7 +649,10 @@ verify_method_declaration(IDL_tree method_tree)
IDL_NODE_TYPE(real_type) == IDLN_TYPE_WIDE_STRING ||
(UP_IS_NATIVE(real_type) &&
!IDL_tree_property_get(real_type, "nsid") &&
!IDL_tree_property_get(real_type, "domstring"))))
!IDL_tree_property_get(real_type, "domstring") &&
!IDL_tree_property_get(real_type, "utf8string") &&
!IDL_tree_property_get(real_type, "cstring") &&
!IDL_tree_property_get(real_type, "astring"))))
{
IDL_tree_error(method_tree,
"[shared] parameter \"%s\" must be of type "
@ -618,27 +662,34 @@ verify_method_declaration(IDL_tree method_tree)
}
/*
* inout is not allowed with "domstring" types
* inout is not allowed with "domstring", "UTF8String", "CString"
* and "AString" types
*/
if (IDL_PARAM_DCL(param).attr == IDL_PARAM_INOUT &&
UP_IS_NATIVE(param_type) &&
IDL_tree_property_get(param_type, "domstring") != NULL) {
(IDL_tree_property_get(param_type, "domstring") != NULL ||
IDL_tree_property_get(param_type, "utf8string") != NULL ||
IDL_tree_property_get(param_type, "cstring") != NULL ||
IDL_tree_property_get(param_type, "astring") != NULL )) {
IDL_tree_error(method_tree,
"[domstring] types cannot be used as inout "
"parameters");
"[domstring], [utf8string], [cstring], [astring] "
"types cannot be used as inout parameters");
return FALSE;
}
/*
* arrays of "domstring" types not allowed
* arrays of domstring, utf8string, cstring, astring types not allowed
*/
if (IDL_tree_property_get(simple_decl, "array") != NULL &&
UP_IS_NATIVE(param_type) &&
IDL_tree_property_get(param_type, "domstring") != NULL) {
(IDL_tree_property_get(param_type, "domstring") != NULL ||
IDL_tree_property_get(param_type, "utf8string") != NULL ||
IDL_tree_property_get(param_type, "cstring") != NULL ||
IDL_tree_property_get(param_type, "astring") != NULL)) {
IDL_tree_error(method_tree,
"[domstring] types cannot be used in array "
"parameters");
"[domstring], [utf8string], [cstring], [astring] "
"types cannot be used in array parameters");
return FALSE;
}
@ -646,6 +697,15 @@ verify_method_declaration(IDL_tree method_tree)
!check_param_attribute(method_tree, param, LENGTH_IS) ||
!check_param_attribute(method_tree, param, SIZE_IS))
return FALSE;
/*
* Run additional error checks on the parameter type if targetting an
* older version of XPConnect.
*/
if (!verify_type_fits_version(param_type, method_tree))
return FALSE;
}
/* XXX q: can return type be nsid? */
@ -653,7 +713,10 @@ verify_method_declaration(IDL_tree method_tree)
if (scriptable_method &&
op->op_type_spec != NULL && UP_IS_NATIVE(op->op_type_spec) &&
IDL_tree_property_get(op->op_type_spec, "nsid") == NULL &&
IDL_tree_property_get(op->op_type_spec, "domstring") == NULL)
IDL_tree_property_get(op->op_type_spec, "domstring") == NULL &&
IDL_tree_property_get(op->op_type_spec, "utf8string") == NULL &&
IDL_tree_property_get(op->op_type_spec, "cstring") == NULL &&
IDL_tree_property_get(op->op_type_spec, "astring") == NULL)
{
IDL_tree_error(method_tree,
"methods in [scriptable] interfaces that are "
@ -662,6 +725,7 @@ verify_method_declaration(IDL_tree method_tree)
return FALSE;
}
/*
* nsid's parameters that aren't ptr's or ref's are not currently
* supported in xpcom
@ -681,6 +745,17 @@ verify_method_declaration(IDL_tree method_tree)
return FALSE;
}
/*
* Run additional error checks on the return type if targetting an
* older version of XPConnect.
*/
if (op->op_type_spec != NULL &&
!verify_type_fits_version(op->op_type_spec, method_tree))
{
return FALSE;
}
return TRUE;
}

View File

@ -116,7 +116,7 @@ struct XPTHeader {
/* For error messages. */
#define XPT_MAGIC_STRING "XPCOM\\nTypeLib\\r\\n\\032"
#define XPT_MAJOR_VERSION 0x01
#define XPT_MINOR_VERSION 0x01
#define XPT_MINOR_VERSION 0x02
/* Any file with a major version number of XPT_MAJOR_INCOMPATIBLE_VERSION
* or higher is to be considered incompatible by this version of xpt and
@ -130,9 +130,66 @@ struct XPTHeader {
*/
#define XPT_MAJOR_INCOMPATIBLE_VERSION 0x02
/*
* The "[-t version number]" cmd line parameter to the XPIDL compiler and XPT
* linker specifies the major and minor version number of the output
* type library.
*
* The goal is for the compiler to check that the input IDL file only uses
* constructs that are supported in the version specified. The linker will
* check that all typelib files it reads are of the version specified or
* below.
*
* Both the compiler and the linker will report errors and abort if these
* checks fail.
*
* When you rev up major or minor versions of the type library in the future,
* think about the new stuff that you added to the type library and add checks
* to make sure that occurrences of that new "stuff" will get caught when [-t
* version number] is used with the compiler. Here's what you'll probably
* have to do each time you rev up major/minor versions:
*
* 1) Add the current version number string (before your change) to the
* XPT_TYPELIB_VERSIONS list.
*
* 2) Do your changes add new features to XPIDL? Ensure that those new
* features are rejected by the XPIDL compiler when any version number in
* the XPT_TYPELIB_VERSIONS list is specified on the command line. The
* one place that currently does this kind of error checking is the function
* verify_type_fits_version() in xpidl_util.c. It currently checks
* attribute types, parameter types, and return types. You'll probably have
* to add to it or generalize it further based on what kind of changes you
* are making.
*
* 3) You will probably NOT need to make any changes to the error checking
* in the linker.
*/
#define XPT_VERSION_UNKNOWN 0
#define XPT_VERSION_UNSUPPORTED 1
#define XPT_VERSION_OLD 2
#define XPT_VERSION_CURRENT 3
typedef struct {
const char* str;
PRUint8 major;
PRUint8 minor;
PRUint16 code;
} XPT_TYPELIB_VERSIONS_STRUCT;
/* Currently accepted list of versions for typelibs */
#define XPT_TYPELIB_VERSIONS { \
{"1.0", 1, 0, XPT_VERSION_UNSUPPORTED}, \
{"1.1", 1, 1, XPT_VERSION_OLD}, \
{"1.2", 1, 2, XPT_VERSION_CURRENT} \
};
extern XPT_PUBLIC_API(PRUint16)
XPT_ParseVersionString(const char* str, PRUint8* major, PRUint8* minor);
extern XPT_PUBLIC_API(XPTHeader *)
XPT_NewHeader(XPTArena *arena, PRUint16 num_interfaces);
XPT_NewHeader(XPTArena *arena, PRUint16 num_interfaces,
PRUint8 major_version, PRUint8 minor_version);
extern XPT_PUBLIC_API(void)
XPT_FreeHeader(XPTArena *arena, XPTHeader* aHeader);
@ -315,7 +372,10 @@ enum XPTTypeDescriptorTags {
TD_INTERFACE_IS_TYPE = 19,
TD_ARRAY = 20,
TD_PSTRING_SIZE_IS = 21,
TD_PWSTRING_SIZE_IS = 22
TD_PWSTRING_SIZE_IS = 22,
TD_UTF8STRING = 23,
TD_CSTRING = 24,
TD_ASTRING = 25,
};
struct XPTTypeDescriptor {

View File

@ -120,14 +120,14 @@ XPT_SizeOfHeaderBlock(XPTHeader *header)
}
XPT_PUBLIC_API(XPTHeader *)
XPT_NewHeader(XPTArena *arena, PRUint16 num_interfaces)
XPT_NewHeader(XPTArena *arena, PRUint16 num_interfaces, PRUint8 major_version, PRUint8 minor_version)
{
XPTHeader *header = XPT_NEWZAP(arena, XPTHeader);
if (!header)
return NULL;
memcpy(header->magic, XPT_MAGIC, 16);
header->major_version = XPT_MAJOR_VERSION;
header->minor_version = XPT_MINOR_VERSION;
header->major_version = major_version;
header->minor_version = minor_version;
header->num_interfaces = num_interfaces;
if (num_interfaces) {
header->interface_directory =
@ -936,3 +936,21 @@ XPT_GetInterfaceIndexByName(XPTInterfaceDirectoryEntry *ide_block,
return PR_FALSE;
}
static XPT_TYPELIB_VERSIONS_STRUCT versions[] = XPT_TYPELIB_VERSIONS;
#define XPT_TYPELIB_VERSIONS_COUNT (sizeof(versions) / sizeof(versions[0]))
XPT_PUBLIC_API(PRUint16)
XPT_ParseVersionString(const char* str, PRUint8* major, PRUint8* minor)
{
int i;
for (i = 0; i < XPT_TYPELIB_VERSIONS_COUNT; i++) {
if (!strcmp(versions[i].str, str)) {
*major = versions[i].major;
*minor = versions[i].minor;
return versions[i].code;
}
}
return XPT_VERSION_UNKNOWN;
}

View File

@ -105,7 +105,7 @@ main(int argc, char **argv)
TRY("XPT_NewArena", arena);
/* construct a header */
header = XPT_NewHeader(arena, 1);
header = XPT_NewHeader(arena, 1, XPT_MAJOR_VERSION, XPT_MINOR_VERSION);
TRY("NewHeader", header);

View File

@ -73,8 +73,8 @@ static char *ptype_array[32] =
"float *", "double *", "boolean *", "char *",
"wchar_t *", "void *", "nsIID *", "DOMString *",
"string", "wstring", "Interface *", "InterfaceIs *",
"array", "string_s", "wstring_s", "reserved",
"reserved", "reserved", "reserved", "reserved",
"array", "string_s", "wstring_s", "UTF8String *",
"CString *", "AString *", "reserved", "reserved",
"reserved", "reserved", "reserved", "reserved"};
static char *rtype_array[32] =
@ -83,8 +83,8 @@ static char *rtype_array[32] =
"float &", "double &", "boolean &", "char &",
"wchar_t &", "void &", "nsIID &", "DOMString &",
"string &", "wstring &", "Interface &", "InterfaceIs &",
"array &", "string_s &", "wstring_s &", "reserved",
"reserved", "reserved", "reserved", "reserved",
"array &", "string_s &", "wstring_s &", "UTF8String &",
"CString &", "AString &", "reserved", "reserved",
"reserved", "reserved", "reserved", "reserved"};
PRBool param_problems = PR_FALSE;

View File

@ -95,6 +95,10 @@ PRUint16 trueNumberOfInterfaces = 0;
PRUint16 totalNumberOfInterfaces = 0;
PRUint16 oldTotalNumberOfInterfaces = 0;
/* The following globals are explained in xpt_struct.h */
PRUint8 major_version = XPT_MAJOR_VERSION;
PRUint8 minor_version = XPT_MINOR_VERSION;
#if defined(XP_MAC) && defined(XPIDL_PLUGIN)
#define main xptlink_main
@ -132,6 +136,7 @@ main(int argc, char **argv)
PRUint32 newOffset;
size_t flen = 0;
char *head, *data, *whole;
const char *outFileName;
FILE *in, *out;
fixElement *fix_array = NULL;
int i,j;
@ -150,7 +155,54 @@ main(int argc, char **argv)
first_ann = XPT_NewAnnotation(arena, XPT_ANN_LAST, NULL, NULL);
for (i=2; i<argc; i++) {
/* Check if the "-t version numnber" cmd line arg is present */
i = 1;
if (argv[i][0] == '-' && argv[i][1] == 't') {
/* Parse for "-t version number" */
/* If -t is the last argument on the command line, we have a problem */
if (i + 1 == argc) {
fprintf(stderr, "ERROR: missing version number after -t\n");
xpt_link_usage(argv);
return 1;
}
/*
* Assume that the argument after "-t" is the version number string
* and search for it in our internal list of acceptable version
* numbers.
*/
switch (XPT_ParseVersionString(argv[++i], &major_version,
&minor_version)) {
case XPT_VERSION_CURRENT:
case XPT_VERSION_OLD:
break;
case XPT_VERSION_UNSUPPORTED:
fprintf(stderr, "ERROR: version \"%s\" not supported.\n",
argv[i]);
xpt_link_usage(argv);
return 1;
case XPT_VERSION_UNKNOWN:
default:
fprintf(stderr, "ERROR: version \"%s\" not recognised.\n",
argv[i]);
xpt_link_usage(argv);
return 1;
}
/* Hang onto the output file name. It's needed later. */
outFileName = argv[++i];
/* Increment i to the cmd line arg after outFileName */
i++;
}
else {
outFileName = argv[1];
i = 2;
}
for ( /* use i from earlier */ ; i < argc; i++) {
char *name = argv[i];
flen = get_file_length(name);
@ -194,6 +246,23 @@ main(int argc, char **argv)
return 1;
}
/*
* Make sure that the version of the typelib file is less than or
* equal to the version specified in the -t cmd line arg.
*/
if (header &&
(header->major_version > major_version ||
(header->major_version == major_version &&
header->minor_version > minor_version))) {
fprintf(stderr, "FAILED: %s's version, %d.%d, is newer than "
"the version (%d.%d) specified in the -t "
"command line argument.\n",
name, header->major_version, header->minor_version,
major_version, minor_version);
return 1;
}
oldTotalNumberOfInterfaces = totalNumberOfInterfaces;
totalNumberOfInterfaces += header->num_interfaces;
if (header->num_interfaces > 0) {
@ -492,7 +561,9 @@ main(int argc, char **argv)
}
}
header = XPT_NewHeader(arena, (PRUint16)trueNumberOfInterfaces);
header = XPT_NewHeader(arena, (PRUint16)trueNumberOfInterfaces,
major_version, minor_version);
header->annotations = first_ann;
for (i=0; i<trueNumberOfInterfaces; i++) {
if (!copy_IDE(&IDE_array[i], &header->interface_directory[i])) {
@ -531,7 +602,7 @@ main(int argc, char **argv)
return 1;
}
XPT_SeekTo(cursor, newOffset);
out = fopen(argv[1], "wb");
out = fopen(outFileName, "wb");
if (!out) {
perror("FAILED: fopen");
return 1;
@ -805,7 +876,8 @@ print_IID(struct nsID *iid, FILE *file)
static void
xpt_link_usage(char *argv[])
{
fprintf(stdout, "Usage: %s outfile file1.xpt file2.xpt ...\n"
" Links multiple typelib files into one outfile\n", argv[0]);
fprintf(stdout, "Usage: %s [-t version number] outfile file1.xpt file2.xpt ...\n"
" Links multiple typelib files into one outfile\n"
" -t create a typelib of an older version number\n", argv[0]);
}