Mozilla/mozilla/xpcom/tools/xpidl/macplugin/mac_xpt_linker.cpp
1999-05-09 15:03:13 +00:00

461 lines
11 KiB
C++

/*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/*
mac_xpt_linker.cpp
CodeWarrior plugin linker, links together multiple .xpt files.
by Patrick C. Beard.
*/
/* standard headers */
#include <stdio.h>
#include <string.h>
#include <setjmp.h>
/* system headers */
#include <Files.h>
#include <Strings.h>
/* compiler headers */
#include "DropInCompilerLinker.h"
#include "CompilerMapping.h"
#include "CWPluginErrors.h"
/* project headers */
#include "mac_xpidl_panel.h"
#include "mac_console.h"
#include "mac_strings.h"
#include "FullPath.h"
#include "MoreFilesExtras.h"
/* use standard CodeWarrior debugger */
#define kDebuggerCreator 'MWDB'
/* prototypes of local functions */
static CWResult Link(CWPluginContext context);
static CWResult Disassemble(CWPluginContext context);
static CWResult GetTargetInfo(CWPluginContext context);
extern "C" {
pascal short xpt_linker(CWPluginContext context);
int xptlink_main(int argc, char* argv[]);
int xptdump_main(int argc, char* argv[]);
FILE * FSp_fopen(ConstFSSpecPtr spec, const char * open_mode);
size_t mac_get_file_length(const char* filename);
}
/* external variables */
extern jmp_buf exit_jump;
extern int exit_status;
/* global variables */
CWPluginContext gPluginContext;
/* local variables */
static CWFileSpec gOutputDirectory;
static CWFileSpec gObjectCodeDirectory;
/*
* xpt_linker - main entry-point for linker plugin
*
*/
pascal short xpt_linker(CWPluginContext context)
{
long request;
if (CWGetPluginRequest(context, &request) != cwNoErr)
return cwErrRequestFailed;
gPluginContext = context;
short result = cwNoErr;
/* dispatch on linker request */
switch (request) {
case reqInitLinker:
/* linker has just been loaded into memory */
break;
case reqTermLinker:
/* linker is about to be unloaded from memory */
break;
case reqLink:
/* build the final executable */
result = Link(context);
break;
case reqDisassemble:
/* disassemble object code for a given project file */
result = Disassemble(context);
break;
case reqTargetInfo:
/* return info describing target characteristics */
result = GetTargetInfo(context);
break;
default:
result = cwErrRequestFailed;
break;
}
result = CWDonePluginRequest(context, result);
/* return result code */
return result;
}
static char* full_path_to(const FSSpec& file)
{
short len = 0;
Handle fullPath = NULL;
if (FSpGetFullPath(&file, &len, &fullPath) == noErr && fullPath != NULL) {
char* path = new char[1 + len];
if (path != NULL) {
BlockMoveData(*fullPath, path, len);
path[len] = '\0';
}
DisposeHandle(fullPath);
return path;
}
return NULL;
}
/**
* Provides the full path name to a given directory.
*/
static char* full_path_to(short vRefNum, long dirID)
{
long parID;
if (GetParentID(vRefNum, dirID, NULL, &parID) == noErr) {
FSSpec dirSpec = { vRefNum, parID };
if (GetDirName(vRefNum, dirID, dirSpec.name) == noErr) {
return full_path_to(dirSpec);
}
}
return NULL;
}
/**
* Returns the length of a file, assuming it is always located in the
* project's object code directory.
*/
size_t mac_get_file_length(const char* filename)
{
FSSpec fileSpec = { gObjectCodeDirectory.vRefNum, gObjectCodeDirectory.parID };
c2p_strcpy(fileSpec.name, filename);
long dataSize, rsrcSize;
if (FSpGetFileSize(&fileSpec, &dataSize, &rsrcSize) != noErr)
dataSize = 0;
return dataSize;
}
/**
* replaces standard fopen -- opens files for writing in the project's output directory,
* and files for reading in the object code directory.
*/
FILE* std::fopen(const char* filename, const char *mode)
{
CWFileSpec& fileDir = (mode[0] == 'r' ? gObjectCodeDirectory : gOutputDirectory);
FSSpec fileSpec = { fileDir.vRefNum, fileDir.parID };
c2p_strcpy(fileSpec.name, filename);
return FSp_fopen(&fileSpec, mode);
}
static CWResult GetSettings(CWPluginContext context, XPIDLSettings& settings)
{
CWMemHandle settingsHand;
CWResult err = CWGetNamedPreferences(context, kXPIDLPanelName, &settingsHand);
if (!CWSUCCESS(err))
return (err);
XPIDLSettings* settingsPtr = NULL;
err = CWLockMemHandle(context, settingsHand, false, (void**)&settingsPtr);
if (!CWSUCCESS(err))
return (err);
settings = *settingsPtr;
err = CWUnlockMemHandle(context, settingsHand);
if (!CWSUCCESS(err))
return (err);
return noErr;
}
static CWResult Link(CWPluginContext context)
{
long index;
CWResult err;
long filecount;
// load the relevant prefs.
XPIDLSettings settings = { kXPIDLSettingsVersion, kXPIDLModeTypelib, false, false };
err = GetSettings(context, settings);
if (err != cwNoErr)
return (err);
// find out how many files there are to link.
err = CWGetProjectFileCount(context, &filecount);
if (err != cwNoErr)
return (err);
// assemble the argument list.
// { "xpt_link", outputFile, inputFile1, ..., inputFileN, NULL }
char** argv = new char*[2 + filecount + 1];
int argc = 0;
argv[argc++] = "xpt_link";
// get the output directory.
err = CWGetOutputFileDirectory(context, &gOutputDirectory);
if (!CWSUCCESS(err))
return (err);
// get the object code directory.
err = CWGetStoredObjectFileSpec(context, 0, &gObjectCodeDirectory);
if (!CWSUCCESS(err))
return (err);
// push the output file name.
if ((argv[argc++] = p2c_strdup(settings.output)) == NULL)
return cwErrOutOfMemory;
for (index = 0; (err == cwNoErr) && (index < filecount); index++) {
// get the name of each output file.
CWFileSpec outputFile;
err = CWGetStoredObjectFileSpec(context, index, &outputFile);
if (err == cwNoErr) {
if ((argv[argc++] = p2c_strdup(outputFile.name)) == NULL) {
err = cwErrOutOfMemory;
break;
}
}
}
if (err != cwNoErr)
return err;
// trap calls to exit, which longjmp back to here.
if (setjmp(exit_jump) == 0) {
if (xptlink_main(argc, argv) != 0)
err = cwErrRequestFailed;
} else {
// evidently the good old exit function got called.
if (exit_status != 0)
err = cwErrRequestFailed;
}
return (err);
}
static CWResult Disassemble(CWPluginContext context)
{
CWResult err = noErr;
// cache the project's output directory.
err = CWGetOutputFileDirectory(gPluginContext, &gOutputDirectory);
if (!CWSUCCESS(err))
return (err);
long fileNum;
err = CWGetMainFileNumber(context, &fileNum);
if (!CWSUCCESS(err))
return (err);
// get the output file's location from the stored object data.
err = CWGetStoredObjectFileSpec(context, fileNum, &gObjectCodeDirectory);
if (!CWSUCCESS(err))
return (err);
char* outputName = p2c_strdup(gObjectCodeDirectory.name);
if (outputName == NULL)
return cwErrOutOfMemory;
XPIDLSettings settings = { kXPIDLSettingsVersion, kXPIDLModeTypelib, false, false };
GetSettings(context, settings);
// build an argument list and call xpt_dump.
int argc = 1;
char* argv[] = { "xpt_dump", NULL, NULL, NULL };
if (settings.verbose) argv[argc++] = "-v";
argv[argc++] = outputName;
// trap calls to exit, which longjmp back to here.
if (setjmp(exit_jump) == 0) {
if (xptdump_main(argc, argv) != 0)
err = cwErrRequestFailed;
} else {
// evidently the good old exit function got called.
if (exit_status != 0)
err = cwErrRequestFailed;
}
delete[] outputName;
if (err == noErr) {
// display the disassembly in its own fresh text window.
CWNewTextDocumentInfo info = {
NULL,
mac_console_handle,
false
};
CWResizeMemHandle(context, mac_console_handle, mac_console_count);
err = CWCreateNewTextDocument(context, &info);
}
return (err);
}
static CWResult GetTargetInfo(CWPluginContext context)
{
CWTargetInfo targ;
memset(&targ, 0, sizeof(targ));
CWResult err = CWGetOutputFileDirectory(context, &targ.outfile);
targ.outputType = linkOutputFile;
targ.symfile = targ.outfile; /* location of SYM file */
targ.linkType = exelinkageFlat;
targ.targetCPU = '****';
targ.targetOS = '****';
// load the relevant settings.
XPIDLSettings settings = { kXPIDLSettingsVersion, kXPIDLModeTypelib, false, false };
err = GetSettings(context, settings);
if (err != cwNoErr)
return (err);
#if CWPLUGIN_HOST == CWPLUGIN_HOST_MACOS
// tell the IDE about the output file.
targ.outfileCreator = 'MMCH';
targ.outfileType = 'CWIE';
targ.debuggerCreator = kDebuggerCreator; /* so IDE can locate our debugger */
BlockMoveData(settings.output, targ.outfile.name, 1 + settings.output[0]);
targ.symfile.name[0] = 0;
#endif
#if CWPLUGIN_HOST == CWPLUGIN_HOST_WIN32
targ.debugHelperIsRegKey = true;
*(long*)targ.debugHelperName = kDebuggerCreator;
targ.debugHelperName[4] = 0;
strcat(targ.outfile.path, "\\");
strcat(targ.outfile.path, prefsData.outfile);
strcpy(targ.symfile.path, targ.outfile.path);
strcat(targ.symfile.path, ".SYM");
#endif
targ.runfile = targ.outfile;
targ.linkAgainstFile = targ.outfile;
/* we can only run applications */
// targ.canRun = (prefsData.projtype == kProjTypeApplication);
/* we can only debug if we have a SYM file */
// targ.canDebug = prefsData.linksym;
err = CWSetTargetInfo(context, &targ);
return err;
}
#if 0
#if CW_USE_PRAGMA_EXPORT
#pragma export on
#endif
CWPLUGIN_ENTRY(CWPlugin_GetDropInFlags)(const DropInFlags** flags, long* flagsSize)
{
static const DropInFlags sFlags = {
kCurrentDropInFlagsVersion,
CWDROPINLINKERTYPE,
DROPINCOMPILERLINKERAPIVERSION_7,
(linkMultiTargAware | linkAlwaysReload),
0,
DROPINCOMPILERLINKERAPIVERSION
};
*flags = &sFlags;
*flagsSize = sizeof(sFlags);
return cwNoErr;
}
CWPLUGIN_ENTRY(CWPlugin_GetDropInName)(const char** dropinName)
{
static const char* sDropInName = "xpt Linker";
*dropinName = sDropInName;
return cwNoErr;
}
CWPLUGIN_ENTRY(CWPlugin_GetDisplayName)(const char** displayName)
{
static const char* sDisplayName = "xpt Linker";
*displayName = sDisplayName;
return cwNoErr;
}
CWPLUGIN_ENTRY(CWPlugin_GetPanelList)(const CWPanelList** panelList)
{
// +++Turn this on when the sample panel has been converted!
static const char* sPanelName = kXPIDLPanelName;
static CWPanelList sPanelList = { kCurrentCWPanelListVersion, 1, &sPanelName };
*panelList = &sPanelList;
return cwNoErr;
}
CWPLUGIN_ENTRY(CWPlugin_GetTargetList)(const CWTargetList** targetList)
{
static CWDataType sCPU = '****';
static CWDataType sOS = '****';
static CWTargetList sTargetList = { kCurrentCWTargetListVersion, 1, &sCPU, 1, &sOS };
*targetList = &sTargetList;
return cwNoErr;
}
CWPLUGIN_ENTRY(CWPlugin_GetDefaultMappingList)(const CWExtMapList** defaultMappingList)
{
static CWExtensionMapping sExtension = { 'MMCH', ".xpt", 0 };
static CWExtMapList sExtensionMapList = { kCurrentCWExtMapListVersion, 1, &sExtension };
*defaultMappingList = &sExtensionMapList;
return cwNoErr;
}
CWPLUGIN_ENTRY (CWPlugin_GetFamilyList)(const CWFamilyList** familyList)
{
static CWFamily sFamily = { 'XIDL', "xpidl Settings" };
static CWFamilyList sFamilyList = { kCurrentCWFamilyListVersion, 0, &sFamily };
*familyList = &sFamilyList;
return cwNoErr;
}
#if CW_USE_PRAGMA_EXPORT
#pragma export off
#endif
#endif