Switch tab-indented files to 4-space indent

This commit is contained in:
Wolfgang Thaller
2019-08-18 13:21:00 +02:00
parent 9cb90cb3b0
commit e5185d23c3
133 changed files with 7879 additions and 7866 deletions

View File

@@ -6,6 +6,9 @@ indent_style = space
tab_width = 4
charset = utf-8
[InterfacesAndLibraries/**/*]
indent_style = tab
[gcc/**/*]
indent_style = tab
tab_width = 8
@@ -16,5 +19,15 @@ indent_style = tab
tab_width = 8
indent_width = 2
[libelf/**/*]
indent_style = tab
tab_width = 8
indent_width = 2
[hfsutils/**/*]
indent_style = tab
tab_width = 8
indent_width = 2
[**/Makefile]
indent_style=tab

View File

@@ -1,20 +1,20 @@
find_program(LAUNCH_APPL LaunchAPPL PATH "${CMAKE_INSTALL_PREFIX}/../bin/")
execute_process(COMMAND ${LAUNCH_APPL} --list-emulators
OUTPUT_VARIABLE EMULATOR_LIST)
OUTPUT_VARIABLE EMULATOR_LIST)
string(REPLACE "\n" ";" EMULATOR_LIST "${EMULATOR_LIST}")
if(CMAKE_SYSTEM_NAME MATCHES "RetroCarbon")
if("carbon" IN_LIST EMULATOR_LIST)
set(RETRO68_LAUNCH_METHOD carbon CACHE STRING "How to launch Mac applications (for automated testing)")
else()
set(RETRO68_LAUNCH_METHOD NONE CACHE STRING "How to launch Mac applications (for automated testing)")
endif()
if("carbon" IN_LIST EMULATOR_LIST)
set(RETRO68_LAUNCH_METHOD carbon CACHE STRING "How to launch Mac applications (for automated testing)")
else()
set(RETRO68_LAUNCH_METHOD NONE CACHE STRING "How to launch Mac applications (for automated testing)")
endif()
else()
if("classic" IN_LIST EMULATOR_LIST)
set(RETRO68_LAUNCH_METHOD classic CACHE STRING "How to launch Mac applications (for automated testing)")
else()
set(RETRO68_LAUNCH_METHOD NONE CACHE STRING "How to launch Mac applications (for automated testing)")
endif()
if("classic" IN_LIST EMULATOR_LIST)
set(RETRO68_LAUNCH_METHOD classic CACHE STRING "How to launch Mac applications (for automated testing)")
else()
set(RETRO68_LAUNCH_METHOD NONE CACHE STRING "How to launch Mac applications (for automated testing)")
endif()
endif()
if(CMAKE_SYSTEM_NAME MATCHES "RetroCarbon")
@@ -33,17 +33,17 @@ set(LAUNCH_METHOD_FLAG)
if(RETRO68_LAUNCH_METHOD MATCHES "NONE")
else()
set(LAUNCH_METHOD_FLAG "-e${RETRO68_LAUNCH_METHOD}")
endif() # RETRO68_LAUNCH_METHOD
endif() # RETRO68_LAUNCH_METHOD
enable_testing()
function(test FILE)
get_filename_component(NAME ${FILE} NAME_WE)
get_filename_component(NAME ${FILE} NAME_WE)
add_application(${NAME} ${FILE} Test.h Test.c)
target_include_directories(${NAME} PRIVATE .)
add_test(NAME ${TESTCASE_PREFIX}${NAME} COMMAND ${LAUNCH_APPL}
add_test(NAME ${TESTCASE_PREFIX}${NAME} COMMAND ${LAUNCH_APPL}
${LAUNCH_METHOD_FLAG} ${RETRO68_TEST_CONFIG} ${NAME}.bin)
if(ARGN)
set_tests_properties(${TESTCASE_PREFIX}${NAME} ${ARGN})
@@ -51,8 +51,8 @@ function(test FILE)
endfunction()
if(CMAKE_SYSTEM_NAME MATCHES "Retro68")
test(ReallyEmpty.c)
set_target_properties(ReallyEmpty PROPERTIES LINK_FLAGS "-Wl,-gc-sections -Wl,--mac-single")
test(ReallyEmpty.c)
set_target_properties(ReallyEmpty PROPERTIES LINK_FLAGS "-Wl,-gc-sections -Wl,--mac-single")
endif()
test(Empty.c)
@@ -70,10 +70,10 @@ test(Init.cc PROPERTIES PASS_REGULAR_EXPRESSION "constructor\nmain\ndestructor")
test(StdIO.c PROPERTIES PASS_REGULAR_EXPRESSION "OK")
if(CMAKE_SYSTEM_NAME MATCHES Retro68)
add_application(Segments Segment1.c Segment2.c Segments.segmap Test.h Test.c)
set_target_properties(Segments PROPERTIES
LINK_FLAGS "-Wl,-gc-sections -Wl,--mac-segments -Wl,${CMAKE_CURRENT_SOURCE_DIR}/Segments.segmap")
add_test(NAME ${TESTCASE_PREFIX}Segments COMMAND ${LAUNCH_APPL}
add_application(Segments Segment1.c Segment2.c Segments.segmap Test.h Test.c)
set_target_properties(Segments PROPERTIES
LINK_FLAGS "-Wl,-gc-sections -Wl,--mac-segments -Wl,${CMAKE_CURRENT_SOURCE_DIR}/Segments.segmap")
add_test(NAME ${TESTCASE_PREFIX}Segments COMMAND ${LAUNCH_APPL}
${LAUNCH_METHOD_FLAG} ${RETRO68_TEST_CONFIG} Segments.bin)
endif()

View File

@@ -1,5 +1,5 @@
int main()
{
// Test: do things work well enough for us to get to main()?
return 0;
// Test: do things work well enough for us to get to main()?
return 0;
}

View File

@@ -2,5 +2,5 @@
int main()
{
TEST_LOG_OK();
TEST_LOG_OK();
}

View File

@@ -3,20 +3,20 @@
class Constructed
{
public:
Constructed()
{
TestLog("constructor");
}
~Constructed()
{
TestLog("destructor");
}
Constructed()
{
TestLog("constructor");
}
~Constructed()
{
TestLog("destructor");
}
};
Constructed thing;
int main()
{
TestLog("main");
return 0;
TestLog("main");
return 0;
}

View File

@@ -4,10 +4,10 @@ char readWriteData[6] = "Three";
int main()
{
// constant initialized data
TEST_LOG_SIZED("One",3);
TEST_LOG_SIZED("Two",3);
// read-write initialized data
TEST_LOG_SIZED(readWriteData,5);
return 0;
// constant initialized data
TEST_LOG_SIZED("One",3);
TEST_LOG_SIZED("Two",3);
// read-write initialized data
TEST_LOG_SIZED(readWriteData,5);
return 0;
}

View File

@@ -1,6 +1,6 @@
void _start()
{
// Test: do things work well enough for us to get to a startup function?
// Note: this won't work for multisegment 68K apps, as the startup function will be in the wrong segment.
// Test: do things work well enough for us to get to a startup function?
// Note: this won't work for multisegment 68K apps, as the startup function will be in the wrong segment.
}

View File

@@ -10,87 +10,87 @@ void Bar();
Boolean Test(Boolean unloadFoo, Boolean unloadBar, Boolean compact)
{
variable = 6;
Foo();
if(variable != 54)
{
TestLog("Expected 54 after Foo().");
return false;
}
variable = 6;
Foo();
if(variable != 54)
{
TestLog("Expected 54 after Foo().");
return false;
}
if(unloadFoo)
UnloadSeg(&Foo);
if(unloadBar)
UnloadSeg(&Bar);
if(unloadFoo)
UnloadSeg(&Foo);
if(unloadBar)
UnloadSeg(&Bar);
Size grow;
if(compact)
MaxMem(&grow);
Size grow;
if(compact)
MaxMem(&grow);
Bar();
if(variable != 42)
{
TestLog("Expected 42 after Bar().");
return false;
}
return true;
Bar();
if(variable != 42)
{
TestLog("Expected 42 after Bar().");
return false;
}
return true;
}
int main()
{
Size grow, maxblock, maxblock2, freemem, freemem2;
Size grow, maxblock, maxblock2, freemem, freemem2;
MaxApplZone(); // just to keep things simple and predictable
MoreMasters();
MaxApplZone(); // just to keep things simple and predictable
MoreMasters();
maxblock = MaxMem(&grow);
freemem = FreeMem();
maxblock = MaxMem(&grow);
freemem = FreeMem();
TestLog("1. No unloading");
if(!Test(false, false, false))
return 1;
TestLog("1. No unloading");
if(!Test(false, false, false))
return 1;
maxblock2 = MaxMem(&grow);
maxblock2 = MaxMem(&grow);
TestLog("2. UnloadSeg(&Foo)");
if(!Test(true, false, false))
return 1;
TestLog("3. UnloadSeg(&Bar)");
if(!Test(false, true, false))
return 1;
TestLog("4. UnloadSeg(&Foo); UnloadSeg(&Bar)");
if(!Test(true, true, false))
return 1;
TestLog("2. UnloadSeg(&Foo)");
if(!Test(true, false, false))
return 1;
TestLog("3. UnloadSeg(&Bar)");
if(!Test(false, true, false))
return 1;
TestLog("4. UnloadSeg(&Foo); UnloadSeg(&Bar)");
if(!Test(true, true, false))
return 1;
TestLog("5. UnloadSeg(&Foo); MaxMem()");
if(!Test(true, false, true))
return 1;
TestLog("6. UnloadSeg(&Bar); MaxMem()");
if(!Test(false, true, true))
return 1;
TestLog("7. UnloadSeg(&Foo); UnloadSeg(&Bar); MaxMem()");
if(!Test(true, true, true))
return 1;
TestLog("5. UnloadSeg(&Foo); MaxMem()");
if(!Test(true, false, true))
return 1;
TestLog("6. UnloadSeg(&Bar); MaxMem()");
if(!Test(false, true, true))
return 1;
TestLog("7. UnloadSeg(&Foo); UnloadSeg(&Bar); MaxMem()");
if(!Test(true, true, true))
return 1;
UnloadSeg(&Foo);
UnloadSeg(&Foo);
maxblock2 = MaxMem(&grow);
freemem2 = FreeMem();
maxblock2 = MaxMem(&grow);
freemem2 = FreeMem();
if(maxblock2 < maxblock || freemem2 < freemem)
{
TestLog("Leak");
char s[256];
sprintf(s, "maxblock: %d (delta %d), freemem: %d (delta %d)",
maxblock2, maxblock2-maxblock, freemem2, freemem2-freemem);
TestLog(s);
return 1;
}
else if(maxblock2 > maxblock || freemem2 > freemem)
TestLog("Magic Memory");
if(maxblock2 < maxblock || freemem2 < freemem)
{
TestLog("Leak");
char s[256];
sprintf(s, "maxblock: %d (delta %d), freemem: %d (delta %d)",
maxblock2, maxblock2-maxblock, freemem2, freemem2-freemem);
TestLog(s);
return 1;
}
else if(maxblock2 > maxblock || freemem2 > freemem)
TestLog("Magic Memory");
TestLog("OK");
TestLog("OK");
return 0;
return 0;
}

View File

@@ -2,11 +2,11 @@ extern int variable;
#include <SegLoad.h>
void Foo()
{
variable *= 9;
variable *= 9;
}
void Bar()
{
variable /= 9;
variable *= 7;
variable /= 9;
variable *= 7;
}

View File

@@ -2,7 +2,7 @@
int main()
{
FILE *f = fopen("out", "w");
fprintf(f, "OK\n");
fclose(f);
FILE *f = fopen("out", "w");
fprintf(f, "OK\n");
fclose(f);
}

View File

@@ -2,5 +2,5 @@
void TestLog(const char *str)
{
TEST_LOG_SIZED(str, strlen(str));
TEST_LOG_SIZED(str, strlen(str));
}

View File

@@ -22,52 +22,52 @@ void TestLog(const char *str);
/* The same thing as a macro. String length has to be given explicitly,
* to avoid a call to strlen(). */
#define TEST_LOG_SIZED(str, size) \
do { \
HParamBlockRec _hpb; \
\
unsigned char _fileName[4]; \
short _ref;\
_fileName[0] = 3; \
_fileName[1] = 'o'; \
_fileName[2] = 'u'; \
_fileName[3] = 't'; \
\
_hpb.ioParam.ioCompletion = NULL; \
_hpb.ioParam.ioNamePtr = (StringPtr)_fileName; \
_hpb.ioParam.ioVRefNum = 0; \
_hpb.fileParam.ioDirID = 0; \
_hpb.ioParam.ioPermssn = fsRdWrPerm; \
_hpb.ioParam.ioMisc = NULL; \
PBHOpenSync(&_hpb); \
_ref = _hpb.ioParam.ioRefNum; \
\
_hpb.ioParam.ioCompletion = NULL; \
_hpb.ioParam.ioBuffer = (Ptr)str; \
_hpb.ioParam.ioReqCount = size; \
_hpb.ioParam.ioPosMode = fsFromLEOF; \
_hpb.ioParam.ioPosOffset = 0; \
_hpb.ioParam.ioRefNum = _ref; \
_hpb.ioParam.ioMisc = NULL; \
PBWriteSync((ParmBlkPtr)&_hpb); \
char _newline = '\n'; \
_hpb.ioParam.ioCompletion = NULL; \
_hpb.ioParam.ioBuffer = &_newline; \
_hpb.ioParam.ioReqCount = 1; \
_hpb.ioParam.ioPosMode = fsFromLEOF; \
_hpb.ioParam.ioPosOffset = 0; \
_hpb.ioParam.ioRefNum = _ref; \
_hpb.ioParam.ioMisc = NULL; \
PBWriteSync((ParmBlkPtr)&_hpb); \
_hpb.ioParam.ioCompletion = NULL; \
_hpb.ioParam.ioRefNum = _ref; \
_hpb.ioParam.ioMisc = NULL; \
PBCloseSync((ParmBlkPtr)&_hpb); \
_hpb.ioParam.ioCompletion = NULL; \
_hpb.ioParam.ioNamePtr = NULL; \
_hpb.ioParam.ioVRefNum = 0; \
_hpb.ioParam.ioMisc = NULL; \
PBFlushVolSync((ParmBlkPtr)&_hpb); \
} while(0);
do { \
HParamBlockRec _hpb; \
\
unsigned char _fileName[4]; \
short _ref;\
_fileName[0] = 3; \
_fileName[1] = 'o'; \
_fileName[2] = 'u'; \
_fileName[3] = 't'; \
\
_hpb.ioParam.ioCompletion = NULL; \
_hpb.ioParam.ioNamePtr = (StringPtr)_fileName; \
_hpb.ioParam.ioVRefNum = 0; \
_hpb.fileParam.ioDirID = 0; \
_hpb.ioParam.ioPermssn = fsRdWrPerm; \
_hpb.ioParam.ioMisc = NULL; \
PBHOpenSync(&_hpb); \
_ref = _hpb.ioParam.ioRefNum; \
\
_hpb.ioParam.ioCompletion = NULL; \
_hpb.ioParam.ioBuffer = (Ptr)str; \
_hpb.ioParam.ioReqCount = size; \
_hpb.ioParam.ioPosMode = fsFromLEOF; \
_hpb.ioParam.ioPosOffset = 0; \
_hpb.ioParam.ioRefNum = _ref; \
_hpb.ioParam.ioMisc = NULL; \
PBWriteSync((ParmBlkPtr)&_hpb); \
char _newline = '\n'; \
_hpb.ioParam.ioCompletion = NULL; \
_hpb.ioParam.ioBuffer = &_newline; \
_hpb.ioParam.ioReqCount = 1; \
_hpb.ioParam.ioPosMode = fsFromLEOF; \
_hpb.ioParam.ioPosOffset = 0; \
_hpb.ioParam.ioRefNum = _ref; \
_hpb.ioParam.ioMisc = NULL; \
PBWriteSync((ParmBlkPtr)&_hpb); \
_hpb.ioParam.ioCompletion = NULL; \
_hpb.ioParam.ioRefNum = _ref; \
_hpb.ioParam.ioMisc = NULL; \
PBCloseSync((ParmBlkPtr)&_hpb); \
_hpb.ioParam.ioCompletion = NULL; \
_hpb.ioParam.ioNamePtr = NULL; \
_hpb.ioParam.ioVRefNum = 0; \
_hpb.ioParam.ioMisc = NULL; \
PBFlushVolSync((ParmBlkPtr)&_hpb); \
} while(0);
/*
* Output either "OK" or "NO".
@@ -75,23 +75,23 @@ void TestLog(const char *str);
* we might not want to test them yet.
*/
#define TEST_LOG_OK() \
do { \
char ok[3]; \
ok[0] = 'O'; \
ok[1] = 'K'; \
ok[2] = '\0'; \
TEST_LOG_SIZED(ok, 2); \
} while(0)
#define TEST_LOG_OK() \
do { \
char ok[3]; \
ok[0] = 'O'; \
ok[1] = 'K'; \
ok[2] = '\0'; \
TEST_LOG_SIZED(ok, 2); \
} while(0)
#define TEST_LOG_NO() \
do { \
char no[3]; \
no[0] = 'O'; \
no[1] = 'K'; \
no[2] = '\0'; \
TEST_LOG_SIZED(no, 2); \
} while(0)
#define TEST_LOG_NO() \
do { \
char no[3]; \
no[0] = 'O'; \
no[1] = 'K'; \
no[2] = '\0'; \
TEST_LOG_SIZED(no, 2); \
} while(0)
#endif // TEST_H

View File

@@ -2,10 +2,10 @@
int main()
{
TEST_LOG_SIZED("One",3);
TEST_LOG_SIZED("Two",3);
for(;;)
;
TEST_LOG_SIZED("Three",5);
return 0;
TEST_LOG_SIZED("One",3);
TEST_LOG_SIZED("Two",3);
for(;;)
;
TEST_LOG_SIZED("Three",5);
return 0;
}

View File

@@ -10,45 +10,45 @@ EventRecord e;
int main()
{
int i;
if(commonSymbol)
{
TEST_LOG_NO();
return 1;
}
if(zeroInited)
{
TEST_LOG_NO();
return 1;
}
for(i = 0; i < 32768; i++)
{
if(zeroInitedArray[i])
{
TEST_LOG_NO();
return 1;
}
zeroInitedArray[i] = 42;
}
int i;
if(commonSymbol)
{
TEST_LOG_NO();
return 1;
}
if(zeroInited)
{
TEST_LOG_NO();
return 1;
}
for(i = 0; i < 32768; i++)
{
if(zeroInitedArray[i])
{
TEST_LOG_NO();
return 1;
}
zeroInitedArray[i] = 42;
}
// Initialize some of the Macintosh Toolbox
// and maybe trigger a context switch, so we can be sure
// our global variables were put in the right placce.
#if !TARGET_API_MAC_CARBON
InitGraf(&qd.thePort);
InitFonts();
InitWindows();
InitGraf(&qd.thePort);
InitFonts();
InitWindows();
#endif
GetNextEvent(everyEvent, &e);
GetNextEvent(everyEvent, &e);
for(i = 0; i < 32768; i++)
{
if(zeroInitedArray[i] != 42)
{
TEST_LOG_NO();
return 1;
}
}
TEST_LOG_OK();
return 0;
for(i = 0; i < 32768; i++)
{
if(zeroInitedArray[i] != 42)
{
TEST_LOG_NO();
return 1;
}
}
TEST_LOG_OK();
return 0;
}

View File

@@ -16,15 +16,15 @@
# along with Retro68. If not, see <http://www.gnu.org/licenses/>.
add_library(RetroConsole
retro/Console.cc
retro/Console.h
retro/ConsoleWindow.cc
retro/ConsoleWindow.h
retro/MacUtils.h
retro/InitConsole.cc
)
retro/Console.cc
retro/Console.h
retro/ConsoleWindow.cc
retro/ConsoleWindow.h
retro/MacUtils.h
retro/InitConsole.cc
)
set_target_properties(retrocrt
PROPERTIES
PROPERTIES
COMPILE_OPTIONS -ffunction-sections)
# different library name for Carbon
@@ -37,6 +37,6 @@ target_include_directories(RetroConsole PUBLIC .)
install(TARGETS RetroConsole DESTINATION lib)
add_application(ConsoleTest
ConsoleTest.cc
)
ConsoleTest.cc
)
target_link_libraries(ConsoleTest RetroConsole)

View File

@@ -3,21 +3,21 @@
namespace retro
{
void InitConsole();
void InitConsole();
}
int main()
{
retro::InitConsole();
std::string out = "Hello, world.\nEnter \"exit\" to quit.\n";
retro::Console::currentInstance->write(out.data(), out.size());
std::string in;
do
{
in = retro::Console::currentInstance->ReadLine();
out = "You Entered: " + in;
retro::Console::currentInstance->write(out.data(), out.size());
} while(in != "exit\n");
return 0;
retro::InitConsole();
std::string out = "Hello, world.\nEnter \"exit\" to quit.\n";
retro::Console::currentInstance->write(out.data(), out.size());
std::string in;
do
{
in = retro::Console::currentInstance->ReadLine();
out = "You Entered: " + in;
retro::Console::currentInstance->write(out.data(), out.size());
} while(in != "exit\n");
return 0;
}

View File

@@ -293,7 +293,7 @@ std::string Console::ReadLine()
char c;
do
{
{
c = WaitNextChar();
if(!c)
{

View File

@@ -25,66 +25,66 @@
namespace retro
{
class Console
{
public:
Console();
Console(GrafPtr port, Rect r);
~Console();
class Console
{
public:
Console();
Console(GrafPtr port, Rect r);
~Console();
void Reshape(Rect newBounds);
void Reshape(Rect newBounds);
void Draw(Rect r);
void Draw() { Draw(bounds); }
void putch(char c);
void Draw(Rect r);
void Draw() { Draw(bounds); }
void putch(char c);
void write(const char *s, int n);
std::string ReadLine();
void write(const char *s, int n);
std::string ReadLine();
static Console *currentInstance;
static Console *currentInstance;
short GetRows() const { return rows; }
short GetCols() const { return cols; }
void Idle();
short GetRows() const { return rows; }
short GetCols() const { return cols; }
void Idle();
bool IsEOF() const { return eof; }
private:
GrafPtr consolePort = nullptr;
Rect bounds;
private:
GrafPtr consolePort = nullptr;
Rect bounds;
std::vector<char> chars, onscreen;
std::vector<char> chars, onscreen;
short cellSizeX;
short cellSizeY;
short cellSizeX;
short cellSizeY;
short rows = 0, cols = 0;
short rows = 0, cols = 0;
short cursorX, cursorY;
short cursorX, cursorY;
Rect dirtyRect = {};
long blinkTicks = 0;
bool cursorDrawn = false;
bool cursorVisible = true;
Rect dirtyRect = {};
long blinkTicks = 0;
bool cursorDrawn = false;
bool cursorVisible = true;
bool eof = false;
void PutCharNoUpdate(char c);
void Update();
void PutCharNoUpdate(char c);
void Update();
Rect CellRect(short x, short y);
void DrawCell(short x, short y, bool erase = true);
void DrawCells(short x1, short x2, short y, bool erase = true);
void ScrollUp(short n = 1);
void InvalidateCursor();
Rect CellRect(short x, short y);
void DrawCell(short x, short y, bool erase = true);
void DrawCells(short x1, short x2, short y, bool erase = true);
void ScrollUp(short n = 1);
void InvalidateCursor();
virtual char WaitNextChar();
protected:
void Init(GrafPtr port, Rect r);
};
virtual char WaitNextChar();
protected:
void Init(GrafPtr port, Rect r);
};
}

View File

@@ -25,103 +25,103 @@ using namespace retro;
namespace
{
std::unordered_map<WindowPtr, ConsoleWindow*> *windows = NULL;
std::unordered_map<WindowPtr, ConsoleWindow*> *windows = NULL;
}
ConsoleWindow::ConsoleWindow(Rect r, ConstStr255Param title)
{
GrafPtr port;
GrafPtr port;
win = NewWindow(NULL, &r, "\pRetro68 Console", true, 0, (WindowPtr)-1, false, 0);
win = NewWindow(NULL, &r, "\pRetro68 Console", true, 0, (WindowPtr)-1, false, 0);
#if !TARGET_API_MAC_CARBON
port = win;
Rect portRect = port->portRect;
port = win;
Rect portRect = port->portRect;
#else
port = GetWindowPort(win);
Rect portRect;
GetPortBounds(port, &portRect);
port = GetWindowPort(win);
Rect portRect;
GetPortBounds(port, &portRect);
#endif
SetPort(port);
EraseRect(&portRect);
SetPort(port);
EraseRect(&portRect);
if(!windows)
windows = new std::unordered_map<WindowPtr, ConsoleWindow*>();
(*windows)[win] = this;
if(!windows)
windows = new std::unordered_map<WindowPtr, ConsoleWindow*>();
(*windows)[win] = this;
Init(port, portRect);
Init(port, portRect);
}
ConsoleWindow::~ConsoleWindow()
{
windows->erase(win);
DisposeWindow(win);
windows->erase(win);
DisposeWindow(win);
}
char ConsoleWindow::WaitNextChar()
{
EventRecord event;
WindowPtr eventWin;
ConsoleWindow *realConsole;
EventRecord event;
WindowPtr eventWin;
ConsoleWindow *realConsole;
#if TARGET_API_MAC_CARBON
Rect *boundsPtr = NULL;
Rect *boundsPtr = NULL;
#else
Rect *boundsPtr = &qd.screenBits.bounds;
Rect *boundsPtr = &qd.screenBits.bounds;
#endif
do
{
#if TARGET_API_MAC_CARBON
#define SystemTask()
#endif
SystemTask();
Idle();
while(!GetNextEvent(everyEvent, &event))
{
SystemTask();
Idle();
}
switch(event.what)
{
case updateEvt:
eventWin = (WindowPtr)event.message;
realConsole = (*windows)[(WindowPtr)event.message];
if(realConsole)
{
Rect updateRect;
BeginUpdate(eventWin);
do
{
#if TARGET_API_MAC_CARBON
#define SystemTask()
#endif
SystemTask();
Idle();
while(!GetNextEvent(everyEvent, &event))
{
SystemTask();
Idle();
}
switch(event.what)
{
case updateEvt:
eventWin = (WindowPtr)event.message;
realConsole = (*windows)[(WindowPtr)event.message];
if(realConsole)
{
Rect updateRect;
BeginUpdate(eventWin);
#if TARGET_API_MAC_CARBON
RgnHandle rgn = NewRgn();
GetPortVisibleRegion(GetWindowPort(eventWin), rgn);
GetRegionBounds(rgn, &updateRect);
DisposeRgn(rgn);
RgnHandle rgn = NewRgn();
GetPortVisibleRegion(GetWindowPort(eventWin), rgn);
GetRegionBounds(rgn, &updateRect);
DisposeRgn(rgn);
#else
updateRect = (*qd.thePort->visRgn)->rgnBBox; // Life was simple back then.
updateRect = (*qd.thePort->visRgn)->rgnBBox; // Life was simple back then.
#endif
realConsole->Draw(updateRect);
EndUpdate(eventWin);
}
break;
case mouseDown:
switch(FindWindow(event.where, &eventWin))
{
case inDrag:
DragWindow(eventWin, event.where, boundsPtr);
break;
case inGrow:
{
long growResult = GrowWindow(eventWin, event.where, boundsPtr);
SizeWindow(eventWin, growResult & 0xFFFF, growResult >> 16, false);
Reshape(Rect {0, 0, (short) (growResult >> 16), (short) (growResult & 0xFFFF) });
}
break;
}
break;
}
} while(event.what != keyDown && event.what != autoKey);
return event.message & charCodeMask;
realConsole->Draw(updateRect);
EndUpdate(eventWin);
}
break;
case mouseDown:
switch(FindWindow(event.where, &eventWin))
{
case inDrag:
DragWindow(eventWin, event.where, boundsPtr);
break;
case inGrow:
{
long growResult = GrowWindow(eventWin, event.where, boundsPtr);
SizeWindow(eventWin, growResult & 0xFFFF, growResult >> 16, false);
Reshape(Rect {0, 0, (short) (growResult >> 16), (short) (growResult & 0xFFFF) });
}
break;
}
break;
}
} while(event.what != keyDown && event.what != autoKey);
return event.message & charCodeMask;
}

View File

@@ -25,14 +25,14 @@
namespace retro
{
class ConsoleWindow : public Console
{
public:
ConsoleWindow(Rect r, ConstStr255Param title);
~ConsoleWindow();
private:
WindowPtr win;
class ConsoleWindow : public Console
{
public:
ConsoleWindow(Rect r, ConstStr255Param title);
~ConsoleWindow();
private:
WindowPtr win;
virtual char WaitNextChar();
};
virtual char WaitNextChar();
};
}

View File

@@ -1,20 +1,20 @@
/*
Copyright 2014 Wolfgang Thaller.
Copyright 2014 Wolfgang Thaller.
This file is part of Retro68.
This file is part of Retro68.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string>
@@ -34,26 +34,26 @@
namespace retro
{
void InitConsole();
void InitConsole();
}
using namespace retro;
void retro::InitConsole()
{
if(Console::currentInstance)
return;
if(Console::currentInstance)
return;
Console::currentInstance = (Console*) -1;
#if !TARGET_API_MAC_CARBON
InitGraf(&qd.thePort);
InitFonts();
InitWindows();
InitMenus();
InitGraf(&qd.thePort);
InitFonts();
InitWindows();
InitMenus();
Rect r = qd.screenBits.bounds;
Rect r = qd.screenBits.bounds;
#else
Rect r = (*GetMainDevice())->gdRect;
Rect r = (*GetMainDevice())->gdRect;
#endif
{
// give MultiFinder a chance to bring the App to front
@@ -71,41 +71,41 @@ void retro::InitConsole()
EventAvail(everyEvent, &event);
}
r.top += 40;
InsetRect(&r, 5,5);
Console::currentInstance = new ConsoleWindow(r, "\pRetro68 Console");
InitCursor();
r.top += 40;
InsetRect(&r, 5,5);
Console::currentInstance = new ConsoleWindow(r, "\pRetro68 Console");
InitCursor();
}
extern "C" ssize_t _consolewrite(int fd, const void *buf, size_t count)
{
if(!Console::currentInstance)
InitConsole();
if(Console::currentInstance == (Console*)-1)
return 0;
if(!Console::currentInstance)
InitConsole();
if(Console::currentInstance == (Console*)-1)
return 0;
Console::currentInstance->write((const char*)buf, count);
return count;
Console::currentInstance->write((const char*)buf, count);
return count;
}
extern "C" ssize_t _consoleread(int fd, void *buf, size_t count)
{
if(!Console::currentInstance)
InitConsole();
if(Console::currentInstance == (Console*)-1)
return 0;
if(!Console::currentInstance)
InitConsole();
if(Console::currentInstance == (Console*)-1)
return 0;
static std::string consoleBuf;
if(consoleBuf.size() == 0)
{
consoleBuf = Console::currentInstance->ReadLine();
static std::string consoleBuf;
if(consoleBuf.size() == 0)
{
consoleBuf = Console::currentInstance->ReadLine();
if(!Console::currentInstance->IsEOF())
consoleBuf += "\n";
}
if(count > consoleBuf.size())
count = consoleBuf.size();
memcpy(buf, consoleBuf.data(), count);
consoleBuf = consoleBuf.substr(count);
return count;
}
if(count > consoleBuf.size())
count = consoleBuf.size();
memcpy(buf, consoleBuf.data(), count);
consoleBuf = consoleBuf.substr(count);
return count;
}

View File

@@ -25,22 +25,22 @@ bool dataSections = true;
bool dataInText = false;
using stringid = int;
unordered_map<stringid,stringid> sectionMap;
unordered_map<stringid,string> stringDictionary;
unordered_map<stringid,stringid> sectionMap;
unordered_map<stringid,string> stringDictionary;
unordered_set<stringid> localLabels;
enum RecordType {
kPad = 0,
kFirst = 1,
kLast = 2,
kPad = 0,
kFirst = 1,
kLast = 2,
kComment = 3,
kDictionary = 4,
kModule = 5,
kEntryPoint = 6,
kSize = 7,
kContent = 8,
kReference = 9,
kComputedRef = 10,
kDictionary = 4,
kModule = 5,
kEntryPoint = 6,
kSize = 7,
kContent = 8,
kReference = 9,
kComputedRef = 10,
kFilename = 11
};
@@ -49,19 +49,19 @@ enum ModuleFlags {
kExtern = 0x08 // default local
};
enum ReferenceFlags { // flags field of kReference
k16BitPatch = 0x10, // default 32Bit
kFromData = 0x01, // default fromCode
kA5Relative = 0x80, // default absolute
enum ReferenceFlags { // flags field of kReference
k16BitPatch = 0x10, // default 32Bit
kFromData = 0x01, // default fromCode
kA5Relative = 0x80, // default absolute
kUnknownReferenceFlags = 0x6E // rather a lot, isn't it?
// The following flags are known to exist from DumpOBJ,
// but their value is unkown as I haven't actually seen them yet:
// k32BitOffsets (default k16BitOffsets)
kUnknownReferenceFlags = 0x6E // rather a lot, isn't it?
// The following flags are known to exist from DumpOBJ,
// but their value is unkown as I haven't actually seen them yet:
// k32BitOffsets (default k16BitOffsets)
};
enum ComputedReferenceFlags {
kDifference = 0x80
kDifference = 0x80
};
enum ContentFlags {
@@ -73,97 +73,97 @@ enum ContentFlags {
string encodeIdentifier(stringid id)
{
const string& s = stringDictionary[id];
std::ostringstream ss;
std::ostringstream ss;
if(localLabels.find(id) != localLabels.end())
ss << "L" << id << ".";
if(s.empty() || isdigit(s[0]))
ss << "__z";
ss << "__z";
for(char c : s)
{
if(c == '_' || isalnum(c))
ss << c;
else
{
ss << "__z" << (int) c << "_";
}
}
for(char c : s)
{
if(c == '_' || isalnum(c))
ss << c;
else
{
ss << "__z" << (int) c << "_";
}
}
return ss.str();
return ss.str();
}
struct Reloc
{
int size;
stringid name1 = -1;
stringid name2 = -1;
int size;
stringid name1 = -1;
stringid name2 = -1;
int write(std::ostream& out, uint8_t *p);
int write(std::ostream& out, uint8_t *p);
};
int Reloc::write(std::ostream& out, uint8_t *p)
{
if(size == 2)
{
out << "\t.short ";
int val = (int)p[0] * 256 + p[1];
if(size == 2)
{
out << "\t.short ";
int val = (int)p[0] * 256 + p[1];
out << encodeIdentifier(name1);
if(name2 != -1)
out << " - " << encodeIdentifier(name2);
if(val > 0)
out << " + " << val;
else if(val < 0)
out << " - " << -val;
if(name2 == -1)
out << "-.";
out << std::endl;
return 2;
}
else if(size == 4)
{
out << "\t.long ";
int val = ((int)p[0] << 24) | ((int)p[1] << 16) | ((int)p[2] << 8) | p[3];
out << encodeIdentifier(name1);
if(name2 != -1)
out << " - " << encodeIdentifier(name2);
if(val > 0)
out << " + " << val;
else if(val < 0)
out << " - " << -val;
if(name2 == -1)
out << "-.";
out << std::endl;
return 2;
}
else if(size == 4)
{
out << "\t.long ";
int val = ((int)p[0] << 24) | ((int)p[1] << 16) | ((int)p[2] << 8) | p[3];
out << encodeIdentifier(name1);
if(name2 != -1)
out << " - " << encodeIdentifier(name2);
if(val > 0)
out << " + " << val;
else if(val < 0)
out << " - " << -val;
out << std::endl;
return 4;
}
else
{
assert(false);
return 1;
}
out << encodeIdentifier(name1);
if(name2 != -1)
out << " - " << encodeIdentifier(name2);
if(val > 0)
out << " + " << val;
else if(val < 0)
out << " - " << -val;
out << std::endl;
return 4;
}
else
{
assert(false);
return 1;
}
}
struct Module
{
stringid name;
stringid segment;
stringid name;
stringid segment;
bool isData;
vector<uint8_t> bytes;
unordered_map<uint32_t, vector<stringid>> labels;
unordered_map<uint32_t, Reloc> relocs;
vector<uint8_t> bytes;
unordered_map<uint32_t, vector<stringid>> labels;
unordered_map<uint32_t, Reloc> relocs;
std::vector<std::weak_ptr<Module>> nearrefs;
std::vector<std::weak_ptr<Module>> nearrefs;
void write(std::ostream& out);
void write(std::ostream& out);
};
void Module::write(std::ostream& out)
{
string encodedName = encodeIdentifier(sectionMap[name]);
string encodedName = encodeIdentifier(sectionMap[name]);
if(isData && !dataInText)
if(isData && !dataInText)
{
if(dataSections)
out << "\t.section .data." << encodedName << ",\"aw\"\n";
@@ -175,41 +175,41 @@ void Module::write(std::ostream& out)
else
{
if(functionSections)
out << "\t.section .text." << encodedName << ",\"ax\",@progbits\n";
out << "\t.section .text." << encodedName << ",\"ax\",@progbits\n";
else
out << "\t.section .text,\"ax\",@progbits\n";
out << "\t.section .text,\"ax\",@progbits\n";
out << "\t.align 2,0\n";
}
for(uint32_t offset = 0; offset < bytes.size();)
{
auto labelP = labels.find(offset);
if(labelP != labels.end())
{
for(stringid rawLabel : labelP->second)
{
string label = encodeIdentifier(rawLabel);
if(localLabels.find(rawLabel) == localLabels.end())
for(uint32_t offset = 0; offset < bytes.size();)
{
auto labelP = labels.find(offset);
if(labelP != labels.end())
{
for(stringid rawLabel : labelP->second)
{
string label = encodeIdentifier(rawLabel);
if(localLabels.find(rawLabel) == localLabels.end())
out << "\t.globl " << label << "\n";
out << label << ":\n";
}
}
out << label << ":\n";
}
}
auto relocP = relocs.find(offset);
if(relocP != relocs.end())
{
offset += relocP->second.write(out, &bytes[offset]);
}
else
{
out << "\t.byte " << (int)bytes[offset] << "\n";
offset++;
}
}
auto relocP = relocs.find(offset);
if(relocP != relocs.end())
{
offset += relocP->second.write(out, &bytes[offset]);
}
else
{
out << "\t.byte " << (int)bytes[offset] << "\n";
offset++;
}
}
if(addMacsbugNames && !isData)
{
if(functionSections)
out << "\t.section .text." << encodedName << ".macsbug,\"ax\",@progbits\n";
out << "\t.section .text." << encodedName << ".macsbug,\"ax\",@progbits\n";
if(encodedName.size() < 32)
out << "\t.byte " << (encodedName.size() | 0x80) << "\n";
else
@@ -218,38 +218,38 @@ void Module::write(std::ostream& out)
out << "\t.ascii \"" << encodedName << "\"\n";
out << "\t.align 2,0\n\t.short 0\n";
}
out << "# ######\n\n";
out << "# ######\n\n";
}
void sortModules(std::vector<std::shared_ptr<Module>>& modules)
{
std::set<stringid> unemitted;
for(auto& m : modules)
unemitted.insert(m->name);
std::unordered_map<stringid, std::shared_ptr<Module>> nameMap;
for(auto& m : modules)
for(auto& l : m->labels)
for(auto& str : l.second)
nameMap[str] = m;
for(auto& m : modules)
for(auto& r : m->relocs)
{
if(r.second.size != 2)
continue;
if(r.second.name2 == -1)
{
if(auto p = nameMap.find(r.second.name1); p != nameMap.end())
std::set<stringid> unemitted;
for(auto& m : modules)
unemitted.insert(m->name);
std::unordered_map<stringid, std::shared_ptr<Module>> nameMap;
for(auto& m : modules)
for(auto& l : m->labels)
for(auto& str : l.second)
nameMap[str] = m;
for(auto& m : modules)
for(auto& r : m->relocs)
{
if(r.second.size != 2)
continue;
if(r.second.name2 == -1)
{
if(auto p = nameMap.find(r.second.name1); p != nameMap.end())
{
std::shared_ptr<Module> m1 = p->second;
m1->nearrefs.push_back(m);
m->nearrefs.push_back(m1);
}
}
else
{
}
else
{
auto p1 = nameMap.find(r.second.name1);
auto p2 = nameMap.find(r.second.name2);
@@ -260,60 +260,60 @@ void sortModules(std::vector<std::shared_ptr<Module>>& modules)
m1->nearrefs.push_back(m2);
m2->nearrefs.push_back(m1);
}
}
}
}
}
std::vector<std::shared_ptr<Module>> sorted;
sorted.reserve(modules.size());
auto p = sorted.begin();
while(!unemitted.empty())
{
while(p != sorted.end())
{
for(auto& m2weak : (*p)->nearrefs)
{
if(std::shared_ptr<Module> m2 = m2weak.lock())
{
auto unemittedP = unemitted.find(m2->name);
if(unemittedP != unemitted.end())
{
sorted.push_back(m2);
unemitted.erase(unemittedP);
}
}
}
++p;
}
std::vector<std::shared_ptr<Module>> sorted;
sorted.reserve(modules.size());
auto p = sorted.begin();
while(!unemitted.empty())
{
while(p != sorted.end())
{
for(auto& m2weak : (*p)->nearrefs)
{
if(std::shared_ptr<Module> m2 = m2weak.lock())
{
auto unemittedP = unemitted.find(m2->name);
if(unemittedP != unemitted.end())
{
sorted.push_back(m2);
unemitted.erase(unemittedP);
}
}
}
++p;
}
if(!unemitted.empty())
{
sorted.push_back(nameMap[*unemitted.begin()]);
unemitted.erase(unemitted.begin());
}
}
sorted.swap(modules);
}
sorted.swap(modules);
}
int main(int argc, char* argv[])
{
if(argc != 2)
{
std::cerr << "Usage: ConvertOBJ mpw.o > retro68.s\n";
return 1;
}
std::ifstream in(argv[1]);
if(!in)
{
std::cerr << "Could not read imput file \"" << argv[1] << "\"\n";
std::cerr << "Usage: ConvertOBJ mpw.o > retro68.s\n";
return 1;
}
std::shared_ptr<Module> module;
std::vector<std::shared_ptr<Module>> modules;
if(argc != 2)
{
std::cerr << "Usage: ConvertOBJ mpw.o > retro68.s\n";
return 1;
}
std::ifstream in(argv[1]);
if(!in)
{
std::cerr << "Could not read imput file \"" << argv[1] << "\"\n";
std::cerr << "Usage: ConvertOBJ mpw.o > retro68.s\n";
return 1;
}
std::shared_ptr<Module> module;
std::vector<std::shared_ptr<Module>> modules;
{
@@ -343,30 +343,30 @@ int main(int argc, char* argv[])
std::cout << "\t.text\n\t.align 2\n";
for(bool endOfObject = false; !endOfObject;) {
if(verbose)
std::cerr << std::hex << in.tellg() << ": ";
int recordType = byte(in);
if(!in)
{
std::cerr << "Unexpected End of File\n";
return 1;
}
for(bool endOfObject = false; !endOfObject;) {
if(verbose)
std::cerr << std::hex << in.tellg() << ": ";
int recordType = byte(in);
if(!in)
{
std::cerr << "Unexpected End of File\n";
return 1;
}
if(verbose)
std::cerr << "Record: " << recordType << std::endl;
if(verbose)
std::cerr << "Record: " << recordType << std::endl;
switch(recordType)
{
case kPad:
if(verbose)
std::cerr << "Pad\n";
break;
switch(recordType)
{
case kPad:
if(verbose)
std::cerr << "Pad\n";
break;
case kComment:
{
/*int flags =*/ byte(in);
int size = word(in);
/*int flags =*/ byte(in);
int size = word(in);
size -= 4;
if(verbose)
std::cerr << "Comment: ";
@@ -380,189 +380,189 @@ int main(int argc, char* argv[])
std::cerr << std::endl;
}
break;
case kDictionary:
{
/*int flags =*/ byte(in);
if(verbose)
std::cerr << "Dictionary\n";
int sz = word(in);
int stringId = word(in);
int end = (int)(in.tellg()) - 6 + sz;
while(in.tellg() < end)
{
int n = byte(in);
string s;
for(int i = 0; i < n; i++)
s += (char) byte(in);
if(verbose)
std::cerr << s << std::endl;
stringDictionary[stringId++] = s;
}
}
break;
case kModule:
{
int flags = byte(in);
stringid name = word(in);
sectionMap[name] = name;
stringid segment = word(in);
case kDictionary:
{
/*int flags =*/ byte(in);
if(verbose)
std::cerr << "Dictionary\n";
int sz = word(in);
int stringId = word(in);
int end = (int)(in.tellg()) - 6 + sz;
while(in.tellg() < end)
{
int n = byte(in);
string s;
for(int i = 0; i < n; i++)
s += (char) byte(in);
if(verbose)
std::cerr << s << std::endl;
stringDictionary[stringId++] = s;
}
}
break;
case kModule:
{
int flags = byte(in);
stringid name = word(in);
sectionMap[name] = name;
stringid segment = word(in);
if(verbose)
std::cerr << "Module " << stringDictionary[name] << "(" << stringDictionary[segment] << "), flags = " << flags << "\n";
if(verbose)
std::cerr << "Module " << stringDictionary[name] << "(" << stringDictionary[segment] << "), flags = " << flags << "\n";
if((flags & kExtern) == 0)
localLabels.insert(name);
module.reset(new Module());
module->name = name;
module.reset(new Module());
module->name = name;
module->segment = segment;
module->isData = (flags & kData) != 0;
module->labels[0].push_back(name);
modules.push_back(module);
}
break;
case kContent:
{
int flags = byte(in);
int sz = word(in) - 4;
uint32_t offset = 0;
if(flags & kContentOffset)
{
offset = longword(in);
sz -= 4;
}
module->labels[0].push_back(name);
modules.push_back(module);
}
break;
case kContent:
{
int flags = byte(in);
int sz = word(in) - 4;
uint32_t offset = 0;
if(flags & kContentOffset)
{
offset = longword(in);
sz -= 4;
}
int repeat = 1;
if(flags & kContentRepeat)
{
repeat = word(in);
sz -= 2;
}
if(verbose)
std::cerr << "Content (offset = " << offset << ", size = " << sz << ", repeat = " << repeat << ")\n";
if(verbose)
std::cerr << "Content (offset = " << offset << ", size = " << sz << ", repeat = " << repeat << ")\n";
assert(module.get());
if(module->bytes.size() < offset + sz * repeat)
module->bytes.resize(offset + sz * repeat);
in.read((char*) &module->bytes[offset], sz);
assert(module.get());
if(module->bytes.size() < offset + sz * repeat)
module->bytes.resize(offset + sz * repeat);
in.read((char*) &module->bytes[offset], sz);
while(--repeat > 0)
{
std::copy(module->bytes.begin() + offset, module->bytes.begin() + offset + sz,
module->bytes.begin() + offset + sz);
offset += sz;
}
}
break;
case kSize:
{
/*int flags =*/ byte(in);
long size = longword(in);
if(verbose)
std::cerr << "Size " << size << "\n";
assert(module.get());
module->bytes.resize(size);
}
break;
case kReference:
{
int flags = byte(in);
int sz = word(in);
int end = (int)(in.tellg()) - 4 + sz;
stringid name = word(in);
}
break;
case kSize:
{
/*int flags =*/ byte(in);
long size = longword(in);
if(verbose)
std::cerr << "Size " << size << "\n";
assert(module.get());
module->bytes.resize(size);
}
break;
case kReference:
{
int flags = byte(in);
int sz = word(in);
int end = (int)(in.tellg()) - 4 + sz;
stringid name = word(in);
if(verbose)
std::cerr << "Reference to " << stringDictionary[name] << " at\n";
Reloc reloc;
reloc.name1 = name;
if(verbose)
std::cerr << "Reference to " << stringDictionary[name] << " at\n";
Reloc reloc;
reloc.name1 = name;
if(flags & kUnknownReferenceFlags)
{
std::cerr << "Unknown relocation flags: 0x" << std::hex << flags << std::endl;
std::cerr << "Cannot convert this file.\n";
std::exit(1);
}
if(flags & kA5Relative)
{
std::cerr << "Unsupported relocation flags: 0x" << std::hex << flags << std::endl;
std::cerr << "MPW .o files with near-model global variables or calls to imported functions will not work.\n";
std::cerr << "Cannot convert this file.\n";
std::exit(1);
}
flags &= ~kFromData; // FIXME: sticking data bits in the text section, not nice, but might sometimes work
if(flags & kUnknownReferenceFlags)
{
std::cerr << "Unknown relocation flags: 0x" << std::hex << flags << std::endl;
std::cerr << "Cannot convert this file.\n";
std::exit(1);
}
if(flags & kA5Relative)
{
std::cerr << "Unsupported relocation flags: 0x" << std::hex << flags << std::endl;
std::cerr << "MPW .o files with near-model global variables or calls to imported functions will not work.\n";
std::cerr << "Cannot convert this file.\n";
std::exit(1);
}
flags &= ~kFromData; // FIXME: sticking data bits in the text section, not nice, but might sometimes work
reloc.size = (flags & k16BitPatch ? 2 : 4);
reloc.size = (flags & k16BitPatch ? 2 : 4);
assert(module);
assert(module);
while(in.tellg() < end)
{
int offset = word(in);
if(verbose)
std::cerr << " " << offset << std::endl;
module->relocs[offset] = reloc;
}
}
break;
case kEntryPoint:
{
int flags = byte(in);
stringid name = word(in);
long offset = longword(in);
if(verbose)
std::cerr << "EntryPoint " << stringDictionary[name] << " at offset " << offset << "\n";
while(in.tellg() < end)
{
int offset = word(in);
if(verbose)
std::cerr << " " << offset << std::endl;
module->relocs[offset] = reloc;
}
}
break;
case kEntryPoint:
{
int flags = byte(in);
stringid name = word(in);
long offset = longword(in);
if(verbose)
std::cerr << "EntryPoint " << stringDictionary[name] << " at offset " << offset << "\n";
if((flags & kExtern) == 0)
localLabels.insert(name);
assert(module);
module->labels[offset].push_back(name);
}
break;
case kComputedRef:
{
int flags = byte(in);
int sz = word(in);
int end = (int)(in.tellg()) - 4 + sz;
stringid name1 = word(in);
stringid name2 = word(in);
assert(module);
module->labels[offset].push_back(name);
}
break;
case kComputedRef:
{
int flags = byte(in);
int sz = word(in);
int end = (int)(in.tellg()) - 4 + sz;
stringid name1 = word(in);
stringid name2 = word(in);
Reloc reloc;
reloc.name1 = name1;
reloc.name2 = name2;
reloc.size = 2;
Reloc reloc;
reloc.name1 = name1;
reloc.name2 = name2;
reloc.size = 2;
assert(flags == 0x90);
assert(module);
assert(flags == 0x90);
assert(module);
if(auto p = sectionMap.find(name1); p != sectionMap.end())
sectionMap[module->name] = p->second;
if(verbose)
std::cerr << "ComputedReference to "
if(verbose)
std::cerr << "ComputedReference to "
<< stringDictionary[name1] << " - " << stringDictionary[name2] << " at\n";
while(in.tellg() < end)
{
int offset = word(in);
if(verbose)
std::cerr << " " << offset << std::endl;
module->relocs[offset] = reloc;
}
}
break;
while(in.tellg() < end)
{
int offset = word(in);
if(verbose)
std::cerr << " " << offset << std::endl;
module->relocs[offset] = reloc;
}
}
break;
case kFilename:
/* int flags = */ byte(in);
/* short nameref = */ word(in);
/* long date = */ longword(in);
break;
case kLast:
byte(in);
endOfObject = true;
break;
default:
std::cerr << "Unknown record (type " << recordType << ") at " << std::hex << in.tellg() << std::endl;
return 1;
}
}
if(shouldSortModules)
sortModules(modules);
for(auto& m : modules)
m->write(std::cout);
return 0;
case kLast:
byte(in);
endOfObject = true;
break;
default:
std::cerr << "Unknown record (type " << recordType << ") at " << std::hex << in.tellg() << std::endl;
return 1;
}
}
if(shouldSortModules)
sortModules(modules);
for(auto& m : modules)
m->write(std::cout);
return 0;
}

View File

@@ -18,12 +18,12 @@
find_package(Boost COMPONENTS REQUIRED)
add_executable(Elf2Mac
Elf2Mac.h Elf2Mac.cc SegmentMap.cc LdScript.cc
Reloc.h Reloc.cc
Symbol.h Symbol.cc
Symtab.h Symtab.cc
Section.h Section.cc
Object.h Object.cc)
Elf2Mac.h Elf2Mac.cc SegmentMap.cc LdScript.cc
Reloc.h Reloc.cc
Symbol.h Symbol.cc
Symtab.h Symtab.cc
Section.h Section.cc
Object.h Object.cc)
target_link_libraries(Elf2Mac ResourceFiles ELF)
target_include_directories(Elf2Mac PRIVATE ${CMAKE_INSTALL_PREFIX}/include)

View File

@@ -1,20 +1,20 @@
/*
Copyright 2017 Wolfgang Thaller.
Copyright 2017 Wolfgang Thaller.
This file is part of Retro68.
This file is part of Retro68.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Elf2Mac.h"
@@ -45,179 +45,179 @@ string argvZero;
void RealLD(vector<string> args)
{
vector<const char*> argv;
string realLD = argvZero + ".real";
argv.push_back(realLD.c_str());
for(string& s : args)
argv.push_back(s.c_str());
argv.push_back(NULL);
vector<const char*> argv;
string realLD = argvZero + ".real";
argv.push_back(realLD.c_str());
for(string& s : args)
argv.push_back(s.c_str());
argv.push_back(NULL);
pid_t pid = fork();
if(pid < 0)
{
perror("unable to fork");
exit(-1);
}
else if(pid == 0)
{
execvp(argv[0], const_cast<char* const *> (argv.data()));
perror("exec failed");
exit(-1);
}
else
{
int wstatus;
int result = 0;
do
{
result = waitpid(pid, &wstatus, 0);
} while(result == -1 && errno == EINTR);
if(!WIFEXITED(wstatus))
{
errx(EXIT_FAILURE, "ld process did not exit properly");
}
else
{
int exitcode = WEXITSTATUS(wstatus);
if(exitcode)
exit(exitcode);
}
}
pid_t pid = fork();
if(pid < 0)
{
perror("unable to fork");
exit(-1);
}
else if(pid == 0)
{
execvp(argv[0], const_cast<char* const *> (argv.data()));
perror("exec failed");
exit(-1);
}
else
{
int wstatus;
int result = 0;
do
{
result = waitpid(pid, &wstatus, 0);
} while(result == -1 && errno == EINTR);
if(!WIFEXITED(wstatus))
{
errx(EXIT_FAILURE, "ld process did not exit properly");
}
else
{
int exitcode = WEXITSTATUS(wstatus);
if(exitcode)
exit(exitcode);
}
}
}
int main(int argc, char *argv[])
{
vector<string> args;
std::copy(argv + 1, argv+argc, std::back_inserter(args));
argvZero = argv[0];
vector<string> args;
std::copy(argv + 1, argv+argc, std::back_inserter(args));
argvZero = argv[0];
if(boost::algorithm::ends_with(argv[0], "ld"))
{
string outputFile = "a.out";
if(boost::algorithm::ends_with(argv[0], "ld"))
{
string outputFile = "a.out";
string entryPoint = "_start";
bool elf2mac = false;
bool flatoutput = false;
bool segments = true;
bool stripMacsbug = false;
bool elf2mac = false;
bool flatoutput = false;
bool segments = true;
bool stripMacsbug = false;
bool saveLdScript = false;
SegmentMap segmentMap;
SegmentMap segmentMap;
vector<string> args2;
for(auto p = args.begin(), e = args.end(); p != e; ++p)
{
if(*p == "-o")
{
++p;
if(p == e)
errx(EXIT_FAILURE, "-o missing argument");
outputFile = *p;
}
else if(boost::algorithm::starts_with(*p, "-o"))
{
outputFile = (*p).substr(2);
}
else if(*p == "-elf2mac" || *p == "--elf2mac")
{
elf2mac = true;
}
vector<string> args2;
for(auto p = args.begin(), e = args.end(); p != e; ++p)
{
if(*p == "-o")
{
++p;
if(p == e)
errx(EXIT_FAILURE, "-o missing argument");
outputFile = *p;
}
else if(boost::algorithm::starts_with(*p, "-o"))
{
outputFile = (*p).substr(2);
}
else if(*p == "-elf2mac" || *p == "--elf2mac")
{
elf2mac = true;
}
else if(*p == "-e")
{
++p;
if(p == e)
errx(EXIT_FAILURE, "-e missing argument");
entryPoint = *p;
}
{
++p;
if(p == e)
errx(EXIT_FAILURE, "-e missing argument");
entryPoint = *p;
}
else if(boost::algorithm::starts_with(*p, "-e"))
{
entryPoint = (*p).substr(2);
}
else if(*p == "--mac-flat")
{
elf2mac = true;
flatoutput = true;
segments = false;
}
else if(*p == "--mac-single")
{
elf2mac = true;
flatoutput = false;
segments = false;
}
else if(*p == "--mac-segments")
{
elf2mac = true;
if(flatoutput)
errx(EXIT_FAILURE, "--mac-segments can't be used with --mac-flat");
++p;
if(p == e)
errx(EXIT_FAILURE, "--mac-segments missing argument");
segmentMap = SegmentMap(*p);
}
else if(*p == "--mac-strip-macsbug")
{
stripMacsbug = true;
}
else if(*p == "--mac-flat")
{
elf2mac = true;
flatoutput = true;
segments = false;
}
else if(*p == "--mac-single")
{
elf2mac = true;
flatoutput = false;
segments = false;
}
else if(*p == "--mac-segments")
{
elf2mac = true;
if(flatoutput)
errx(EXIT_FAILURE, "--mac-segments can't be used with --mac-flat");
++p;
if(p == e)
errx(EXIT_FAILURE, "--mac-segments missing argument");
segmentMap = SegmentMap(*p);
}
else if(*p == "--mac-strip-macsbug")
{
stripMacsbug = true;
}
else if(*p == "--mac-keep-ldscript")
{
saveLdScript = true;
}
else
{
args2.push_back(*p);
}
}
else
{
args2.push_back(*p);
}
}
if(elf2mac)
{
char tmpfile[] = "/tmp/ldscriptXXXXXX";
int fd = mkstemp(tmpfile);
if(fd < 0)
errx(EXIT_FAILURE, "can't create temp file");
if(elf2mac)
{
char tmpfile[] = "/tmp/ldscriptXXXXXX";
int fd = mkstemp(tmpfile);
if(fd < 0)
errx(EXIT_FAILURE, "can't create temp file");
{
ofstream out(tmpfile);
if(segments)
{
segmentMap.CreateLdScript(out, entryPoint, stripMacsbug);
}
else
{
CreateFlatLdScript(out, entryPoint, stripMacsbug);
}
}
{
ofstream out(tmpfile);
if(segments)
{
segmentMap.CreateLdScript(out, entryPoint, stripMacsbug);
}
else
{
CreateFlatLdScript(out, entryPoint, stripMacsbug);
}
}
args2.push_back("-o");
args2.push_back(outputFile + ".gdb");
args2.push_back("-T");
args2.push_back(tmpfile);
RealLD(args2);
if(saveLdScript)
args2.push_back("-o");
args2.push_back(outputFile + ".gdb");
args2.push_back("-T");
args2.push_back(tmpfile);
RealLD(args2);
if(saveLdScript)
std::cerr << "Ld Script at: " << tmpfile << std::endl;
else
unlink(tmpfile);
Object theObject(outputFile + ".gdb");
if(flatoutput)
theObject.FlatCode(outputFile);
else if(segments)
theObject.MultiSegmentApp(outputFile, segmentMap);
else
theObject.SingleSegmentApp(outputFile);
}
else
{
RealLD(args);
}
return 0;
}
else
{
if(argc != 2)
errx(EXIT_FAILURE, "usage : %s file-name ", argv[0]);
Object theObject(argv[1]);
SegmentMap segmentMap;
theObject.MultiSegmentApp("out.bin", segmentMap);
}
return 0;
Object theObject(outputFile + ".gdb");
if(flatoutput)
theObject.FlatCode(outputFile);
else if(segments)
theObject.MultiSegmentApp(outputFile, segmentMap);
else
theObject.SingleSegmentApp(outputFile);
}
else
{
RealLD(args);
}
return 0;
}
else
{
if(argc != 2)
errx(EXIT_FAILURE, "usage : %s file-name ", argv[0]);
Object theObject(argv[1]);
SegmentMap segmentMap;
theObject.MultiSegmentApp("out.bin", segmentMap);
}
return 0;
}

View File

@@ -1,20 +1,20 @@
/*
Copyright 2017 Wolfgang Thaller.
Copyright 2017 Wolfgang Thaller.
This file is part of Retro68.
This file is part of Retro68.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ELF2MAC_H

View File

@@ -1,20 +1,20 @@
/*
Copyright 2017 Wolfgang Thaller.
Copyright 2017 Wolfgang Thaller.
This file is part of Retro68.
This file is part of Retro68.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Elf2Mac.h"
@@ -34,7 +34,7 @@ SECTIONS
)ld";
const char * textSection = R"ld(/* ld script for Elf2Mac */
.text : {
.text : {
_stext = . ;
PROVIDE(_rsrc_start = .);
*(.rsrcheader)
@@ -142,7 +142,7 @@ const char * scriptEnd = R"ld(
* Keep them for now, they are discarded by Elf2Mac. */
/DISCARD/ : { *(.note.GNU-stack) }
/* Stabs debugging sections. */
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
@@ -184,120 +184,120 @@ const char * scriptEnd = R"ld(
void CreateFlatLdScript(std::ostream& out, string entryPoint, bool stripMacsbug)
{
out << "_MULTISEG_APP = 0;\n";
out << boost::replace_all_copy<string>(scriptStart, "@entryPoint@", entryPoint);
if(stripMacsbug)
{
out << "\t.strippedmacsbugnames 0 (NOLOAD) : { *(.text.*.macsbug) }\n";
out << "\t. = 0;\n";
}
out << boost::replace_all_copy<string>(textSection, "@entryPoint@", entryPoint) << scriptEnd;
out << "_MULTISEG_APP = 0;\n";
out << boost::replace_all_copy<string>(scriptStart, "@entryPoint@", entryPoint);
if(stripMacsbug)
{
out << "\t.strippedmacsbugnames 0 (NOLOAD) : { *(.text.*.macsbug) }\n";
out << "\t. = 0;\n";
}
out << boost::replace_all_copy<string>(textSection, "@entryPoint@", entryPoint) << scriptEnd;
}
void SegmentInfo::WriteFilters(std::ostream &out, string section)
{
for(string filter : filters)
{
out << " " << filter << "(" << section << ")\n";
out << " " << filter << "(" << section << ".*)\n";
}
for(string filter : filters)
{
out << " " << filter << "(" << section << ")\n";
out << " " << filter << "(" << section << ".*)\n";
}
}
void SegmentInfo::WriteFiltersKeep(std::ostream &out, string section)
{
for(string filter : filters)
{
out << "\t\tKEEP(" << filter << "(" << section << "))\n";
out << "\t\tKEEP(" << filter << "(" << section << ".*))\n";
}
for(string filter : filters)
{
out << "\t\tKEEP(" << filter << "(" << section << "))\n";
out << "\t\tKEEP(" << filter << "(" << section << ".*))\n";
}
}
void SegmentInfo::CreateLdScript(std::ostream &out, string entryPoint)
{
out << "\t.code" << id << " : {\n";
out << "\t\tFILL(0x4E71);\n";
if(id == 1)
{
out << boost::replace_all_copy<string>(R"ld(
_stext = .;
FILL(0x4E71);
PROVIDE(_rsrc_start = .);
. = ALIGN (2);
_entry_trampoline = .;
SHORT(DEFINED(__break_on_entry) ? 0xA9FF : 0x4e71);
LONG(0x61000002); /* bsr *+2 */
SHORT(0x0697); /* addi.l #_, (a7) */
LONG(@entryPoint@ - _entry_trampoline - 6);
PROVIDE(_start = .); /* fallback entry point to a safe spot - needed for libretro bootstrap */
SHORT(0x4e75); /* rts */
out << "\t.code" << id << " : {\n";
out << "\t\tFILL(0x4E71);\n";
if(id == 1)
{
out << boost::replace_all_copy<string>(R"ld(
_stext = .;
FILL(0x4E71);
PROVIDE(_rsrc_start = .);
. = ALIGN (2);
_entry_trampoline = .;
SHORT(DEFINED(__break_on_entry) ? 0xA9FF : 0x4e71);
LONG(0x61000002); /* bsr *+2 */
SHORT(0x0697); /* addi.l #_, (a7) */
LONG(@entryPoint@ - _entry_trampoline - 6);
PROVIDE(_start = .); /* fallback entry point to a safe spot - needed for libretro bootstrap */
SHORT(0x4e75); /* rts */
FILL(0);
*(.relocvars)
FILL(0x4E71);
FILL(0);
*(.relocvars)
FILL(0x4E71);
)ld", "@entryPoint@", entryPoint);
}
WriteFilters(out, ".text");
}
WriteFilters(out, ".text");
if(id == 2)
{
out << "\t\t*(.gnu.linkonce.t*)\n";
}
if(id == 1)
{
out << R"ld(
. = ALIGN (4) ;
__init_section = .;
KEEP (*(.init))
__init_section_end = .;
__fini_section = .;
KEEP (*(.fini))
__fini_section_end = .;
if(id == 2)
{
out << "\t\t*(.gnu.linkonce.t*)\n";
}
if(id == 1)
{
out << R"ld(
. = ALIGN (4) ;
__init_section = .;
KEEP (*(.init))
__init_section_end = .;
__fini_section = .;
KEEP (*(.fini))
__fini_section_end = .;
)ld";
}
}
out << "\t\t. = ALIGN (4);\n"; // this is important, for some reason.
if(id == 1)
out << "\t\t__EH_FRAME_BEGIN__" << " = .;\n";
else
out << "\t\t__EH_FRAME_BEGIN__" << id << " = .;\n";
WriteFiltersKeep(out, ".eh_frame");
out << "\t\tLONG(0);\n";
WriteFiltersKeep(out, ".gcc_except_table");
out << "\t\t. = ALIGN (4);\n"; // this is important, for some reason.
if(id == 1)
out << "\t\t__EH_FRAME_BEGIN__" << " = .;\n";
else
out << "\t\t__EH_FRAME_BEGIN__" << id << " = .;\n";
WriteFiltersKeep(out, ".eh_frame");
out << "\t\tLONG(0);\n";
WriteFiltersKeep(out, ".gcc_except_table");
if(id == 1)
{
out << R"ld(
. = ALIGN(0x4) ;
_etext = . ;
if(id == 1)
{
out << R"ld(
. = ALIGN(0x4) ;
_etext = . ;
)ld";
}
else
{
out << boost::replace_all_copy<string>(R"ld(
. = ALIGN(0x4);
FILL(0);
. += 32;
LONG(__EH_FRAME_BEGIN__@N@ - .);
}
else
{
out << boost::replace_all_copy<string>(R"ld(
. = ALIGN(0x4);
FILL(0);
. += 32;
LONG(__EH_FRAME_BEGIN__@N@ - .);
)ld", "@N@", boost::lexical_cast<string>(id));
}
}
out << "\t}\n";
out << "\t}\n";
}
void SegmentMap::CreateLdScript(std::ostream &out, string entryPoint, bool stripMacsbug)
{
out << "_MULTISEG_APP = 1;\n";
out << boost::replace_all_copy<string>(scriptStart, "@entryPoint@", entryPoint);
if(stripMacsbug)
{
out << "\t.strippedmacsbugnames 0 (NOLOAD) : { *(.text.*.macsbug) }\n";
out << "\t. = 0;\n";
}
for(SegmentInfo& seg: segments)
{
seg.CreateLdScript(out, entryPoint);
}
out << "_MULTISEG_APP = 1;\n";
out << boost::replace_all_copy<string>(scriptStart, "@entryPoint@", entryPoint);
if(stripMacsbug)
{
out << "\t.strippedmacsbugnames 0 (NOLOAD) : { *(.text.*.macsbug) }\n";
out << "\t. = 0;\n";
}
for(SegmentInfo& seg: segments)
{
seg.CreateLdScript(out, entryPoint);
}
out << scriptEnd;
out << scriptEnd;
}

View File

@@ -1,20 +1,20 @@
/*
Copyright 2017 Wolfgang Thaller.
Copyright 2017 Wolfgang Thaller.
This file is part of Retro68.
This file is part of Retro68.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Object.h"
@@ -52,173 +52,173 @@ Object::~Object()
Object::Object(string input)
{
if(elf_version ( EV_CURRENT ) == EV_NONE)
errx(EXIT_FAILURE , "ELF library initialization failed: %s", elf_errmsg( -1));
if(elf_version ( EV_CURRENT ) == EV_NONE)
errx(EXIT_FAILURE , "ELF library initialization failed: %s", elf_errmsg( -1));
int fd = open(input.c_str(), O_RDONLY, 0);
elf = elf_begin(fd, ELF_C_READ, NULL);
int fd = open(input.c_str(), O_RDONLY, 0);
elf = elf_begin(fd, ELF_C_READ, NULL);
elf_getshdrstrndx(elf, &sectionHeaderStringTableIdx);
elf_getshdrstrndx(elf, &sectionHeaderStringTableIdx);
GElf_Ehdr ehdr;
gelf_getehdr(elf, &ehdr);
GElf_Ehdr ehdr;
gelf_getehdr(elf, &ehdr);
int idx;
int idx;
idx = 1;
for(Elf_Scn *scn = NULL; (scn = elf_nextscn(elf, scn)) != NULL; idx++)
{
GElf_Shdr shdr;
gelf_getshdr(scn, &shdr);
std::string name = elf_strptr(elf, sectionHeaderStringTableIdx, shdr.sh_name);
if(shdr.sh_type == SHT_STRTAB)
{
if(name == ".strtab")
mainStringTableIdx = idx;
}
}
idx = 1;
for(Elf_Scn *scn = NULL; (scn = elf_nextscn(elf, scn)) != NULL; idx++)
{
GElf_Shdr shdr;
gelf_getshdr(scn, &shdr);
std::string name = elf_strptr(elf, sectionHeaderStringTableIdx, shdr.sh_name);
if(shdr.sh_type == SHT_STRTAB)
{
if(name == ".strtab")
mainStringTableIdx = idx;
}
}
idx = 1;
for(Elf_Scn *scn = NULL; (scn = elf_nextscn(elf, scn)) != NULL; idx++)
{
GElf_Shdr shdr;
gelf_getshdr(scn, &shdr);
std::string name = elf_strptr(elf, sectionHeaderStringTableIdx, shdr.sh_name);
//std::cout << "section #" << idx << ": " << name << std::endl;
//std::cout << " =" << shdr.sh_addr << " + " << shdr.sh_size << std::endl;
idx = 1;
for(Elf_Scn *scn = NULL; (scn = elf_nextscn(elf, scn)) != NULL; idx++)
{
GElf_Shdr shdr;
gelf_getshdr(scn, &shdr);
std::string name = elf_strptr(elf, sectionHeaderStringTableIdx, shdr.sh_name);
//std::cout << "section #" << idx << ": " << name << std::endl;
//std::cout << " =" << shdr.sh_addr << " + " << shdr.sh_size << std::endl;
if(shdr.sh_type == SHT_SYMTAB
&& !symtab)
{
symtab.reset(new Symtab(*this, scn));
}
if(shdr.sh_type == SHT_RELA)
{
if(boost::algorithm::starts_with(name,".rela."))
{
string progbitsName = name.substr(5);
assert(sections.find(progbitsName) != sections.end());
sections[progbitsName]->SetRela(scn);
}
}
if(shdr.sh_type == SHT_PROGBITS && (shdr.sh_flags & SHF_ALLOC))
{
SectionKind kind = SectionKind::code;
if(shdr.sh_type == SHT_SYMTAB
&& !symtab)
{
symtab.reset(new Symtab(*this, scn));
}
if(shdr.sh_type == SHT_RELA)
{
if(boost::algorithm::starts_with(name,".rela."))
{
string progbitsName = name.substr(5);
assert(sections.find(progbitsName) != sections.end());
sections[progbitsName]->SetRela(scn);
}
}
if(shdr.sh_type == SHT_PROGBITS && (shdr.sh_flags & SHF_ALLOC))
{
SectionKind kind = SectionKind::code;
if(name == ".data")
kind = SectionKind::data;
if(name == ".strippedmacsbugnames")
kind = SectionKind::undefined;
if(name == ".data")
kind = SectionKind::data;
if(name == ".strippedmacsbugnames")
kind = SectionKind::undefined;
auto section = make_shared<Section>(*this, name, idx, kind, scn);
auto section = make_shared<Section>(*this, name, idx, kind, scn);
sections[name] = sectionsByElfIndex[idx] = section;
if(kind == SectionKind::data)
dataSection = section;
else if(kind == SectionKind::code)
codeSections.push_back(section);
}
if(shdr.sh_type == SHT_NOBITS)
{
bssSection = sections[name] = sectionsByElfIndex[idx] =
make_shared<Section>(*this, name, idx, SectionKind::bss, scn);
}
}
sections[name] = sectionsByElfIndex[idx] = section;
if(kind == SectionKind::data)
dataSection = section;
else if(kind == SectionKind::code)
codeSections.push_back(section);
}
if(shdr.sh_type == SHT_NOBITS)
{
bssSection = sections[name] = sectionsByElfIndex[idx] =
make_shared<Section>(*this, name, idx, SectionKind::bss, scn);
}
}
std::sort(codeSections.begin(), codeSections.end(),
[](shared_ptr<Section> a, shared_ptr<Section> b) { return a->name < b->name; });
std::sort(codeSections.begin(), codeSections.end(),
[](shared_ptr<Section> a, shared_ptr<Section> b) { return a->name < b->name; });
}
void Object::FlatCode(std::ostream& out)
{
for(auto sec : codeSections)
{
sec->FixRelocs(true);
out << sec->GetData();
}
dataSection->FixRelocs(true);
out << dataSection->GetData();
for(auto sec : codeSections)
{
sec->FixRelocs(true);
out << sec->GetData();
}
dataSection->FixRelocs(true);
out << dataSection->GetData();
std::vector<RuntimeReloc> relocs;
for(auto sec : codeSections)
{
auto tmp = sec->GetRelocations(false);
relocs.insert(relocs.end(), tmp.begin(), tmp.end());
}
{
auto tmp = dataSection->GetRelocations(false);
relocs.insert(relocs.end(), tmp.begin(), tmp.end());
}
out << SerializeRelocs(relocs);
std::vector<RuntimeReloc> relocs;
for(auto sec : codeSections)
{
auto tmp = sec->GetRelocations(false);
relocs.insert(relocs.end(), tmp.begin(), tmp.end());
}
{
auto tmp = dataSection->GetRelocations(false);
relocs.insert(relocs.end(), tmp.begin(), tmp.end());
}
out << SerializeRelocs(relocs);
}
void Object::FlatCode(string fn)
{
ofstream out(fn);
FlatCode(out);
ofstream out(fn);
FlatCode(out);
}
std::string fromhex(std::string hex)
{
std::string bin;
int nibble;
bool haveNibble = false;
for(std::string::iterator p = hex.begin(); p != hex.end(); ++p)
{
if(std::isspace(*p))
continue;
assert(isdigit(*p) || (tolower(*p) >= 'a' && tolower(*p) <= 'f'));
int digit;
if(isdigit(*p))
digit = *p - '0';
else
digit = tolower(*p) - 'a' + 0xA;
std::string bin;
int nibble;
bool haveNibble = false;
for(std::string::iterator p = hex.begin(); p != hex.end(); ++p)
{
if(std::isspace(*p))
continue;
assert(isdigit(*p) || (tolower(*p) >= 'a' && tolower(*p) <= 'f'));
int digit;
if(isdigit(*p))
digit = *p - '0';
else
digit = tolower(*p) - 'a' + 0xA;
if(haveNibble)
{
bin += (char) ((nibble << 4) | digit);
haveNibble = false;
}
else
{
nibble = digit;
haveNibble = true;
}
}
return bin;
if(haveNibble)
{
bin += (char) ((nibble << 4) | digit);
haveNibble = false;
}
else
{
nibble = digit;
haveNibble = true;
}
}
return bin;
}
void Object::SingleSegmentApp(string output)
{
ResourceFile file(output);
Resources& rsrc = file.resources;
ResourceFile file(output);
Resources& rsrc = file.resources;
rsrc.addResource(Resource(ResType("CODE"), 0,
fromhex(
"00000028 00000000 00000008 00000020"
"0000 3F3C 0001 A9F0"
)
));
rsrc.addResource(Resource(ResType("CODE"), 0,
fromhex(
"00000028 00000000 00000008 00000020"
"0000 3F3C 0001 A9F0"
)
));
{
std::ostringstream code1;
word(code1, 0);
word(code1, 1);
FlatCode(code1);
{
std::ostringstream code1;
word(code1, 0);
word(code1, 1);
FlatCode(code1);
rsrc.addResource(Resource(ResType("CODE"), 1,
code1.str()));
}
rsrc.addResource(Resource(ResType("CODE"), 1,
code1.str()));
}
file.creator = ResType("????");
file.type = ResType("APPL");
file.creator = ResType("????");
file.type = ResType("APPL");
file.write();
file.write();
}
@@ -227,70 +227,70 @@ void Object::MultiSegmentApp(string output, SegmentMap& segmentMap)
{
bool noisy = false;
ResourceFile file(output);
Resources& rsrc = file.resources;
ResourceFile file(output);
Resources& rsrc = file.resources;
for(auto namedSec : sections)
{
namedSec.second->ScanRelocs();
}
for(auto namedSec : sections)
{
namedSec.second->ScanRelocs();
}
int jtEntryCount = 0;
unordered_map<int, vector<Symbol*>> jtEntries;
for(Symbol& sym : symtab->symbols)
{
if(sym.valid)
{
if(sym.referencedExternally && sym.sectionKind == SectionKind::code)
{
sym.needsJT = true;
sym.jtIndex = -1;
sym.section->jtEntries.push_back(&sym);
++jtEntryCount;
}
}
}
int jtEntryCount = 0;
unordered_map<int, vector<Symbol*>> jtEntries;
for(Symbol& sym : symtab->symbols)
{
if(sym.valid)
{
if(sym.referencedExternally && sym.sectionKind == SectionKind::code)
{
sym.needsJT = true;
sym.jtIndex = -1;
sym.section->jtEntries.push_back(&sym);
++jtEntryCount;
}
}
}
uint32_t data_and_bss_size = dataSection->shdr.sh_size + bssSection->shdr.sh_size;
uint32_t data_and_bss_size = dataSection->shdr.sh_size + bssSection->shdr.sh_size;
{
std::ostringstream code0;
longword(code0, 0x20 + 8 * (jtEntryCount+2));
longword(code0, data_and_bss_size);
longword(code0, 8 * (jtEntryCount+2));
longword(code0, 0x20);
{
std::ostringstream code0;
longword(code0, 0x20 + 8 * (jtEntryCount+2));
longword(code0, data_and_bss_size);
longword(code0, 8 * (jtEntryCount+2));
longword(code0, 0x20);
code0 << fromhex("0000 3F3C 0001 A9F0"); // jt entry for entrypoint
code0 << fromhex("0000 FFFF 0000 0000"); // 32-bit entries start from here
code0 << fromhex("0000 3F3C 0001 A9F0"); // jt entry for entrypoint
code0 << fromhex("0000 FFFF 0000 0000"); // 32-bit entries start from here
int jtIndex = 2;
int id = 1;
for(auto sec : codeSections)
{
sec->codeID = id;
int jtIndex = 2;
int id = 1;
for(auto sec : codeSections)
{
sec->codeID = id;
sec->firstJTEntryIndex = jtIndex;
sec->firstJTEntryIndex = jtIndex;
GElf_Shdr &shdr = sec->shdr;
GElf_Shdr &shdr = sec->shdr;
for(Symbol* jtEntry : sec->jtEntries)
{
word(code0, id);
word(code0, 0xA9F0);
uint32_t offset = jtEntry->st_value - shdr.sh_addr;
if(id == 1)
offset += 4;
else
offset += 40;
longword(code0, offset);
for(Symbol* jtEntry : sec->jtEntries)
{
word(code0, id);
word(code0, 0xA9F0);
uint32_t offset = jtEntry->st_value - shdr.sh_addr;
if(id == 1)
offset += 4;
else
offset += 40;
longword(code0, offset);
jtEntry->jtIndex = jtIndex++;
jtEntry->jtIndex = jtIndex++;
//std::cout << "JT Entry " << jtEntry->jtIndex << ": " << jtEntry->name << std::endl;
}
//std::cout << "JT Entry " << jtEntry->jtIndex << ": " << jtEntry->name << std::endl;
}
id++;
}
id++;
}
if(noisy)
{
@@ -302,69 +302,69 @@ void Object::MultiSegmentApp(string output, SegmentMap& segmentMap)
std::cout << ".bss: " << bssSection->shdr.sh_size << " bytes at A5-"
<< std::hex << bssSection->shdr.sh_size << std::dec << "\n";
}
rsrc.addResource(Resource(ResType("CODE"), 0, code0.str()));
}
rsrc.addResource(Resource(ResType("CODE"), 0, code0.str()));
}
for(auto sec : codeSections)
{
int id = sec->codeID;
if(id == 1)
sec->outputBase = 4; // standard 'CODE' header
else
sec->outputBase = 40; // far-model 'CODE' header
for(auto sec : codeSections)
{
int id = sec->codeID;
if(id == 1)
sec->outputBase = 4; // standard 'CODE' header
else
sec->outputBase = 40; // far-model 'CODE' header
string exceptionInfoMarker = "__EH_FRAME_BEGIN__";
if(id != 1)
exceptionInfoMarker += boost::lexical_cast<string>(id);
int exceptionInfoSym = symtab->FindSym(exceptionInfoMarker);
if(exceptionInfoSym != -1)
{
Symbol& s = symtab->GetSym(exceptionInfoSym);
sec->exceptionInfoStart = s.st_value;
string exceptionInfoMarker = "__EH_FRAME_BEGIN__";
if(id != 1)
exceptionInfoMarker += boost::lexical_cast<string>(id);
int exceptionInfoSym = symtab->FindSym(exceptionInfoMarker);
if(exceptionInfoSym != -1)
{
Symbol& s = symtab->GetSym(exceptionInfoSym);
sec->exceptionInfoStart = s.st_value;
int codeSize = sec->shdr.sh_size;
int exceptionSize = sec->shdr.sh_addr + codeSize - sec->exceptionInfoStart;
double percent = 100.0 * exceptionSize / codeSize;
int codeSize = sec->shdr.sh_size;
int exceptionSize = sec->shdr.sh_addr + codeSize - sec->exceptionInfoStart;
double percent = 100.0 * exceptionSize / codeSize;
if(noisy)
if(noisy)
std::cout << "CODE " << id << " has " << exceptionSize << " bytes of exception info (" << percent << "%)\n";
}
else if(noisy)
std::cout << "exception info marker not found: " << exceptionInfoMarker << std::endl;
}
dataSection->outputBase = -data_and_bss_size;
bssSection->outputBase = -bssSection->shdr.sh_size;
}
else if(noisy)
std::cout << "exception info marker not found: " << exceptionInfoMarker << std::endl;
}
dataSection->outputBase = -data_and_bss_size;
bssSection->outputBase = -bssSection->shdr.sh_size;
for(auto namedSec : sections)
{
namedSec.second->FixRelocs(false);
}
for(auto namedSec : sections)
{
namedSec.second->FixRelocs(false);
}
for(auto sec : codeSections)
{
int id = sec->codeID;
std::ostringstream code;
if(id == 1)
{
word(code, 0);
word(code, 1);
}
else
{
word(code, 0xFFFF);
word(code, 0);
longword(code, 0);
longword(code, 0);
longword(code, 8 * sec->firstJTEntryIndex );
longword(code, sec->jtEntries.size());
longword(code, 0); // reloc info for A5
longword(code, 0); // assumed address for A5
longword(code, 0); // reloc info for code
longword(code, 0); // assumed address for start of code resource
longword(code, 0);
}
code << sec->GetData();
for(auto sec : codeSections)
{
int id = sec->codeID;
std::ostringstream code;
if(id == 1)
{
word(code, 0);
word(code, 1);
}
else
{
word(code, 0xFFFF);
word(code, 0);
longword(code, 0);
longword(code, 0);
longword(code, 8 * sec->firstJTEntryIndex );
longword(code, sec->jtEntries.size());
longword(code, 0); // reloc info for A5
longword(code, 0); // assumed address for A5
longword(code, 0); // reloc info for code
longword(code, 0); // assumed address for start of code resource
longword(code, 0);
}
code << sec->GetData();
if(noisy)
{
@@ -377,24 +377,24 @@ void Object::MultiSegmentApp(string output, SegmentMap& segmentMap)
}
}
string segmentName = segmentMap.GetSegmentName(id);
string segmentName = segmentMap.GetSegmentName(id);
rsrc.addResource(Resource(ResType("CODE"), id,
code.str(),
segmentName));
rsrc.addResource(Resource(ResType("CODE"), id,
code.str(),
segmentName));
rsrc.addResource(Resource(ResType("RELA"),id, SerializeRelocs(sec->GetRelocations(true))));
}
rsrc.addResource(Resource(ResType("RELA"),id, SerializeRelocs(sec->GetRelocations(true))));
}
rsrc.addResource(Resource(ResType("DATA"),0, dataSection->GetData()));
rsrc.addResource(Resource(ResType("RELA"),0, SerializeRelocs(dataSection->GetRelocations(true))));
rsrc.addResource(Resource(ResType("DATA"),0, dataSection->GetData()));
rsrc.addResource(Resource(ResType("RELA"),0, SerializeRelocs(dataSection->GetRelocations(true))));
if(noisy)
std::cout << "DATA 0: " << dataSection->shdr.sh_size << " bytes\n";
std::cout << "DATA 0: " << dataSection->shdr.sh_size << " bytes\n";
file.creator = ResType("????");
file.type = ResType("APPL");
file.creator = ResType("????");
file.type = ResType("APPL");
file.write();
file.write();
}

View File

@@ -1,20 +1,20 @@
/*
Copyright 2017 Wolfgang Thaller.
Copyright 2017 Wolfgang Thaller.
This file is part of Retro68.
This file is part of Retro68.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OBJECT_H
@@ -36,25 +36,25 @@ class SegmentMap;
class Object
{
public:
Elf *elf;
std::unique_ptr<Symtab> symtab;
std::unordered_map<std::string, std::shared_ptr<Section>> sections;
std::unordered_map<int, std::shared_ptr<Section>> sectionsByElfIndex;
Elf *elf;
std::unique_ptr<Symtab> symtab;
std::unordered_map<std::string, std::shared_ptr<Section>> sections;
std::unordered_map<int, std::shared_ptr<Section>> sectionsByElfIndex;
std::vector<std::shared_ptr<Section>> codeSections;
std::shared_ptr<Section> dataSection, bssSection;
size_t sectionHeaderStringTableIdx;
size_t mainStringTableIdx;
std::vector<std::shared_ptr<Section>> codeSections;
std::shared_ptr<Section> dataSection, bssSection;
size_t sectionHeaderStringTableIdx;
size_t mainStringTableIdx;
Object(std::string input);
~Object();
Object(std::string input);
~Object();
void FlatCode(std::ostream& out);
void FlatCode(std::string fn);
void FlatCode(std::ostream& out);
void FlatCode(std::string fn);
void SingleSegmentApp(std::string output);
void MultiSegmentApp(std::string output, SegmentMap &segmentMap);
void SingleSegmentApp(std::string output);
void MultiSegmentApp(std::string output, SegmentMap &segmentMap);
};

View File

@@ -1,20 +1,20 @@
/*
Copyright 2017 Wolfgang Thaller.
Copyright 2017 Wolfgang Thaller.
This file is part of Retro68.
This file is part of Retro68.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Reloc.h"
@@ -32,38 +32,38 @@ Reloc::Reloc(const GElf_Rela &rela)
std::string SerializeRelocsUncompressed(std::vector<RuntimeReloc> relocs)
{
std::ostringstream out;
for(const auto& r : relocs)
{
longword(out, r.offset | ((int)r.base << 24));
}
longword(out, -1);
return out.str();
std::ostringstream out;
for(const auto& r : relocs)
{
longword(out, r.offset | ((int)r.base << 24));
}
longword(out, -1);
return out.str();
}
std::string SerializeRelocs(std::vector<RuntimeReloc> relocs)
{
std::ostringstream out;
uint32_t offset = -1;
std::ostringstream out;
uint32_t offset = -1;
for(const auto& r : relocs)
{
uint32_t delta = r.offset - offset;
offset = r.offset;
for(const auto& r : relocs)
{
uint32_t delta = r.offset - offset;
offset = r.offset;
uint32_t base = (uint32_t) r.base;
uint32_t base = (uint32_t) r.base;
uint32_t encoded = (delta << 2) | base;
uint32_t encoded = (delta << 2) | base;
while(encoded >= 128)
{
byte(out, (encoded & 0x7F) | 0x80);
encoded >>= 7;
}
byte(out, encoded);
}
while(encoded >= 128)
{
byte(out, (encoded & 0x7F) | 0x80);
encoded >>= 7;
}
byte(out, encoded);
}
byte(out, 0);
byte(out, 0);
return out.str();
return out.str();
}

View File

@@ -1,20 +1,20 @@
/*
Copyright 2017 Wolfgang Thaller.
Copyright 2017 Wolfgang Thaller.
This file is part of Retro68.
This file is part of Retro68.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef RELOC_H
@@ -28,30 +28,30 @@
enum class RelocBase
{
code = 0,
data,
bss,
jumptable,
code1
code = 0,
data,
bss,
jumptable,
code1
};
class Reloc : public GElf_Rela
{
public:
RelocBase relocBase;
RelocBase relocBase;
Reloc();
Reloc(const GElf_Rela& rela);
Reloc();
Reloc(const GElf_Rela& rela);
};
class RuntimeReloc
{
public:
RelocBase base;
uint32_t offset;
RelocBase base;
uint32_t offset;
RuntimeReloc() : base(RelocBase::code), offset(0) {}
RuntimeReloc(RelocBase b, uint32_t o) : base(b), offset(o) {}
RuntimeReloc() : base(RelocBase::code), offset(0) {}
RuntimeReloc(RelocBase b, uint32_t o) : base(b), offset(o) {}
};
std::string SerializeRelocsUncompressed(std::vector<RuntimeReloc> relocs);

View File

@@ -1,20 +1,20 @@
/*
Copyright 2017 Wolfgang Thaller.
Copyright 2017 Wolfgang Thaller.
This file is part of Retro68.
This file is part of Retro68.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Section.h"
@@ -43,198 +43,198 @@ Section::Section(Object& theObject, string name, int idx, SectionKind kind, Elf_
exceptionInfoStart(0),
codeID(-1), firstJTEntryIndex(0)
{
data = elf_getdata(elfsec, NULL);
gelf_getshdr(elfsec, &shdr);
outputBase = shdr.sh_addr;
data = elf_getdata(elfsec, NULL);
gelf_getshdr(elfsec, &shdr);
outputBase = shdr.sh_addr;
}
void Section::SetRela(Elf_Scn *scn)
{
relasec = scn;
GElf_Shdr rshdr;
gelf_getshdr(relasec, &rshdr);
relasec = scn;
GElf_Shdr rshdr;
gelf_getshdr(relasec, &rshdr);
int nRela = rshdr.sh_size / rshdr.sh_entsize;
Elf_Data *data = elf_getdata(relasec, NULL);
for(int i = 0; i < nRela; i++)
{
GElf_Rela rela;
gelf_getrela(data, i, &rela);
int nRela = rshdr.sh_size / rshdr.sh_entsize;
Elf_Data *data = elf_getdata(relasec, NULL);
for(int i = 0; i < nRela; i++)
{
GElf_Rela rela;
gelf_getrela(data, i, &rela);
if(rela.r_offset < shdr.sh_addr || rela.r_offset > shdr.sh_addr + shdr.sh_size - 4)
{
// FIXME: There are sometimes relocations beyond the end of the sections
// in LD output for some reason. That's bad. Let's ignore it.
continue;
}
relocs.push_back(rela);
}
if(rela.r_offset < shdr.sh_addr || rela.r_offset > shdr.sh_addr + shdr.sh_size - 4)
{
// FIXME: There are sometimes relocations beyond the end of the sections
// in LD output for some reason. That's bad. Let's ignore it.
continue;
}
relocs.push_back(rela);
}
std::sort(relocs.begin(), relocs.end(),
[](GElf_Rela& a, GElf_Rela& b) { return a.r_offset < b.r_offset; });
std::sort(relocs.begin(), relocs.end(),
[](GElf_Rela& a, GElf_Rela& b) { return a.r_offset < b.r_offset; });
}
uint32_t Section::GetSize()
{
return data->d_size;
return data->d_size;
}
string Section::GetData()
{
return string((char*)data->d_buf, (char*)data->d_buf + data->d_size);
return string((char*)data->d_buf, (char*)data->d_buf + data->d_size);
}
std::vector<RuntimeReloc> Section::GetRelocations(bool useOffsets)
{
std::vector<RuntimeReloc> outRelocs;
std::vector<RuntimeReloc> outRelocs;
for(auto& rela : relocs)
{
//printf("rel: %d %d %x %x\n", (int)GELF_R_TYPE(rela.r_info), (int)GELF_R_SYM(rela.r_info), (unsigned)rela.r_addend, (unsigned)rela.r_offset);
for(auto& rela : relocs)
{
//printf("rel: %d %d %x %x\n", (int)GELF_R_TYPE(rela.r_info), (int)GELF_R_SYM(rela.r_info), (unsigned)rela.r_addend, (unsigned)rela.r_offset);
int symidx = GELF_R_SYM(rela.r_info);
if(symidx == 0)
continue;
int symidx = GELF_R_SYM(rela.r_info);
if(symidx == 0)
continue;
Symbol& sym = theObject.symtab->GetSym(symidx);
Symbol& sym = theObject.symtab->GetSym(symidx);
if(sym.st_shndx == SHN_UNDEF || sym.st_shndx >= SHN_LORESERVE)
continue;
if(sym.sectionKind == SectionKind::undefined)
continue;
if(sym.st_shndx == SHN_UNDEF || sym.st_shndx >= SHN_LORESERVE)
continue;
if(sym.sectionKind == SectionKind::undefined)
continue;
if(GELF_R_TYPE(rela.r_info) == R_68K_32)
{
assert(sym.sectionKind != SectionKind::undefined);
if(GELF_R_TYPE(rela.r_info) == R_68K_32)
{
assert(sym.sectionKind != SectionKind::undefined);
uint32_t offset = rela.r_offset;
if(useOffsets)
offset -= shdr.sh_addr;
uint32_t offset = rela.r_offset;
if(useOffsets)
offset -= shdr.sh_addr;
//longword(out, offset | ((int)rela.relocBase << 24));
outRelocs.emplace_back(rela.relocBase, offset);
}
}
//longword(out, offset | ((int)rela.relocBase << 24));
outRelocs.emplace_back(rela.relocBase, offset);
}
}
return outRelocs;
return outRelocs;
}
void Section::ScanRelocs()
{
for(Reloc& rela : relocs)
{
int symidx = GELF_R_SYM(rela.r_info);
if(symidx == 0)
continue;
for(Reloc& rela : relocs)
{
int symidx = GELF_R_SYM(rela.r_info);
if(symidx == 0)
continue;
Symbol *sym = &theObject.symtab->GetSym(symidx);
Symbol *sym = &theObject.symtab->GetSym(symidx);
if(sym->st_shndx == SHN_UNDEF)
continue;
if(sym->st_shndx == SHN_UNDEF)
continue;
if(rela.r_addend != 0)
{
int symidx2 = theObject.symtab->FindSym(sym->st_shndx, sym->st_value + rela.r_addend);
if(symidx2 != -1)
{
sym = &theObject.symtab->GetSym(symidx2);
rela.r_addend = 0;
rela.r_info = GELF_R_INFO(symidx2, GELF_R_TYPE(rela.r_info));
if(rela.r_addend != 0)
{
int symidx2 = theObject.symtab->FindSym(sym->st_shndx, sym->st_value + rela.r_addend);
if(symidx2 != -1)
{
sym = &theObject.symtab->GetSym(symidx2);
rela.r_addend = 0;
rela.r_info = GELF_R_INFO(symidx2, GELF_R_TYPE(rela.r_info));
}
}
}
}
if(sym->st_shndx != idx)
sym->referencedExternally = true;
}
if(sym->st_shndx != idx)
sym->referencedExternally = true;
}
}
void Section::FixRelocs(bool allowDirectCodeRefs)
{
for(Reloc& rela : relocs)
{
if(GELF_R_TYPE(rela.r_info) != R_68K_32)
continue;
for(Reloc& rela : relocs)
{
if(GELF_R_TYPE(rela.r_info) != R_68K_32)
continue;
int symidx = GELF_R_SYM(rela.r_info);
if(symidx == 0)
continue;
Symbol& sym = theObject.symtab->GetSym(symidx);
int symidx = GELF_R_SYM(rela.r_info);
if(symidx == 0)
continue;
Symbol& sym = theObject.symtab->GetSym(symidx);
if(sym.sectionKind == SectionKind::undefined)
continue;
if(sym.sectionKind == SectionKind::undefined)
continue;
RelocBase relocBase;
switch(sym.sectionKind)
{
case SectionKind::code:
relocBase = RelocBase::code;
if(sym.needsJT && (exceptionInfoStart == 0 || rela.r_offset < exceptionInfoStart || sym.name == "__gxx_personality_v0"))
{
if(rela.r_addend == 0)
{
relocBase = RelocBase::jumptable;
}
else
{
if(sym.section.get() != this)
{
std::cerr << "Invalid ref from "
<< name << ":" << std::hex << rela.r_offset-shdr.sh_addr << std::dec
<< " to " << sym.section->name
<< "(" << sym.name << ")"
<< "+" << rela.r_offset << std::endl;
}
assert(sym.section.get() == this);
}
}
else if(!allowDirectCodeRefs)
{
if(sym.section.get() != this)
{
std::cerr << "Invalid ref from "
<< name << ":" << std::hex << rela.r_offset-shdr.sh_addr << std::dec
<< " to " << sym.section->name
<< "(" << sym.name << ")"
<< "+" << rela.r_offset << std::endl;
std::cerr << "needsJT: " << (sym.needsJT ? "true" : "false") << std::endl;
std::cerr << "from addr: " << rela.r_offset << ", exceptionInfoStart: " << exceptionInfoStart << std::endl;
RelocBase relocBase;
switch(sym.sectionKind)
{
case SectionKind::code:
relocBase = RelocBase::code;
if(sym.needsJT && (exceptionInfoStart == 0 || rela.r_offset < exceptionInfoStart || sym.name == "__gxx_personality_v0"))
{
if(rela.r_addend == 0)
{
relocBase = RelocBase::jumptable;
}
else
{
if(sym.section.get() != this)
{
std::cerr << "Invalid ref from "
<< name << ":" << std::hex << rela.r_offset-shdr.sh_addr << std::dec
<< " to " << sym.section->name
<< "(" << sym.name << ")"
<< "+" << rela.r_offset << std::endl;
}
assert(sym.section.get() == this);
}
}
else if(!allowDirectCodeRefs)
{
if(sym.section.get() != this)
{
std::cerr << "Invalid ref from "
<< name << ":" << std::hex << rela.r_offset-shdr.sh_addr << std::dec
<< " to " << sym.section->name
<< "(" << sym.name << ")"
<< "+" << rela.r_offset << std::endl;
std::cerr << "needsJT: " << (sym.needsJT ? "true" : "false") << std::endl;
std::cerr << "from addr: " << rela.r_offset << ", exceptionInfoStart: " << exceptionInfoStart << std::endl;
}
assert(sym.section.get() == this);
}
break;
case SectionKind::data:
relocBase = RelocBase::data;
break;
case SectionKind::bss:
relocBase = RelocBase::bss;
break;
case SectionKind::undefined:
assert(false);
break;
}
rela.relocBase = relocBase;
}
assert(sym.section.get() == this);
}
break;
case SectionKind::data:
relocBase = RelocBase::data;
break;
case SectionKind::bss:
relocBase = RelocBase::bss;
break;
case SectionKind::undefined:
assert(false);
break;
}
rela.relocBase = relocBase;
uint8_t *relocand = ((uint8_t*) data->d_buf + rela.r_offset - shdr.sh_addr);
uint8_t *relocand = ((uint8_t*) data->d_buf + rela.r_offset - shdr.sh_addr);
if(relocBase == RelocBase::jumptable)
{
uint32_t dst = 0x20 + sym.jtIndex * 8 + 2;
relocand[0] = dst >> 24;
relocand[1] = dst >> 16;
relocand[2] = dst >> 8;
relocand[3] = dst;
}
else
{
uint32_t orig = (relocand[0] << 24) | (relocand[1] << 16) | (relocand[2] << 8) | relocand[3];
uint32_t dst = orig + sym.section->outputBase - sym.section->shdr.sh_addr;
relocand[0] = dst >> 24;
relocand[1] = dst >> 16;
relocand[2] = dst >> 8;
relocand[3] = dst;
}
}
if(relocBase == RelocBase::jumptable)
{
uint32_t dst = 0x20 + sym.jtIndex * 8 + 2;
relocand[0] = dst >> 24;
relocand[1] = dst >> 16;
relocand[2] = dst >> 8;
relocand[3] = dst;
}
else
{
uint32_t orig = (relocand[0] << 24) | (relocand[1] << 16) | (relocand[2] << 8) | relocand[3];
uint32_t dst = orig + sym.section->outputBase - sym.section->shdr.sh_addr;
relocand[0] = dst >> 24;
relocand[1] = dst >> 16;
relocand[2] = dst >> 8;
relocand[3] = dst;
}
}
}

View File

@@ -1,20 +1,20 @@
/*
Copyright 2017 Wolfgang Thaller.
Copyright 2017 Wolfgang Thaller.
This file is part of Retro68.
This file is part of Retro68.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SECTION_H
@@ -33,41 +33,41 @@ class RuntimeReloc;
enum class SectionKind
{
undefined = -1,
code = 0,
data,
bss
undefined = -1,
code = 0,
data,
bss
};
class Section
{
public:
Object& theObject;
std::string name;
int idx;
SectionKind kind;
Elf_Scn *elfsec, *relasec;
Elf_Data *data;
GElf_Shdr shdr;
uint32_t outputBase;
uint32_t exceptionInfoStart;
Object& theObject;
std::string name;
int idx;
SectionKind kind;
Elf_Scn *elfsec, *relasec;
Elf_Data *data;
GElf_Shdr shdr;
uint32_t outputBase;
uint32_t exceptionInfoStart;
int codeID;
int codeID;
std::vector<Reloc> relocs;
std::vector<Symbol*> jtEntries;
int firstJTEntryIndex;
std::vector<Reloc> relocs;
std::vector<Symbol*> jtEntries;
int firstJTEntryIndex;
Section(Object& object, std::string name, int idx, SectionKind kind, Elf_Scn *elfsec);
~Section();
void SetRela(Elf_Scn *scn);
Section(Object& object, std::string name, int idx, SectionKind kind, Elf_Scn *elfsec);
~Section();
void SetRela(Elf_Scn *scn);
uint32_t GetSize();
std::string GetData();
std::vector<RuntimeReloc> GetRelocations(bool useOffsets);
uint32_t GetSize();
std::string GetData();
std::vector<RuntimeReloc> GetRelocations(bool useOffsets);
void ScanRelocs();
void FixRelocs(bool allowDirectCodeRefs);
void ScanRelocs();
void FixRelocs(bool allowDirectCodeRefs);
};

View File

@@ -1,20 +1,20 @@
/*
Copyright 2017 Wolfgang Thaller.
Copyright 2017 Wolfgang Thaller.
This file is part of Retro68.
This file is part of Retro68.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
*/
#include "SegmentMap.h"
@@ -29,98 +29,98 @@ SegmentInfo::SegmentInfo()
SegmentMap::SegmentMap()
{
segments.emplace_back(1, "Runtime",
"*/libretrocrt.a:start.c.obj",
"*/libretrocrt.a:relocate.c.obj",
"*/libretrocrt.a:MultiSegApp.c.obj",
"*/libretrocrt.a:LoadSeg.s.obj",
"*/libretrocrt.a:*",
segments.emplace_back(1, "Runtime",
"*/libretrocrt.a:start.c.obj",
"*/libretrocrt.a:relocate.c.obj",
"*/libretrocrt.a:MultiSegApp.c.obj",
"*/libretrocrt.a:LoadSeg.s.obj",
"*/libretrocrt.a:*",
"*/libInterface.a:*",
"*/libgcc.a:*",
"*/libc.a:*"
);
segments.emplace_back(5, "libstdc++ locale",
"*/libstdc++.a:locale.o",
"*/libstdc++.a:locale_faces.o",
"*/libstdc++.a:locale_init.o");
segments.emplace_back(7, "libstdc++ locale-inst",
"*/libstdc++.a:locale-inst.o");
segments.emplace_back(8, "libstdc++ wlocale-inst",
"*/libstdc++.a:wlocale-inst.o");
segments.emplace_back(6, "libstdc++ cp-demangle",
"*/libstdc++.a:cp-demangle.o");
segments.emplace_back(3, "libstdc++",
"*/libstdc++.a:*");
segments.emplace_back(4, "RetroConsole",
"*/libRetroConsole.a:*");
"*/libgcc.a:*",
"*/libc.a:*"
);
segments.emplace_back(5, "libstdc++ locale",
"*/libstdc++.a:locale.o",
"*/libstdc++.a:locale_faces.o",
"*/libstdc++.a:locale_init.o");
segments.emplace_back(7, "libstdc++ locale-inst",
"*/libstdc++.a:locale-inst.o");
segments.emplace_back(8, "libstdc++ wlocale-inst",
"*/libstdc++.a:wlocale-inst.o");
segments.emplace_back(6, "libstdc++ cp-demangle",
"*/libstdc++.a:cp-demangle.o");
segments.emplace_back(3, "libstdc++",
"*/libstdc++.a:*");
segments.emplace_back(4, "RetroConsole",
"*/libRetroConsole.a:*");
segments.emplace_back(2, "Main",
"*");
segments.emplace_back(2, "Main",
"*");
}
SegmentMap::SegmentMap(std::string filename)
{
segments.emplace_back(1, "Runtime",
"*/libretrocrt.a:start.c.obj",
"*/libretrocrt.a:relocate.c.obj",
"*/libretrocrt.a:MultiSegApp.c.obj",
"*/libretrocrt.a:LoadSeg.s.obj",
"*/libretrocrt.a:*",
segments.emplace_back(1, "Runtime",
"*/libretrocrt.a:start.c.obj",
"*/libretrocrt.a:relocate.c.obj",
"*/libretrocrt.a:MultiSegApp.c.obj",
"*/libretrocrt.a:LoadSeg.s.obj",
"*/libretrocrt.a:*",
"*/libInterface.a:*",
"*/libgcc.a:*",
"*/libc.a:*"
);
"*/libgcc.a:*",
"*/libc.a:*"
);
std::ifstream in(filename);
int id = -1;
int nextID = 3;
while(in)
{
std::string s;
in >> std::ws;
std::getline(in, s);
//std::cout << "segs: " << s << std::endl;
if(!in)
break;
std::ifstream in(filename);
int id = -1;
int nextID = 3;
while(in)
{
std::string s;
in >> std::ws;
std::getline(in, s);
//std::cout << "segs: " << s << std::endl;
if(!in)
break;
std::string upper;
std::transform(s.begin(), s.end(), std::back_inserter(upper), [](char c) { return std::toupper(c); });
std::string upper;
std::transform(s.begin(), s.end(), std::back_inserter(upper), [](char c) { return std::toupper(c); });
if(s[0] == '#')
continue;
else if(upper == "SEGMENT" || (upper.substr(0,7) == "SEGMENT" && std::isspace(upper[7])))
{
std::string name;
if(s[0] == '#')
continue;
else if(upper == "SEGMENT" || (upper.substr(0,7) == "SEGMENT" && std::isspace(upper[7])))
{
std::string name;
auto p = s.begin() + 7;
while(p != s.end() && std::isspace(*p))
++p;
name = std::string(p, s.end());
id = nextID++;
auto p = s.begin() + 7;
while(p != s.end() && std::isspace(*p))
++p;
name = std::string(p, s.end());
id = nextID++;
segments.emplace_back(id, name);
}
else
{
if(id < 0)
{
throw std::runtime_error("missing SEGMENT directive.\n");
}
segments.emplace_back(id, name);
}
else
{
if(id < 0)
{
throw std::runtime_error("missing SEGMENT directive.\n");
}
segments.back().filters.push_back(s);
}
}
segments.back().filters.push_back(s);
}
}
segments.emplace_back(2, "Main",
"*");
segments.emplace_back(2, "Main",
"*");
}
std::string SegmentMap::GetSegmentName(int id)
{
for(auto& seg : segments)
{
if(seg.id == id)
return seg.name;
}
return "";
for(auto& seg : segments)
{
if(seg.id == id)
return seg.name;
}
return "";
}

View File

@@ -1,20 +1,20 @@
/*
Copyright 2017 Wolfgang Thaller.
Copyright 2017 Wolfgang Thaller.
This file is part of Retro68.
This file is part of Retro68.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SEGMENTMAP_H
@@ -26,31 +26,31 @@
class SegmentInfo
{
public:
int id;
std::string name;
std::vector<std::string> filters;
SegmentInfo();
int id;
std::string name;
std::vector<std::string> filters;
SegmentInfo();
template<typename... Args>
SegmentInfo(int id, std::string name, Args... args)
: id(id), name(name), filters { args... }
{
}
template<typename... Args>
SegmentInfo(int id, std::string name, Args... args)
: id(id), name(name), filters { args... }
{
}
void WriteFilters(std::ostream& out, std::string section);
void WriteFiltersKeep(std::ostream& out, std::string section);
void CreateLdScript(std::ostream& out, std::string entryPoint);
void WriteFilters(std::ostream& out, std::string section);
void WriteFiltersKeep(std::ostream& out, std::string section);
void CreateLdScript(std::ostream& out, std::string entryPoint);
};
class SegmentMap
{
std::vector<SegmentInfo> segments;
std::vector<SegmentInfo> segments;
public:
SegmentMap();
SegmentMap(std::string filename);
SegmentMap();
SegmentMap(std::string filename);
void CreateLdScript(std::ostream& out, std::string entryPoint, bool stripMacsbug);
std::string GetSegmentName(int id);
void CreateLdScript(std::ostream& out, std::string entryPoint, bool stripMacsbug);
std::string GetSegmentName(int id);
};
#endif // SEGMENTMAP_H

View File

@@ -1,20 +1,20 @@
/*
Copyright 2017 Wolfgang Thaller.
Copyright 2017 Wolfgang Thaller.
This file is part of Retro68.
This file is part of Retro68.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Symbol.h"
@@ -33,13 +33,13 @@ Symbol::Symbol(Object& theObject, const GElf_Sym &sym)
sectionKind(SectionKind::undefined),
needsJT(false)
{
if(st_shndx != SHN_UNDEF && st_shndx < SHN_LORESERVE)
{
section = theObject.sectionsByElfIndex[st_shndx];
sectionKind = section->kind;
}
if(st_name)
{
name = elf_strptr(theObject.elf, theObject.mainStringTableIdx, st_name);
}
if(st_shndx != SHN_UNDEF && st_shndx < SHN_LORESERVE)
{
section = theObject.sectionsByElfIndex[st_shndx];
sectionKind = section->kind;
}
if(st_name)
{
name = elf_strptr(theObject.elf, theObject.mainStringTableIdx, st_name);
}
}

View File

@@ -1,20 +1,20 @@
/*
Copyright 2017 Wolfgang Thaller.
Copyright 2017 Wolfgang Thaller.
This file is part of Retro68.
This file is part of Retro68.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SYMBOL_H
@@ -32,16 +32,16 @@ class Object;
class Symbol : public GElf_Sym
{
public:
bool valid;
bool referencedExternally;
SectionKind sectionKind;
bool needsJT;
int jtIndex;
std::shared_ptr<Section> section;
std::string name;
bool valid;
bool referencedExternally;
SectionKind sectionKind;
bool needsJT;
int jtIndex;
std::shared_ptr<Section> section;
std::string name;
Symbol();
Symbol(Object &theObject, const GElf_Sym& sym);
Symbol();
Symbol(Object &theObject, const GElf_Sym& sym);
};

View File

@@ -1,20 +1,20 @@
/*
Copyright 2017 Wolfgang Thaller.
Copyright 2017 Wolfgang Thaller.
This file is part of Retro68.
This file is part of Retro68.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Symtab.h"
@@ -30,26 +30,26 @@ using std::string;
Symtab::Symtab(Object& theObject, Elf_Scn *elfsec)
: elfsec(elfsec)
{
data = elf_getdata(elfsec, NULL);
data = elf_getdata(elfsec, NULL);
GElf_Shdr shdr;
gelf_getshdr(elfsec, &shdr);
GElf_Shdr shdr;
gelf_getshdr(elfsec, &shdr);
int count = shdr.sh_size / shdr.sh_entsize;
symbols.reserve(count);
int count = shdr.sh_size / shdr.sh_entsize;
symbols.reserve(count);
for(int i = 0; i < count; i++)
{
GElf_Sym sym;
auto res = gelf_getsym(data, i, &sym);
assert(res != 0);
symbols.emplace_back(theObject, sym);
for(int i = 0; i < count; i++)
{
GElf_Sym sym;
auto res = gelf_getsym(data, i, &sym);
assert(res != 0);
symbols.emplace_back(theObject, sym);
if(sym.st_shndx != SHN_UNDEF && sym.st_shndx < SHN_LORESERVE)
symbolsByAddress[make_pair((int)sym.st_shndx,sym.st_value)] = i;
if(sym.st_name)
symbolsByName[symbols.back().name] = i;
}
if(sym.st_shndx != SHN_UNDEF && sym.st_shndx < SHN_LORESERVE)
symbolsByAddress[make_pair((int)sym.st_shndx,sym.st_value)] = i;
if(sym.st_name)
symbolsByName[symbols.back().name] = i;
}
}
Symtab::~Symtab()
@@ -59,23 +59,23 @@ Symtab::~Symtab()
Symbol &Symtab::GetSym(int idx)
{
return symbols[idx];
return symbols[idx];
}
int Symtab::FindSym(int secidx, uint32_t addr)
{
auto p = symbolsByAddress.find(make_pair(secidx, addr));
if(p != symbolsByAddress.end())
return p->second;
else
return -1;
auto p = symbolsByAddress.find(make_pair(secidx, addr));
if(p != symbolsByAddress.end())
return p->second;
else
return -1;
}
int Symtab::FindSym(string name)
{
auto p = symbolsByName.find(name);
if(p != symbolsByName.end())
return p->second;
else
return -1;
auto p = symbolsByName.find(name);
if(p != symbolsByName.end())
return p->second;
else
return -1;
}

View File

@@ -1,20 +1,20 @@
/*
Copyright 2017 Wolfgang Thaller.
Copyright 2017 Wolfgang Thaller.
This file is part of Retro68.
This file is part of Retro68.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Retro68 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with Retro68. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SYMTAB_H
@@ -33,18 +33,18 @@ class Symbol;
class Symtab
{
public:
Elf_Scn *elfsec;
Elf_Data *data;
std::vector<Symbol> symbols;
std::map<std::pair<int,uint32_t>, int> symbolsByAddress;
std::unordered_map<std::string, int> symbolsByName;
Elf_Scn *elfsec;
Elf_Data *data;
std::vector<Symbol> symbols;
std::map<std::pair<int,uint32_t>, int> symbolsByAddress;
std::unordered_map<std::string, int> symbolsByName;
Symtab(Object &theObject, Elf_Scn *elfsec);
~Symtab();
Symtab(Object &theObject, Elf_Scn *elfsec);
~Symtab();
Symbol& GetSym(int idx);
int FindSym(int secidx, uint32_t addr);
int FindSym(std::string name);
Symbol& GetSym(int idx);
int FindSym(int secidx, uint32_t addr);
int FindSym(std::string name);
};

View File

@@ -1,8 +1,8 @@
find_package(Boost COMPONENTS filesystem program_options)
set(LAUNCHMETHODS
Executor.h Executor.cc
MiniVMac.h MiniVMac.cc
Executor.h Executor.cc
MiniVMac.h MiniVMac.cc
SSH.h SSH.cc
StreamBasedLauncher.h StreamBasedLauncher.cc
Serial.h Serial.cc
@@ -11,32 +11,32 @@ set(LAUNCHMETHODS
)
if(APPLE)
LIST(APPEND LAUNCHMETHODS
Classic.h Classic.cc
)
LIST(APPEND LAUNCHMETHODS
Carbon.h Carbon.cc)
LIST(APPEND LAUNCHMETHODS
Classic.h Classic.cc
)
LIST(APPEND LAUNCHMETHODS
Carbon.h Carbon.cc)
endif()
add_definitions(-DRETRO68_PREFIX="${CMAKE_INSTALL_PREFIX}")
add_executable(LaunchAPPL
LaunchAPPL.cc
MakeExecutable.cc
LaunchAPPL.cc
MakeExecutable.cc
LaunchMethod.h LaunchMethod.cc
Launcher.h Launcher.cc
LaunchMethod.h LaunchMethod.cc
Launcher.h Launcher.cc
Utilities.h Utilities.cc
Utilities.h Utilities.cc
${LAUNCHMETHODS})
${LAUNCHMETHODS})
target_include_directories(LaunchAPPL PRIVATE ${CMAKE_INSTALL_PREFIX}/include ${Boost_INCLUDE_DIR})
target_link_libraries(LaunchAPPL ResourceFiles LaunchAPPLCommon ${Boost_LIBRARIES})
if(APPLE)
find_library(APPLICATIONSERVICES_FW ApplicationServices)
target_link_libraries(LaunchAPPL ${APPLICATIONSERVICES_FW})
find_library(APPLICATIONSERVICES_FW ApplicationServices)
target_link_libraries(LaunchAPPL ${APPLICATIONSERVICES_FW})
endif()
install(TARGETS LaunchAPPL RUNTIME DESTINATION bin)

View File

@@ -3,17 +3,17 @@
#include "Utilities.h"
const std::string launchCFM =
"/System/Library/Frameworks/Carbon.framework/Versions/A/Support/LaunchCFMApp";
"/System/Library/Frameworks/Carbon.framework/Versions/A/Support/LaunchCFMApp";
namespace po = boost::program_options;
class CarbonLauncher : public Launcher
{
public:
CarbonLauncher(po::variables_map& options);
virtual ~CarbonLauncher();
CarbonLauncher(po::variables_map& options);
virtual ~CarbonLauncher();
virtual bool Go(int timeout = 0);
virtual bool Go(int timeout = 0);
};
@@ -30,18 +30,18 @@ CarbonLauncher::~CarbonLauncher()
bool CarbonLauncher::Go(int timeout)
{
return ChildProcess(launchCFM, { appPath.string() }, timeout) == 0;
return ChildProcess(launchCFM, { appPath.string() }, timeout) == 0;
}
bool Carbon::CheckPlatform()
{
/* If LaunchCFMApp doesn't exist, we're likely on a Mac OS X version
where it doesn't exist anymore (10.7 Lion or later),
or on an entirely different platform. */
return CheckExecutable(launchCFM);
/* If LaunchCFMApp doesn't exist, we're likely on a Mac OS X version
where it doesn't exist anymore (10.7 Lion or later),
or on an entirely different platform. */
return CheckExecutable(launchCFM);
}
std::unique_ptr<Launcher> Carbon::MakeLauncher(variables_map &options)
{
return std::unique_ptr<Launcher>(new CarbonLauncher(options));
return std::unique_ptr<Launcher>(new CarbonLauncher(options));
}

View File

@@ -6,10 +6,10 @@
class Carbon : public LaunchMethod
{
public:
virtual std::string GetName() { return "carbon"; }
virtual std::string GetName() { return "carbon"; }
virtual bool CheckPlatform();
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
virtual bool CheckPlatform();
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
};
#endif // CARBON_METHOD_H

View File

@@ -12,10 +12,10 @@ namespace po = boost::program_options;
class ClassicLauncher : public Launcher
{
public:
ClassicLauncher(po::variables_map& options);
virtual ~ClassicLauncher();
ClassicLauncher(po::variables_map& options);
virtual ~ClassicLauncher();
virtual bool Go(int timeout = 0);
virtual bool Go(int timeout = 0);
};
@@ -31,52 +31,52 @@ ClassicLauncher::~ClassicLauncher()
}
bool ClassicLauncher::Go(int timeout)
{
FSRef ref;
FSPathMakeRef((const UInt8*) appPath.string().c_str(), &ref, NULL);
LSApplicationParameters params;
memset(&params, 0, sizeof(params));
params.flags = kLSLaunchStartClassic
| kLSLaunchInClassic
| kLSLaunchDontAddToRecents
| kLSLaunchNewInstance;
params.application = &ref;
ProcessSerialNumber psn;
LSOpenApplication(&params, &psn);
// Classic startup takes place before LSOpenApplication returns,
// so no extra timeout is needed
for(int i = 0; i < timeout || timeout == 0; i++)
{
sleep(1);
ProcessInfoRec pi;
pi.processInfoLength = sizeof(pi);
pi.processName = NULL;
pi.processAppSpec = 0;
if(GetProcessInformation(&psn, &pi) == procNotFound)
return true;
}
{
FSRef ref;
FSPathMakeRef((const UInt8*) appPath.string().c_str(), &ref, NULL);
LSApplicationParameters params;
memset(&params, 0, sizeof(params));
params.flags = kLSLaunchStartClassic
| kLSLaunchInClassic
| kLSLaunchDontAddToRecents
| kLSLaunchNewInstance;
params.application = &ref;
ProcessSerialNumber psn;
LSOpenApplication(&params, &psn);
// Classic startup takes place before LSOpenApplication returns,
// so no extra timeout is needed
for(int i = 0; i < timeout || timeout == 0; i++)
{
sleep(1);
ProcessInfoRec pi;
pi.processInfoLength = sizeof(pi);
pi.processName = NULL;
pi.processAppSpec = 0;
if(GetProcessInformation(&psn, &pi) == procNotFound)
return true;
}
KillProcess(&psn);
KillProcess(&psn);
return false;
return false;
}
bool Classic::CheckPlatform()
{
long sysver = 0;
Gestalt(gestaltSystemVersion, &sysver);
if(sysver >= 0x1050)
return false;
else
return true;
long sysver = 0;
Gestalt(gestaltSystemVersion, &sysver);
if(sysver >= 0x1050)
return false;
else
return true;
}
std::unique_ptr<Launcher> Classic::MakeLauncher(variables_map &options)
{
return std::unique_ptr<Launcher>(new ClassicLauncher(options));
return std::unique_ptr<Launcher>(new ClassicLauncher(options));
}
#endif

View File

@@ -6,10 +6,10 @@
class Classic : public LaunchMethod
{
public:
virtual std::string GetName() { return "classic"; }
virtual std::string GetName() { return "classic"; }
virtual bool CheckPlatform();
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
virtual bool CheckPlatform();
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
};
#endif // CLASSIC_H

View File

@@ -7,10 +7,10 @@ namespace po = boost::program_options;
class ExecutorLauncher : public Launcher
{
public:
ExecutorLauncher(po::variables_map& options);
virtual ~ExecutorLauncher();
ExecutorLauncher(po::variables_map& options);
virtual ~ExecutorLauncher();
virtual bool Go(int timeout = 0);
virtual bool Go(int timeout = 0);
};
@@ -27,37 +27,37 @@ ExecutorLauncher::~ExecutorLauncher()
bool ExecutorLauncher::Go(int timeout)
{
std::vector<std::string> args;
if(options.count("executor-option"))
args = options["executor-option"].as<std::vector<std::string>>();
args.push_back(appPath.string());
std::vector<std::string> args;
if(options.count("executor-option"))
args = options["executor-option"].as<std::vector<std::string>>();
args.push_back(appPath.string());
if(options.count("executor-system-folder"))
setenv("SystemFolder", options["executor-system-folder"].as<std::string>().c_str(), true);
if(options.count("executor-system-folder"))
setenv("SystemFolder", options["executor-system-folder"].as<std::string>().c_str(), true);
return ChildProcess(options["executor-path"].as<std::string>(), args, timeout) == 0;
return ChildProcess(options["executor-path"].as<std::string>(), args, timeout) == 0;
}
void Executor::GetOptions(options_description &desc)
{
desc.add_options()
("executor-path", po::value<std::string>()->default_value("executor"),"path to executor")
("executor-system-folder", po::value<std::string>(),
"system folder for executor (overrides SystemFolder environment variable)")
("executor-option", po::value<std::vector<std::string>>(),
"pass an option to executor")
;
desc.add_options()
("executor-path", po::value<std::string>()->default_value("executor"),"path to executor")
("executor-system-folder", po::value<std::string>(),
"system folder for executor (overrides SystemFolder environment variable)")
("executor-option", po::value<std::vector<std::string>>(),
"pass an option to executor")
;
}
bool Executor::CheckOptions(variables_map &options)
{
if(options.count("executor-path") == 0)
return false;
return CheckExecutable(options["executor-path"].as<std::string>());
if(options.count("executor-path") == 0)
return false;
return CheckExecutable(options["executor-path"].as<std::string>());
}
std::unique_ptr<Launcher> Executor::MakeLauncher(variables_map &options)
{
return std::unique_ptr<Launcher>(new ExecutorLauncher(options));
return std::unique_ptr<Launcher>(new ExecutorLauncher(options));
}

View File

@@ -6,11 +6,11 @@
class Executor : public LaunchMethod
{
public:
virtual std::string GetName() { return "executor"; }
virtual void GetOptions(options_description& desc);
virtual bool CheckOptions(variables_map& options);
virtual std::string GetName() { return "executor"; }
virtual void GetOptions(options_description& desc);
virtual bool CheckOptions(variables_map& options);
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
};
#endif // EXECUTOR_H

View File

@@ -9,13 +9,13 @@
#include "Launcher.h"
#if defined(__APPLE__)
# define ResType MacResType
# include <ApplicationServices/ApplicationServices.h>
# undef ResType
# if TARGET_CPU_PPC
# include "Classic.h"
# endif
# include "Carbon.h"
# define ResType MacResType
# include <ApplicationServices/ApplicationServices.h>
# undef ResType
# if TARGET_CPU_PPC
# include "Classic.h"
# endif
# include "Carbon.h"
#endif
#include "Executor.h"
#include "MiniVMac.h"
@@ -37,224 +37,224 @@ static vector<LaunchMethod*> launchMethods;
static void RegisterLaunchMethods()
{
vector<LaunchMethod*> methods = {
vector<LaunchMethod*> methods = {
#if defined(__APPLE__)
# if TARGET_CPU_PPC
new Classic(),
# endif
new Carbon(),
# if TARGET_CPU_PPC
new Classic(),
# endif
new Carbon(),
#endif
new Executor(), new MiniVMac(),
new SSH(),
new Executor(), new MiniVMac(),
new SSH(),
new Serial(),
new TCP(),
new SharedFile()
// #### Add new `LaunchMethod`s here.
};
for(LaunchMethod *m : methods)
{
if(m->CheckPlatform())
launchMethods.push_back(m);
}
// #### Add new `LaunchMethod`s here.
};
for(LaunchMethod *m : methods)
{
if(m->CheckPlatform())
launchMethods.push_back(m);
}
}
static void usage()
{
std::cerr << "Usage: " << "LaunchAPPL [options] appl-file\n";
std::cerr << desc << std::endl;
std::cerr << "Defaults are read from:\n";
for(string str : configFiles)
{
std::cerr << "\t" << str;
if(!std::ifstream(str))
std::cerr << " (not found)";
std::cerr << std::endl;
}
std::cerr << std::endl;
std::cerr << "Usage: " << "LaunchAPPL [options] appl-file\n";
std::cerr << desc << std::endl;
std::cerr << "Defaults are read from:\n";
for(string str : configFiles)
{
std::cerr << "\t" << str;
if(!std::ifstream(str))
std::cerr << " (not found)";
std::cerr << std::endl;
}
std::cerr << std::endl;
vector<string> configuredMethods, unconfiguredMethods;
for(LaunchMethod *method : launchMethods)
(method->CheckOptions(options) ? configuredMethods : unconfiguredMethods)
.push_back(method->GetName());
vector<string> configuredMethods, unconfiguredMethods;
for(LaunchMethod *method : launchMethods)
(method->CheckOptions(options) ? configuredMethods : unconfiguredMethods)
.push_back(method->GetName());
if(!configuredMethods.empty())
{
std::cerr << "Available emulators/environments:\n";
for(string m : configuredMethods)
std::cerr << "\t" << m << std::endl;
}
if(!unconfiguredMethods.empty())
{
std::cerr << "Emulators/environments needing more configuration:\n";
for(string m : unconfiguredMethods)
std::cerr << "\t" << m << std::endl;
}
if(!configuredMethods.empty())
{
std::cerr << "Available emulators/environments:\n";
for(string m : configuredMethods)
std::cerr << "\t" << m << std::endl;
}
if(!unconfiguredMethods.empty())
{
std::cerr << "Emulators/environments needing more configuration:\n";
for(string m : unconfiguredMethods)
std::cerr << "\t" << m << std::endl;
}
if(options.count("emulator"))
{
string e = options["emulator"].as<string>();
std::cerr << "\nChosen emulator/environment: " << e;
if(std::find(configuredMethods.begin(), configuredMethods.end(), e)
!= configuredMethods.end())
std::cerr << "\n";
else if(std::find(unconfiguredMethods.begin(), unconfiguredMethods.end(), e)
!= unconfiguredMethods.end())
std::cerr << " (needs more configuration)\n";
else
std::cerr << " (UNKNOWN)\n";
}
else
{
std::cerr << "\nNo emulator/environment chosen (-e)\n";
}
if(options.count("emulator"))
{
string e = options["emulator"].as<string>();
std::cerr << "\nChosen emulator/environment: " << e;
if(std::find(configuredMethods.begin(), configuredMethods.end(), e)
!= configuredMethods.end())
std::cerr << "\n";
else if(std::find(unconfiguredMethods.begin(), unconfiguredMethods.end(), e)
!= unconfiguredMethods.end())
std::cerr << " (needs more configuration)\n";
else
std::cerr << " (UNKNOWN)\n";
}
else
{
std::cerr << "\nNo emulator/environment chosen (-e)\n";
}
}
void MakeExecutable(string filepath);
int main(int argc, char *argv[])
{
RegisterLaunchMethods();
configFiles = { string(getenv("HOME")) + "/.LaunchAPPL.cfg", RETRO68_PREFIX "/LaunchAPPL.cfg"};
RegisterLaunchMethods();
configFiles = { string(getenv("HOME")) + "/.LaunchAPPL.cfg", RETRO68_PREFIX "/LaunchAPPL.cfg"};
desc.add_options()
("help,h", "show this help message")
("list-emulators,l", "get the list of available, fully configured emulators/environments")
("make-executable,x", po::value<std::string>(), "make a MacBinary file executable")
;
po::options_description configdesc;
configdesc.add_options()
("emulator,e", po::value<std::string>(), "what emulator/environment to use")
;
for(LaunchMethod *lm : launchMethods)
lm->GetOptions(configdesc);
desc.add(configdesc);
desc.add_options()
("help,h", "show this help message")
("list-emulators,l", "get the list of available, fully configured emulators/environments")
("make-executable,x", po::value<std::string>(), "make a MacBinary file executable")
;
po::options_description configdesc;
configdesc.add_options()
("emulator,e", po::value<std::string>(), "what emulator/environment to use")
;
for(LaunchMethod *lm : launchMethods)
lm->GetOptions(configdesc);
desc.add(configdesc);
desc.add_options()
("timeout,t", po::value<int>(),"abort after timeout")
desc.add_options()
("timeout,t", po::value<int>(),"abort after timeout")
("upgrade-server", "upgrade the server application")
;
po::options_description hidden, alldesc;
hidden.add_options()
("application,a", po::value<std::string>(), "application" )
;
alldesc.add(desc).add(hidden);
try
{
auto parsed = po::command_line_parser(argc, argv)
.options(alldesc)
.positional(po::positional_options_description().add("application", -1))
.style(po::command_line_style::default_style)
.run();
;
po::options_description hidden, alldesc;
hidden.add_options()
("application,a", po::value<std::string>(), "application" )
;
alldesc.add(desc).add(hidden);
try
{
auto parsed = po::command_line_parser(argc, argv)
.options(alldesc)
.positional(po::positional_options_description().add("application", -1))
.style(po::command_line_style::default_style)
.run();
po::store(parsed, options);
}
catch(po::error& e)
{
std::cerr << "ERROR: " << e.what() << std::endl << std::endl;
usage();
return 1;
}
po::store(parsed, options);
}
catch(po::error& e)
{
std::cerr << "ERROR: " << e.what() << std::endl << std::endl;
usage();
return 1;
}
for(string configFileName : configFiles)
{
try
{
std::ifstream cfg(configFileName);
if(cfg)
{
auto parsed = po::parse_config_file<char>(cfg,configdesc,false);
for(string configFileName : configFiles)
{
try
{
std::ifstream cfg(configFileName);
if(cfg)
{
auto parsed = po::parse_config_file<char>(cfg,configdesc,false);
po::store(parsed, options);
}
}
catch(po::error& e)
{
std::cerr << "CONFIG FILE ERROR: " << e.what() << std::endl << std::endl;
usage();
return 1;
}
}
po::store(parsed, options);
}
}
catch(po::error& e)
{
std::cerr << "CONFIG FILE ERROR: " << e.what() << std::endl << std::endl;
usage();
return 1;
}
}
po::notify(options);
po::notify(options);
vector<string> commandModes = {"application", "help", "make-executable", "list-emulators"};
int nModes = 0;
string mode;
vector<string> commandModes = {"application", "help", "make-executable", "list-emulators"};
int nModes = 0;
string mode;
for(string aMode : commandModes)
{
if(options.count(aMode))
{
nModes++;
mode = aMode;
}
}
if(nModes > 1)
{
std::cerr << "Need to specify either an application file or exactly one of ";
for(int i = 1, n = commandModes.size(); i < n-1; i++)
std::cerr << "--" << commandModes[i] << ", ";
std::cerr << "or " << commandModes.back() << "." << std::endl << std::endl;
usage();
return 1;
}
if(mode == "" || mode == "help")
{
usage();
return 0;
}
else if(mode == "make-executable")
{
string fn = options["make-executable"].as<std::string>();
MakeExecutable(fn);
return 0;
}
else if(mode == "list-emulators")
{
for(LaunchMethod *method : launchMethods)
if(method->CheckOptions(options))
std::cout << method->GetName() << std::endl;
return 0;
}
for(string aMode : commandModes)
{
if(options.count(aMode))
{
nModes++;
mode = aMode;
}
}
if(nModes > 1)
{
std::cerr << "Need to specify either an application file or exactly one of ";
for(int i = 1, n = commandModes.size(); i < n-1; i++)
std::cerr << "--" << commandModes[i] << ", ";
std::cerr << "or " << commandModes.back() << "." << std::endl << std::endl;
usage();
return 1;
}
if(mode == "" || mode == "help")
{
usage();
return 0;
}
else if(mode == "make-executable")
{
string fn = options["make-executable"].as<std::string>();
MakeExecutable(fn);
return 0;
}
else if(mode == "list-emulators")
{
for(LaunchMethod *method : launchMethods)
if(method->CheckOptions(options))
std::cout << method->GetName() << std::endl;
return 0;
}
if(!options.count("emulator"))
{
std::cerr << "ERROR: emulator/environment not specified.\n";
usage();
return 1;
}
if(!options.count("emulator"))
{
std::cerr << "ERROR: emulator/environment not specified.\n";
usage();
return 1;
}
LaunchMethod *method = NULL;
for(LaunchMethod *lm : launchMethods)
{
if(lm->GetName() == options["emulator"].as<string>())
{
method = lm;
break;
}
}
if(!method)
{
std::cerr << "ERROR: unknown emulator/environment: " << options["emulator"].as<string>() << "\n";
return 1;
}
LaunchMethod *method = NULL;
for(LaunchMethod *lm : launchMethods)
{
if(lm->GetName() == options["emulator"].as<string>())
{
method = lm;
break;
}
}
if(!method)
{
std::cerr << "ERROR: unknown emulator/environment: " << options["emulator"].as<string>() << "\n";
return 1;
}
if(!method->CheckOptions(options))
{
std::cerr << "Need more configuration.\n";
usage();
return 1;
}
if(!method->CheckOptions(options))
{
std::cerr << "Need more configuration.\n";
usage();
return 1;
}
std::unique_ptr<Launcher> launcher = method->MakeLauncher(options);
std::unique_ptr<Launcher> launcher = method->MakeLauncher(options);
int timeout = options.count("timeout") ? options["timeout"].as<int>() : 0;
int timeout = options.count("timeout") ? options["timeout"].as<int>() : 0;
bool result = launcher->Go(timeout);
bool result = launcher->Go(timeout);
launcher->DumpOutput();
launcher->DumpOutput();
return result ? 0 : 1;
return result ? 0 : 1;
}

View File

@@ -16,10 +16,10 @@ void LaunchMethod::GetOptions(boost::program_options::options_description &desc)
bool LaunchMethod::CheckPlatform()
{
return true;
return true;
}
bool LaunchMethod::CheckOptions(boost::program_options::variables_map &options)
{
return true;
return true;
}

View File

@@ -18,52 +18,52 @@ class Launcher;
class LaunchMethod
{
public:
typedef boost::program_options::options_description options_description;
typedef boost::program_options::variables_map variables_map;
typedef boost::program_options::options_description options_description;
typedef boost::program_options::variables_map variables_map;
LaunchMethod();
virtual ~LaunchMethod();
LaunchMethod();
virtual ~LaunchMethod();
/**
* @brief GetName
* @return the name of the launch method, as it will be specified on the command line
*/
virtual std::string GetName() = 0;
/**
* @brief GetName
* @return the name of the launch method, as it will be specified on the command line
*/
virtual std::string GetName() = 0;
/**
* @brief GetOptions
* @param desc
*
* Add any command line options for this LaunchMethod
* to the options_description structure.
*/
virtual void GetOptions(options_description& desc);
/**
* @brief GetOptions
* @param desc
*
* Add any command line options for this LaunchMethod
* to the options_description structure.
*/
virtual void GetOptions(options_description& desc);
/**
* @brief CheckPlatform
*
* Check whether this is the right kind of machine to use this method.
* For things like Apple's Classic Environment, which is only available on some system versions.
* The default implementation returns true.
*/
virtual bool CheckPlatform();
/**
* @brief CheckPlatform
*
* Check whether this is the right kind of machine to use this method.
* For things like Apple's Classic Environment, which is only available on some system versions.
* The default implementation returns true.
*/
virtual bool CheckPlatform();
/**
* @brief CheckOptions
* @param options
* @return are we ready to run?
*
* Check whether all necessary options have been specified.
* Don't output error messages here, this is also called when outputting usage information
*/
virtual bool CheckOptions(variables_map& options);
/**
* @brief CheckOptions
* @param options
* @return are we ready to run?
*
* Check whether all necessary options have been specified.
* Don't output error messages here, this is also called when outputting usage information
*/
virtual bool CheckOptions(variables_map& options);
/**
* @brief MakeLauncher
* @param options
* @return a new instance of a subclass of Launcher which will do the actual work
*/
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options) = 0;
/**
* @brief MakeLauncher
* @param options
* @return a new instance of a subclass of Launcher which will do the actual work
*/
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options) = 0;
protected:
};

View File

@@ -11,47 +11,47 @@ using std::vector;
Launcher::Launcher(boost::program_options::variables_map &options)
: options(options)
{
string fn = options["application"].as<std::string>();
if(fn == "-")
{
std::stringstream tmp;
tmp << std::cin.rdbuf();
if(!app.read(tmp, ResourceFile::Format::macbin))
throw std::runtime_error("Could not load application from stdin.");
}
else
{
app.assign(fn);
if(!app.read())
throw std::runtime_error("Could not load application file.");
}
tempDir = fs::absolute(fs::unique_path());
fs::create_directories(tempDir);
string fn = options["application"].as<std::string>();
if(fn == "-")
{
std::stringstream tmp;
tmp << std::cin.rdbuf();
if(!app.read(tmp, ResourceFile::Format::macbin))
throw std::runtime_error("Could not load application from stdin.");
}
else
{
app.assign(fn);
if(!app.read())
throw std::runtime_error("Could not load application file.");
}
tempDir = fs::absolute(fs::unique_path());
fs::create_directories(tempDir);
appPath = tempDir / "Application";
outPath = tempDir / "out";
appPath = tempDir / "Application";
outPath = tempDir / "out";
fs::ofstream out(outPath);
fs::ofstream out(outPath);
}
Launcher::Launcher(boost::program_options::variables_map &options, ResourceFile::Format f)
: Launcher(options)
{
app.assign(appPath.string(), f);
app.write();
app.assign(appPath.string(), f);
app.write();
}
void Launcher::DumpOutput()
{
fs::ifstream in(outPath);
std::cout << in.rdbuf();
fs::ifstream in(outPath);
std::cout << in.rdbuf();
}
Launcher::~Launcher()
{
fs::remove_all(tempDir);
fs::remove_all(tempDir);
}

View File

@@ -14,61 +14,61 @@
class Launcher
{
protected:
boost::program_options::variables_map& options;
boost::program_options::variables_map& options;
ResourceFile app;
boost::filesystem::path tempDir, appPath, outPath;
bool keepTempFiles;
ResourceFile app;
boost::filesystem::path tempDir, appPath, outPath;
bool keepTempFiles;
public:
/**
* @brief Launcher
* @param options
*
* Create a Launcher object and set up a temporary directory to play in.
* Reads the Applicatio specified on the command line into the `app` member variable.
* Also create an empty file named 'out' in the temporary directory, for test suite programs.
*/
Launcher(boost::program_options::variables_map& options);
/**
* @brief Launcher
* @param options
*
* Create a Launcher object and set up a temporary directory to play in.
* Reads the Applicatio specified on the command line into the `app` member variable.
* Also create an empty file named 'out' in the temporary directory, for test suite programs.
*/
Launcher(boost::program_options::variables_map& options);
/**
* @brief Launcher
* @param options
* @param f
*
* Create a Launcher object, set up a temporary directory
* and store the application to be executed at `appPath` in the temporary directory,
* using format `f`.
*/
Launcher(boost::program_options::variables_map& options, ResourceFile::Format f);
/**
* @brief Launcher
* @param options
* @param f
*
* Create a Launcher object, set up a temporary directory
* and store the application to be executed at `appPath` in the temporary directory,
* using format `f`.
*/
Launcher(boost::program_options::variables_map& options, ResourceFile::Format f);
/**
* @brief ~Launcher
* Delete our temporary directory.
*/
virtual ~Launcher();
/**
* @brief ~Launcher
* Delete our temporary directory.
*/
virtual ~Launcher();
/**
* @brief Go
* @param timeout
* @return true for success
*
* Launch the application, return true on success and false on error or timeout.
*/
virtual bool Go(int timeout = 0) = 0;
/**
* @brief Go
* @param timeout
* @return true for success
*
* Launch the application, return true on success and false on error or timeout.
*/
virtual bool Go(int timeout = 0) = 0;
/**
* @brief DumpOutput
*
* After the application has been run, copy the contents of the 'out' file to stdout.
*/
virtual void DumpOutput();
/**
* @brief DumpOutput
*
* After the application has been run, copy the contents of the 'out' file to stdout.
*/
virtual void DumpOutput();
/**
* @brief KeepTempFiles
* Inhibit deletion of the temporary directory.
*/
void KeepTempFiles() { keepTempFiles = true; }
/**
* @brief KeepTempFiles
* Inhibit deletion of the temporary directory.
*/
void KeepTempFiles() { keepTempFiles = true; }
};
#endif // LAUNCHER_H

View File

@@ -11,43 +11,43 @@ namespace fs = boost::filesystem;
void MakeExecutable(string fn)
{
ResourceFile rsrcFile(fn);
if(!rsrcFile.read())
{
std::cerr << "Cannot read application file: " << fn << std::endl;
exit(1);
}
if(!rsrcFile.hasPlainDataFork())
{
std::cerr << "--make-executable can not be used with this data format.\n";
exit(1);
}
ResourceFile rsrcFile(fn);
if(!rsrcFile.read())
{
std::cerr << "Cannot read application file: " << fn << std::endl;
exit(1);
}
if(!rsrcFile.hasPlainDataFork())
{
std::cerr << "--make-executable can not be used with this data format.\n";
exit(1);
}
string headerString = "#!" RETRO68_PREFIX "/bin/LaunchAPPL\n";
string headerString = "#!" RETRO68_PREFIX "/bin/LaunchAPPL\n";
bool hadShebang = false;
if(rsrcFile.data.size())
{
if(headerString.substr(2) == "#!")
{
string::size_type eol = headerString.find('\n');
if(eol != string::npos && eol >= 13 && eol < 4096)
{
if(headerString.substr(eol-11,11) == "/LaunchAPPL")
hadShebang = true;
}
}
bool hadShebang = false;
if(rsrcFile.data.size())
{
if(headerString.substr(2) == "#!")
{
string::size_type eol = headerString.find('\n');
if(eol != string::npos && eol >= 13 && eol < 4096)
{
if(headerString.substr(eol-11,11) == "/LaunchAPPL")
hadShebang = true;
}
}
if(!hadShebang)
{
std::cerr << "Unfortunately, the application already has a data fork.\n";
std::cerr << "LaunchAPPL --make-executable does not currently work for PowerPC apps.\n";
// TODO: if it's a PEF container, move it back a little and update cfrg
exit(1);
}
}
if(!hadShebang)
{
std::cerr << "Unfortunately, the application already has a data fork.\n";
std::cerr << "LaunchAPPL --make-executable does not currently work for PowerPC apps.\n";
// TODO: if it's a PEF container, move it back a little and update cfrg
exit(1);
}
}
std::fstream(fn, std::ios::in | std::ios::out | std::ios::binary) << headerString;
std::fstream(fn, std::ios::in | std::ios::out | std::ios::binary) << headerString;
fs::permissions(fs::path(fn), fs::owner_exe | fs::group_exe | fs::others_exe | fs::add_perms);
fs::permissions(fs::path(fn), fs::owner_exe | fs::group_exe | fs::others_exe | fs::add_perms);
}

View File

@@ -6,11 +6,11 @@
class MiniVMac : public LaunchMethod
{
public:
virtual std::string GetName() { return "minivmac"; }
virtual void GetOptions(options_description& desc);
virtual bool CheckOptions(variables_map& options);
virtual std::string GetName() { return "minivmac"; }
virtual void GetOptions(options_description& desc);
virtual bool CheckOptions(variables_map& options);
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
};
#endif // MINIVMAC_H

View File

@@ -16,10 +16,10 @@ using std::vector;
class SSHLauncher : public Launcher
{
public:
SSHLauncher(po::variables_map& options);
virtual ~SSHLauncher();
SSHLauncher(po::variables_map& options);
virtual ~SSHLauncher();
virtual bool Go(int timeout = 0);
virtual bool Go(int timeout = 0);
};
@@ -36,115 +36,115 @@ SSHLauncher::~SSHLauncher()
static void insertArgs(vector<string>& args, po::variables_map& options, string name)
{
if(options.count(name))
{
auto extraArgs = SplitArguments(options[name].as<vector<string>>());
args.insert(args.end(), extraArgs.begin(), extraArgs.end());
}
if(options.count(name))
{
auto extraArgs = SplitArguments(options[name].as<vector<string>>());
args.insert(args.end(), extraArgs.begin(), extraArgs.end());
}
}
bool SSHLauncher::Go(int timeout)
{
std::vector<std::string> args;
args.push_back(options["ssh-host"].as<string>());
insertArgs(args, options, "ssh-args");
args.push_back("--");
args.push_back(options["ssh-remote-path"].as<string>());
insertArgs(args, options, "ssh-remote-args");
if(timeout)
{
args.push_back("--timeout");
args.push_back(boost::lexical_cast<std::string>(timeout));
}
args.push_back("-");
std::vector<std::string> args;
args.push_back(options["ssh-host"].as<string>());
insertArgs(args, options, "ssh-args");
args.push_back("--");
args.push_back(options["ssh-remote-path"].as<string>());
insertArgs(args, options, "ssh-remote-args");
if(timeout)
{
args.push_back("--timeout");
args.push_back(boost::lexical_cast<std::string>(timeout));
}
args.push_back("-");
std::string program = options["ssh-path"].as<std::string>();
std::string program = options["ssh-path"].as<std::string>();
std::vector<const char*> argv;
argv.push_back(program.c_str());
for(std::string& s : args)
argv.push_back(s.c_str());
argv.push_back(NULL);
std::vector<const char*> argv;
argv.push_back(program.c_str());
for(std::string& s : args)
argv.push_back(s.c_str());
argv.push_back(NULL);
int fd[2];
pipe(fd);
const int READ_END = 0;
const int WRITE_END = 1;
int fd[2];
pipe(fd);
const int READ_END = 0;
const int WRITE_END = 1;
pid_t pid = fork();
if(pid < 0)
{
perror("unable to fork");
return 1;
}
else if(pid == 0)
{
dup2(fd[READ_END], STDIN_FILENO);
close(fd[WRITE_END]);
close(fd[READ_END]);
pid_t pid = fork();
if(pid < 0)
{
perror("unable to fork");
return 1;
}
else if(pid == 0)
{
dup2(fd[READ_END], STDIN_FILENO);
close(fd[WRITE_END]);
close(fd[READ_END]);
execvp(argv[0], const_cast<char* const *> (argv.data()));
perror("exec failed");
std::cerr << "Tried to execute: " << program;
for(auto a : args)
std::cerr << " " << a;
std::cerr << std::endl;
_exit(1);
}
else
{
close(fd[READ_END]);
execvp(argv[0], const_cast<char* const *> (argv.data()));
perror("exec failed");
std::cerr << "Tried to execute: " << program;
for(auto a : args)
std::cerr << " " << a;
std::cerr << std::endl;
_exit(1);
}
else
{
close(fd[READ_END]);
std::ostringstream tmp;
app.write(tmp, ResourceFile::Format::macbin);
const std::string data = tmp.str();
std::ostringstream tmp;
app.write(tmp, ResourceFile::Format::macbin);
const std::string data = tmp.str();
write(fd[WRITE_END], data.data(), data.size());
close(fd[WRITE_END]);
write(fd[WRITE_END], data.data(), data.size());
close(fd[WRITE_END]);
int wstatus;
int result = 0;
do
{
result = waitpid(pid, &wstatus, 0);
} while(result == -1 && errno == EINTR);
int wstatus;
int result = 0;
do
{
result = waitpid(pid, &wstatus, 0);
} while(result == -1 && errno == EINTR);
if(!WIFEXITED(wstatus))
{
return false;
}
else
{
//int exitcode = WEXITSTATUS(wstatus);
return true;
}
}
if(!WIFEXITED(wstatus))
{
return false;
}
else
{
//int exitcode = WEXITSTATUS(wstatus);
return true;
}
}
}
void SSH::GetOptions(options_description &desc)
{
desc.add_options()
("ssh-path", po::value<string>()->default_value("ssh"),"ssh command to use")
("ssh-host", po::value<string>(),
"[username@]address of remote host")
("ssh-args", po::value<vector<string>>(),
"additional arguments for ssh")
("ssh-remote-path", po::value<string>()->default_value("LaunchAPPL"),
"path to LaunchAPPL on remote host")
("ssh-remote-args", po::value<vector<string>>(),
"additional arguments for LaunchAPPL on remote host")
;
desc.add_options()
("ssh-path", po::value<string>()->default_value("ssh"),"ssh command to use")
("ssh-host", po::value<string>(),
"[username@]address of remote host")
("ssh-args", po::value<vector<string>>(),
"additional arguments for ssh")
("ssh-remote-path", po::value<string>()->default_value("LaunchAPPL"),
"path to LaunchAPPL on remote host")
("ssh-remote-args", po::value<vector<string>>(),
"additional arguments for LaunchAPPL on remote host")
;
}
bool SSH::CheckOptions(variables_map &options)
{
return options.count("ssh-host") != 0;
return options.count("ssh-host") != 0;
}
std::unique_ptr<Launcher> SSH::MakeLauncher(variables_map &options)
{
return std::unique_ptr<Launcher>(new SSHLauncher(options));
return std::unique_ptr<Launcher>(new SSHLauncher(options));
}

View File

@@ -6,11 +6,11 @@
class SSH : public LaunchMethod
{
public:
virtual std::string GetName() { return "ssh"; }
virtual void GetOptions(options_description& desc);
virtual bool CheckOptions(variables_map& options);
virtual std::string GetName() { return "ssh"; }
virtual void GetOptions(options_description& desc);
virtual bool CheckOptions(variables_map& options);
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
};
#endif // SSH_H

View File

@@ -36,7 +36,7 @@ class SerialLauncher : public StreamBasedLauncher
SerialStream stream;
ReliableStream rStream;
public:
SerialLauncher(po::variables_map& options);
SerialLauncher(po::variables_map& options);
};
@@ -146,10 +146,10 @@ void Serial::GetOptions(options_description &desc)
bool Serial::CheckOptions(variables_map &options)
{
return true;
return true;
}
std::unique_ptr<Launcher> Serial::MakeLauncher(variables_map &options)
{
return std::unique_ptr<Launcher>(new SerialLauncher(options));
return std::unique_ptr<Launcher>(new SerialLauncher(options));
}

View File

@@ -6,11 +6,11 @@
class Serial : public LaunchMethod
{
public:
virtual std::string GetName() { return "serial"; }
virtual void GetOptions(options_description& desc);
virtual bool CheckOptions(variables_map& options);
virtual std::string GetName() { return "serial"; }
virtual void GetOptions(options_description& desc);
virtual bool CheckOptions(variables_map& options);
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
};
#endif // EXECUTOR_H

View File

@@ -30,7 +30,7 @@ class SharedFileLauncher : public StreamBasedLauncher
{
SharedFileStream stream;
public:
SharedFileLauncher(po::variables_map& options);
SharedFileLauncher(po::variables_map& options);
};
SharedFileStream::SharedFileStream(po::variables_map &options)
@@ -90,10 +90,10 @@ void SharedFile::GetOptions(options_description &desc)
bool SharedFile::CheckOptions(variables_map &options)
{
return options.count("shared-directory") != 0;
return options.count("shared-directory") != 0;
}
std::unique_ptr<Launcher> SharedFile::MakeLauncher(variables_map &options)
{
return std::unique_ptr<Launcher>(new SharedFileLauncher(options));
return std::unique_ptr<Launcher>(new SharedFileLauncher(options));
}

View File

@@ -5,9 +5,9 @@
class SharedFile : public LaunchMethod
{
public:
virtual std::string GetName() { return "shared"; }
virtual void GetOptions(options_description& desc);
virtual bool CheckOptions(variables_map& options);
virtual std::string GetName() { return "shared"; }
virtual void GetOptions(options_description& desc);
virtual bool CheckOptions(variables_map& options);
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
};

View File

@@ -12,11 +12,11 @@ class StreamBasedLauncher : public Launcher
std::vector<char> outputBytes;
bool upgradeMode = false;
public:
StreamBasedLauncher(boost::program_options::variables_map& options);
virtual ~StreamBasedLauncher();
StreamBasedLauncher(boost::program_options::variables_map& options);
virtual ~StreamBasedLauncher();
virtual bool Go(int timeout = 0);
virtual void DumpOutput();
virtual bool Go(int timeout = 0);
virtual void DumpOutput();
protected:
void SetupStream(WaitableStream* aStream, Stream* wrapped = nullptr);

View File

@@ -34,7 +34,7 @@ class TCPLauncher : public StreamBasedLauncher
{
TCPStream stream;
public:
TCPLauncher(po::variables_map& options);
TCPLauncher(po::variables_map& options);
};
@@ -85,10 +85,10 @@ void TCP::GetOptions(options_description &desc)
bool TCP::CheckOptions(variables_map &options)
{
return options.count("tcp-address") != 0;
return options.count("tcp-address") != 0;
}
std::unique_ptr<Launcher> TCP::MakeLauncher(variables_map &options)
{
return std::unique_ptr<Launcher>(new TCPLauncher(options));
return std::unique_ptr<Launcher>(new TCPLauncher(options));
}

View File

@@ -6,11 +6,11 @@
class TCP : public LaunchMethod
{
public:
virtual std::string GetName() { return "tcp"; }
virtual void GetOptions(options_description& desc);
virtual bool CheckOptions(variables_map& options);
virtual std::string GetName() { return "tcp"; }
virtual void GetOptions(options_description& desc);
virtual bool CheckOptions(variables_map& options);
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
};
#endif // EXECUTOR_H

View File

@@ -13,90 +13,90 @@ using std::vector;
int ChildProcess(string program, vector<string> args, int timeout)
{
std::vector<const char*> argv;
argv.push_back(program.c_str());
for(string& s : args)
argv.push_back(s.c_str());
argv.push_back(NULL);
std::vector<const char*> argv;
argv.push_back(program.c_str());
for(string& s : args)
argv.push_back(s.c_str());
argv.push_back(NULL);
pid_t pid = fork();
if(pid < 0)
{
perror("unable to fork");
return 1;
}
else if(pid == 0)
{
pid_t worker_pid = timeout ? fork() : 0;
if(worker_pid < 0)
{
perror("unable to fork");
_exit(1);
}
if(worker_pid == 0)
{
execvp(argv[0], const_cast<char* const *> (argv.data()));
perror("exec failed");
std::cerr << "Tried to execute: " << program;
for(auto a : args)
std::cerr << " " << a;
std::cerr << std::endl;
_exit(1);
}
pid_t pid = fork();
if(pid < 0)
{
perror("unable to fork");
return 1;
}
else if(pid == 0)
{
pid_t worker_pid = timeout ? fork() : 0;
if(worker_pid < 0)
{
perror("unable to fork");
_exit(1);
}
if(worker_pid == 0)
{
execvp(argv[0], const_cast<char* const *> (argv.data()));
perror("exec failed");
std::cerr << "Tried to execute: " << program;
for(auto a : args)
std::cerr << " " << a;
std::cerr << std::endl;
_exit(1);
}
pid_t timeout_pid = fork();
if(timeout_pid < 0)
{
perror("unable to fork");
_exit(1);
}
if(timeout_pid == 0)
{
sleep(timeout);
_exit(0);
}
int wstatus;
pid_t exited_pid = wait(&wstatus);
if(exited_pid == worker_pid)
{
kill(timeout_pid, SIGKILL);
wait(NULL);
if(!WIFEXITED(wstatus))
{
return 1;
}
else
{
int exitcode = WEXITSTATUS(wstatus);
_exit(exitcode);
}
}
else
{
kill(worker_pid, SIGKILL);
wait(NULL);
_exit(1);
}
}
else
{
int wstatus;
int result = 0;
do
{
result = waitpid(pid, &wstatus, 0);
} while(result == -1 && errno == EINTR);
pid_t timeout_pid = fork();
if(timeout_pid < 0)
{
perror("unable to fork");
_exit(1);
}
if(timeout_pid == 0)
{
sleep(timeout);
_exit(0);
}
int wstatus;
pid_t exited_pid = wait(&wstatus);
if(exited_pid == worker_pid)
{
kill(timeout_pid, SIGKILL);
wait(NULL);
if(!WIFEXITED(wstatus))
{
return 1;
}
else
{
int exitcode = WEXITSTATUS(wstatus);
_exit(exitcode);
}
}
else
{
kill(worker_pid, SIGKILL);
wait(NULL);
_exit(1);
}
}
else
{
int wstatus;
int result = 0;
do
{
result = waitpid(pid, &wstatus, 0);
} while(result == -1 && errno == EINTR);
if(!WIFEXITED(wstatus))
{
return 1;
}
else
{
int exitcode = WEXITSTATUS(wstatus);
return exitcode;
}
}
if(!WIFEXITED(wstatus))
{
return 1;
}
else
{
int exitcode = WEXITSTATUS(wstatus);
return exitcode;
}
}
}
@@ -104,89 +104,89 @@ int ChildProcess(string program, vector<string> args, int timeout)
bool CheckExecutable(std::string program)
{
if(access(program.c_str(), X_OK) == 0)
return true;
if(program.find("/") != std::string::npos)
return false;
const char *PATH = getenv("PATH");
if(access(program.c_str(), X_OK) == 0)
return true;
if(program.find("/") != std::string::npos)
return false;
const char *PATH = getenv("PATH");
if(PATH)
{
bool endFound = false;
do
{
const char *end = strchr(PATH, ':');
if(!end)
{
end = strchr(PATH, '\0');
endFound = true;
}
std::string pathElement(PATH, end);
if(PATH)
{
bool endFound = false;
do
{
const char *end = strchr(PATH, ':');
if(!end)
{
end = strchr(PATH, '\0');
endFound = true;
}
std::string pathElement(PATH, end);
if(pathElement == "")
pathElement = ".";
if(pathElement == "")
pathElement = ".";
fs::path f = fs::path(pathElement) / program;
fs::path f = fs::path(pathElement) / program;
if(access(f.string().c_str(), X_OK) == 0)
return true;
if(access(f.string().c_str(), X_OK) == 0)
return true;
PATH = end + 1;
} while(!endFound);
}
PATH = end + 1;
} while(!endFound);
}
return false;
return false;
}
vector<string> SplitArguments(std::string str)
{
bool backslash = false;
bool quote = false;
bool begun = false;
vector<string> args;
bool backslash = false;
bool quote = false;
bool begun = false;
vector<string> args;
for(char c : str)
{
if(!backslash && !quote && isspace(c))
{
begun = false;
}
else if(!backslash && c == '"')
{
quote = !quote;
if(quote && !begun)
{
args.emplace_back();
begun = true;
}
}
else if(!backslash && c == '\\')
{
backslash = true;
}
else
{
backslash = false;
for(char c : str)
{
if(!backslash && !quote && isspace(c))
{
begun = false;
}
else if(!backslash && c == '"')
{
quote = !quote;
if(quote && !begun)
{
args.emplace_back();
begun = true;
}
}
else if(!backslash && c == '\\')
{
backslash = true;
}
else
{
backslash = false;
if(!begun)
{
args.emplace_back();
begun = true;
}
args.back() += c;
}
}
if(!begun)
{
args.emplace_back();
begun = true;
}
args.back() += c;
}
}
return args;
return args;
}
vector<string> SplitArguments(vector<string> strs)
{
vector<string> args;
for(string str : strs)
{
vector<string> args1 = SplitArguments(str);
args.insert(args.end(), args1.begin(), args1.end());
}
return args;
vector<string> args;
for(string str : strs)
{
vector<string> args1 = SplitArguments(str);
args.insert(args.end(), args1.begin(), args1.end());
}
return args;
}

View File

@@ -645,20 +645,20 @@ int main()
#if TARGET_CPU_68K && !TARGET_RT_MAC_CFM
short& ROM85 = *(short*) 0x028E;
Boolean is128KROM = (ROM85 > 0);
Boolean hasWaitNextEvent = false;
Boolean is128KROM = (ROM85 > 0);
Boolean hasWaitNextEvent = false;
Boolean hasGestalt = false;
Boolean hasAppleEvents = false;
hasIconUtils = false;
hasColorQD = false;
if (is128KROM)
{
UniversalProcPtr trapUnimpl = GetToolTrapAddress(_Unimplemented);
if (is128KROM)
{
UniversalProcPtr trapUnimpl = GetToolTrapAddress(_Unimplemented);
UniversalProcPtr trapWaitNextEvent = GetToolTrapAddress(_WaitNextEvent);
UniversalProcPtr trapGestalt = GetOSTrapAddress(_Gestalt);
hasWaitNextEvent = (trapWaitNextEvent != trapUnimpl);
hasWaitNextEvent = (trapWaitNextEvent != trapUnimpl);
hasGestalt = (trapGestalt != trapUnimpl);
if(hasGestalt)
@@ -676,10 +676,10 @@ int main()
err = Gestalt(gestaltStandardFileAttr, &response);
hasSys7StdFile = err == noErr && (response & (1 << gestaltStandardFile58)) != 0;
}
}
}
#else
#if !TARGET_API_MAC_CARBON
const Boolean hasWaitNextEvent = true;
const Boolean hasWaitNextEvent = true;
#endif
const Boolean hasGestalt = true;
const Boolean hasAppleEvents = true;
@@ -816,5 +816,5 @@ int main()
}
WritePrefs();
return 0;
return 0;
}

View File

@@ -67,7 +67,7 @@ void MacSerialStream::write(const void* p, size_t n)
pb.ioParam.ioRefNum = outRefNum;
pb.ioParam.ioBuffer = (Ptr)p;
pb.ioParam.ioReqCount = n;
/*OSErr err =*/ PBWriteSync(&pb);
/*OSErr err =*/ PBWriteSync(&pb);
}
void MacSerialStream::idle()

View File

@@ -48,13 +48,13 @@ void MacTCPStream::startListening()
readPB.ioCRefNum = refNum;
readPB.tcpStream = tcpStream;
readPB.csCode = TCPPassiveOpen;
readPB.ioResult = 1;
readPB.csParam.open.ulpTimeoutValue = 5;// ###
readPB.csParam.open.ulpTimeoutAction = 1;
readPB.csParam.open.validityFlags = 0xC0;
readPB.csParam.open.commandTimeoutValue = 0;
readPB.csParam.open.localPort = 1984;
readPB.csCode = TCPPassiveOpen;
readPB.ioResult = 1;
readPB.csParam.open.ulpTimeoutValue = 5;// ###
readPB.csParam.open.ulpTimeoutAction = 1;
readPB.csParam.open.validityFlags = 0xC0;
readPB.csParam.open.commandTimeoutValue = 0;
readPB.csParam.open.localPort = 1984;
PBControlAsync((ParmBlkPtr)&readPB);
}
@@ -74,7 +74,7 @@ MacTCPStream::~MacTCPStream()
memset(&pb, 0, sizeof(pb));
pb.ioCRefNum = refNum;
pb.tcpStream = tcpStream;
pb.csCode = TCPRelease;
pb.csCode = TCPRelease;
PBControlSync((ParmBlkPtr)&pb);
}

View File

@@ -110,7 +110,7 @@ OpenTptStream::~OpenTptStream()
{
endpoint->SetNonBlocking();
if(connected)
endpoint->SndDisconnect(&call);
endpoint->SndDisconnect(&call);
endpoint->Unbind();
OTCloseProvider(endpoint);
}

View File

@@ -40,328 +40,328 @@ bool verboseFlag = false;
struct CFragMember
{
string name;
uint32_t architecture;
uint8_t usage;
char *data;
uint32_t length;
CFragMember() : architecture(0), usage(0), data(0), length(0) {}
CFragMember(string n, uint32_t a, uint8_t u, char *d, uint32_t l)
: name(n), architecture(a), usage(u), data(d), length(l)
{
}
string name;
uint32_t architecture;
uint8_t usage;
char *data;
uint32_t length;
CFragMember() : architecture(0), usage(0), data(0), length(0) {}
CFragMember(string n, uint32_t a, uint8_t u, char *d, uint32_t l)
: name(n), architecture(a), usage(u), data(d), length(l)
{
}
};
void RunCommand(const char *command, std::vector<std::string> args)
{
std::vector<const char*> ptrs;
ptrs.push_back(command);
for(auto& s : args)
ptrs.push_back(s.c_str());
ptrs.push_back(NULL);
std::vector<const char*> ptrs;
ptrs.push_back(command);
for(auto& s : args)
ptrs.push_back(s.c_str());
ptrs.push_back(NULL);
pid_t pid = fork();
if(pid == -1)
{
perror(command);
exit(1);
}
pid_t pid = fork();
if(pid == -1)
{
perror(command);
exit(1);
}
if(pid)
{
int status = 0;
while(waitpid(pid, &status, 0) == -1 && errno == EINTR)
;
if(!WIFEXITED(status) || WEXITSTATUS(status) != 0)
{
std::cerr << command << " failed.\n";
exit(1);
}
}
else
{
execvp(command, const_cast<char *const*>(ptrs.data()));
perror("exec");
exit(1);
}
if(pid)
{
int status = 0;
while(waitpid(pid, &status, 0) == -1 && errno == EINTR)
;
if(!WIFEXITED(status) || WEXITSTATUS(status) != 0)
{
std::cerr << command << " failed.\n";
exit(1);
}
}
else
{
execvp(command, const_cast<char *const*>(ptrs.data()));
perror("exec");
exit(1);
}
}
void MakeImportLibrary(char *pefptr, size_t pefsize, fs::path dest, fs::path tmpdir)
{
PEFContainerHeader *containerHeader = (PEFContainerHeader*) pefptr;
eswap(containerHeader);
PEFContainerHeader *containerHeader = (PEFContainerHeader*) pefptr;
eswap(containerHeader);
assert(containerHeader->tag1 == 'Joy!');
assert(containerHeader->tag2 == 'peff');
assert(containerHeader->tag1 == 'Joy!');
assert(containerHeader->tag2 == 'peff');
PEFSectionHeader *sectionHeaders
= (PEFSectionHeader*) (pefptr + kPEFFirstSectionHeaderOffset);
PEFSectionHeader *sectionHeaders
= (PEFSectionHeader*) (pefptr + kPEFFirstSectionHeaderOffset);
PEFSectionHeader *loaderHeader = NULL;
UInt16 n = containerHeader->sectionCount;
for(UInt16 i=0; i < n; i++)
{
eswap(&sectionHeaders[i]);
if(sectionHeaders[i].sectionKind == kPEFLoaderSection)
loaderHeader = &sectionHeaders[i];
}
PEFSectionHeader *loaderHeader = NULL;
UInt16 n = containerHeader->sectionCount;
for(UInt16 i=0; i < n; i++)
{
eswap(&sectionHeaders[i]);
if(sectionHeaders[i].sectionKind == kPEFLoaderSection)
loaderHeader = &sectionHeaders[i];
}
PEFLoaderInfoHeader *loaderInfoHeader
= (PEFLoaderInfoHeader*) (pefptr + loaderHeader->containerOffset);
eswap(loaderInfoHeader);
UInt32 hashTableSize = 1;
UInt32 hashTablePower = loaderInfoHeader->exportHashTablePower;
while(hashTablePower--)
hashTableSize *= 2;
UInt32 nSymbols = loaderInfoHeader->exportedSymbolCount;
const char *symbols /* use char pointer to avoid packing issues */
= (pefptr + loaderHeader->containerOffset
+ loaderInfoHeader->exportHashOffset
+ hashTableSize * sizeof(PEFExportedSymbolHashSlot)
+ nSymbols * sizeof(PEFExportedSymbolKey));
const char *stringTable = pefptr
+ loaderHeader->containerOffset
+ loaderInfoHeader->loaderStringsOffset;
/*const char *stringTableEnd = pefptr
+ loaderHeader->containerOffset
+ loaderInfoHeader->exportHashOffset;*/
vector< pair< const char *, UInt8 > > classesAndNamePtrs;
for(UInt32 i=0; i < nSymbols; i++)
{
PEFExportedSymbol *sym = (PEFExportedSymbol*) (symbols + 10*i);
eswap(sym);
PEFLoaderInfoHeader *loaderInfoHeader
= (PEFLoaderInfoHeader*) (pefptr + loaderHeader->containerOffset);
eswap(loaderInfoHeader);
UInt32 hashTableSize = 1;
UInt32 hashTablePower = loaderInfoHeader->exportHashTablePower;
while(hashTablePower--)
hashTableSize *= 2;
UInt32 nSymbols = loaderInfoHeader->exportedSymbolCount;
const char *symbols /* use char pointer to avoid packing issues */
= (pefptr + loaderHeader->containerOffset
+ loaderInfoHeader->exportHashOffset
+ hashTableSize * sizeof(PEFExportedSymbolHashSlot)
+ nSymbols * sizeof(PEFExportedSymbolKey));
const char *stringTable = pefptr
+ loaderHeader->containerOffset
+ loaderInfoHeader->loaderStringsOffset;
/*const char *stringTableEnd = pefptr
+ loaderHeader->containerOffset
+ loaderInfoHeader->exportHashOffset;*/
vector< pair< const char *, UInt8 > > classesAndNamePtrs;
for(UInt32 i=0; i < nSymbols; i++)
{
PEFExportedSymbol *sym = (PEFExportedSymbol*) (symbols + 10*i);
eswap(sym);
UInt8 symclass = PEFExportedSymbolClass(sym->classAndName);
UInt32 nameoffset = PEFExportedSymbolNameOffset(sym->classAndName);
const char *nameptr
= stringTable + nameoffset;
classesAndNamePtrs.push_back( make_pair(nameptr, symclass) );
}
std::sort(classesAndNamePtrs.begin(), classesAndNamePtrs.end());
vector< pair<string, UInt8> > exportedSymbols;
for(UInt32 i=0; i < nSymbols; i++)
{
UInt8 symclass = classesAndNamePtrs[i].second;
const char *namestart = classesAndNamePtrs[i].first;
string name;
if(i + 1 < nSymbols)
{
const char *nameend = classesAndNamePtrs[i+1].first;
name = string(namestart,nameend);
}
else
name = string(namestart);
exportedSymbols.push_back( make_pair( name, symclass ) );
}
std::sort(exportedSymbols.begin(), exportedSymbols.end());
fs::path stub_exp(tmpdir / "__stub.exp"),
stub_s(tmpdir / "__stub.s"),
stub_o(tmpdir / "__stub.o");
UInt8 symclass = PEFExportedSymbolClass(sym->classAndName);
UInt32 nameoffset = PEFExportedSymbolNameOffset(sym->classAndName);
const char *nameptr
= stringTable + nameoffset;
classesAndNamePtrs.push_back( make_pair(nameptr, symclass) );
}
std::sort(classesAndNamePtrs.begin(), classesAndNamePtrs.end());
vector< pair<string, UInt8> > exportedSymbols;
for(UInt32 i=0; i < nSymbols; i++)
{
UInt8 symclass = classesAndNamePtrs[i].second;
const char *namestart = classesAndNamePtrs[i].first;
string name;
if(i + 1 < nSymbols)
{
const char *nameend = classesAndNamePtrs[i+1].first;
name = string(namestart,nameend);
}
else
name = string(namestart);
exportedSymbols.push_back( make_pair( name, symclass ) );
}
std::sort(exportedSymbols.begin(), exportedSymbols.end());
fs::path stub_exp(tmpdir / "__stub.exp"),
stub_s(tmpdir / "__stub.s"),
stub_o(tmpdir / "__stub.o");
{
fs::ofstream expFile(stub_exp);
fs::ofstream sFile(stub_s);
sFile << "\t.toc\n";
for(UInt32 i=0; i< nSymbols; i++)
{
string& sym = exportedSymbols[i].first;
if(exportedSymbols[i].second == kPEFTVectorSymbol)
{
expFile << sym << endl;
sFile << ".text" << endl;
sFile << "\t.globl " << sym << endl;
sFile << "\t.globl ." << sym << endl;
sFile << "\t.csect " << sym << "[DS]" << endl;
sFile << sym << ':' << endl;
sFile << ".long ." << sym << ", TOC[tc0], 0" << endl;
sFile << ".text" << endl;
sFile << '.' << sym << ':' << endl;
sFile << "\tblr" << endl;
}
else if(exportedSymbols[i].second == kPEFDataSymbol)
{
expFile << sym << endl;
sFile << "\t.globl " << sym << endl;
sFile << "\t.csect .data[RW],3" << endl;
sFile << "\t.align 2" << endl;
sFile << sym << ':' << endl;
sFile << "\t.long\t42" << endl;
}
}
//cerr << "Generating: " << name << " -> " << libname << endl;
RunCommand("powerpc-apple-macos-as", std::vector<std::string> {
stub_s.string(), "-o", stub_o.string()
});
RunCommand("powerpc-apple-macos-ld", std::vector<std::string> {
"-shared", "--no-check-sections", "-bexport:" + stub_exp.string(),
"-o", dest.string(), stub_o.string()
});
}
{
fs::ofstream expFile(stub_exp);
fs::ofstream sFile(stub_s);
sFile << "\t.toc\n";
for(UInt32 i=0; i< nSymbols; i++)
{
string& sym = exportedSymbols[i].first;
if(exportedSymbols[i].second == kPEFTVectorSymbol)
{
expFile << sym << endl;
sFile << ".text" << endl;
sFile << "\t.globl " << sym << endl;
sFile << "\t.globl ." << sym << endl;
sFile << "\t.csect " << sym << "[DS]" << endl;
sFile << sym << ':' << endl;
sFile << ".long ." << sym << ", TOC[tc0], 0" << endl;
sFile << ".text" << endl;
sFile << '.' << sym << ':' << endl;
sFile << "\tblr" << endl;
}
else if(exportedSymbols[i].second == kPEFDataSymbol)
{
expFile << sym << endl;
sFile << "\t.globl " << sym << endl;
sFile << "\t.csect .data[RW],3" << endl;
sFile << "\t.align 2" << endl;
sFile << sym << ':' << endl;
sFile << "\t.long\t42" << endl;
}
}
//cerr << "Generating: " << name << " -> " << libname << endl;
RunCommand("powerpc-apple-macos-as", std::vector<std::string> {
stub_s.string(), "-o", stub_o.string()
});
RunCommand("powerpc-apple-macos-ld", std::vector<std::string> {
"-shared", "--no-check-sections", "-bexport:" + stub_exp.string(),
"-o", dest.string(), stub_o.string()
});
}
}
bool MakeImportLibraryMulti(fs::path path, fs::path libname)
{
ResourceFile resFile(path.string());
assert(resFile.read());
ResourceFile resFile(path.string());
assert(resFile.read());
std::vector<char> data(resFile.data.begin(), resFile.data.end());
std::vector<char> data(resFile.data.begin(), resFile.data.end());
char *dataPtr = data.data();
std::vector<CFragMember> members;
char *dataPtr = data.data();
std::vector<CFragMember> members;
if(data.size() < 8 || std::string(data.begin(), data.begin()+8) != "Joy!peff")
{
std::cerr << "Not a PEF shared library. Ignoring.\n";
return false;
}
if(resFile.resources.resources.find(ResRef("cfrg",0)) == resFile.resources.resources.end())
{
std::cerr << "No 'cfrg' resource found.\n";
exit(1);
}
if(data.size() < 8 || std::string(data.begin(), data.begin()+8) != "Joy!peff")
{
std::cerr << "Not a PEF shared library. Ignoring.\n";
return false;
}
if(resFile.resources.resources.find(ResRef("cfrg",0)) == resFile.resources.resources.end())
{
std::cerr << "No 'cfrg' resource found.\n";
exit(1);
}
Resource& cfrgRes = resFile.resources.resources[ResRef("cfrg",0)];
Resource& cfrgRes = resFile.resources.resources[ResRef("cfrg",0)];
CFragResource *cfrg = (CFragResource *)cfrgRes.getData().data();
eswap(cfrg);
CFragResource *cfrg = (CFragResource *)cfrgRes.getData().data();
eswap(cfrg);
CFragResourceMember *member = &(cfrg -> firstMember);
CFragResourceMember *member = &(cfrg -> firstMember);
for(UInt16 i = 0; i < cfrg->memberCount; i++)
{
eswap(member);
string membername =
string(member->name+1, member->name+1+member->name[0]);
members.emplace_back(
membername,
member->architecture,
member->usage,
dataPtr + member->offset,
member->length);
for(UInt16 i = 0; i < cfrg->memberCount; i++)
{
eswap(member);
string membername =
string(member->name+1, member->name+1+member->name[0]);
members.emplace_back(
membername,
member->architecture,
member->usage,
dataPtr + member->offset,
member->length);
member = (CFragResourceMember*) (((char*)member) + member->memberSize);
}
member = (CFragResourceMember*) (((char*)member) + member->memberSize);
}
if(!std::any_of(members.begin(), members.end(), [](const auto& member) {
return member.architecture == 'pwpc' || member.architecture == '\?\?\?\?';
}))
{
std::cerr << "Does not contain a PowerPC variant. Ignoring.\n";
return false;
}
if(!std::any_of(members.begin(), members.end(), [](const auto& member) {
return member.architecture == 'pwpc' || member.architecture == '\?\?\?\?';
}))
{
std::cerr << "Does not contain a PowerPC variant. Ignoring.\n";
return false;
}
fs::path tmpdir = libname.parent_path() / fs::unique_path("makeimport-tmp-%%%%-%%%%-%%%%-%%%%");
fs::create_directory(tmpdir);
try
{
fs::path archiveTmp(tmpdir / "__archive.a");
std::vector<string> arArguments { "cq", archiveTmp.string() };
fs::path tmpdir = libname.parent_path() / fs::unique_path("makeimport-tmp-%%%%-%%%%-%%%%-%%%%");
fs::create_directory(tmpdir);
try
{
fs::path archiveTmp(tmpdir / "__archive.a");
std::vector<string> arArguments { "cq", archiveTmp.string() };
int memberIndex = 0;
for(auto &member : members)
{
std::ostringstream memberNameStream;
// classic MacOS shared library names are in MacRoman and
// may contain wierd characters; the shared library name is used
// as the file name for the archive member, so there can be problems.
//
// We encode the file name to hex (and add a human readable name).
// MakePEF contains corresponding decoder logic.
memberNameStream << "imp__";
for(char c : member.name)
{
if(isalnum(c))
memberNameStream << c;
}
memberNameStream << "_";
for(char c : member.name)
{
int cc = (unsigned char) c;
memberNameStream << std::setw(2) << std::setfill('0') << std::hex
<< cc;
}
memberNameStream << "_" << memberIndex++;
string memberName = memberNameStream.str();
if(member.usage == 0 /* import library */
|| member.usage == 3 /* stub library */)
;
else if(member.usage == 4 /* weak stub library */)
memberName += "__weak";
if(verboseFlag)
{
char archStr[5];
archStr[0] = member.architecture >> 24;
archStr[1] = member.architecture >> 16;
archStr[2] = member.architecture >> 8;
archStr[3] = member.architecture;
archStr[4] = 0;
std::cerr << memberName << " (" << archStr << ")\n";
}
if(member.architecture == 'pwpc'
|| member.architecture == '\?\?\?\?')
{
int memberIndex = 0;
for(auto &member : members)
{
std::ostringstream memberNameStream;
// classic MacOS shared library names are in MacRoman and
// may contain wierd characters; the shared library name is used
// as the file name for the archive member, so there can be problems.
//
// We encode the file name to hex (and add a human readable name).
// MakePEF contains corresponding decoder logic.
memberNameStream << "imp__";
for(char c : member.name)
{
if(isalnum(c))
memberNameStream << c;
}
memberNameStream << "_";
for(char c : member.name)
{
int cc = (unsigned char) c;
memberNameStream << std::setw(2) << std::setfill('0') << std::hex
<< cc;
}
memberNameStream << "_" << memberIndex++;
string memberName = memberNameStream.str();
if(member.usage == 0 /* import library */
|| member.usage == 3 /* stub library */)
;
else if(member.usage == 4 /* weak stub library */)
memberName += "__weak";
if(verboseFlag)
{
char archStr[5];
archStr[0] = member.architecture >> 24;
archStr[1] = member.architecture >> 16;
archStr[2] = member.architecture >> 8;
archStr[3] = member.architecture;
archStr[4] = 0;
std::cerr << memberName << " (" << archStr << ")\n";
}
if(member.architecture == 'pwpc'
|| member.architecture == '\?\?\?\?')
{
fs::path shlib_file(tmpdir / (memberName + ".o"));
MakeImportLibrary(member.data, member.length,
shlib_file, tmpdir);
arArguments.push_back(shlib_file.string());
}
}
fs::path shlib_file(tmpdir / (memberName + ".o"));
MakeImportLibrary(member.data, member.length,
shlib_file, tmpdir);
arArguments.push_back(shlib_file.string());
}
}
RunCommand("powerpc-apple-macos-ar", arArguments);
fs::rename(archiveTmp, libname);
}
catch(...)
{
fs::remove_all(tmpdir);
throw;
}
fs::remove_all(tmpdir);
RunCommand("powerpc-apple-macos-ar", arArguments);
fs::rename(archiveTmp, libname);
}
catch(...)
{
fs::remove_all(tmpdir);
throw;
}
fs::remove_all(tmpdir);
return true;
return true;
}
int main (int argc, char * const argv[])
{
//printf("%d\n",argc);
if(argc != 3)
{
cerr << "Usage: makeimport <peflib> <libname>" << endl;
return 1;
}
int fd = open(argv[1], O_RDONLY, 0);
if(fd < 0)
{
perror(argv[1]);
return 1;
}
if(!MakeImportLibraryMulti(argv[1], argv[2]))
//printf("%d\n",argc);
if(argc != 3)
{
cerr << "Usage: makeimport <peflib> <libname>" << endl;
return 1;
}
int fd = open(argv[1], O_RDONLY, 0);
if(fd < 0)
{
perror(argv[1]);
return 1;
}
if(!MakeImportLibraryMulti(argv[1], argv[2]))
return 1;
close(fd);
close(fd);
return 0;
}

View File

@@ -31,520 +31,520 @@ bool verboseFlag = false;
inline int getI16(const void *xx)
{
const unsigned char *x = (const unsigned char*)xx;
return (x[0] << 8) | x[1];
const unsigned char *x = (const unsigned char*)xx;
return (x[0] << 8) | x[1];
}
inline int getI32(const void *xx)
{
const unsigned char *x = (const unsigned char*)xx;
return (x[0] << 24) | (x[1] << 16) | (x[2] << 8) | x[3];
const unsigned char *x = (const unsigned char*)xx;
return (x[0] << 24) | (x[1] << 16) | (x[2] << 8) | x[3];
}
inline int getI8(const void *xx)
{
return *(const unsigned char*)xx;
return *(const unsigned char*)xx;
}
template<typename ch, int n>
inline int get(const ch (&x) [n])
{
switch(n)
{
case 1: return getI8(x);
case 2: return getI16(x);
case 4: return getI32(x);
default: abort();
}
switch(n)
{
case 1: return getI8(x);
case 2: return getI16(x);
case 4: return getI32(x);
default: abort();
}
}
class ImportLib
{
public:
std::string path, base, mem;
std::vector<std::string> imports;
std::vector<int> xcoffImportIndices;
std::string path, base, mem;
std::vector<std::string> imports;
std::vector<int> xcoffImportIndices;
int nameOffset;
bool weak;
std::vector<int> symNameOffsets;
ImportLib(std::string path, std::string base, std::string mem)
: path(path), base(base), mem(mem), weak(false)
{
}
int nameOffset;
bool weak;
std::vector<int> symNameOffsets;
ImportLib(std::string path, std::string base, std::string mem)
: path(path), base(base), mem(mem), weak(false)
{
}
};
void mkpef(const std::string& inFn, const std::string& outFn)
{
std::ifstream in(inFn);
std::ifstream in(inFn);
external_filehdr xcoffHeader;
external_aouthdr aoutHeader;
external_filehdr xcoffHeader;
external_aouthdr aoutHeader;
in.read((char*) &xcoffHeader, sizeof(xcoffHeader));
assert((size_t)get(xcoffHeader.f_opthdr) >= sizeof(aoutHeader));
in.read((char*)&aoutHeader, sizeof(aoutHeader));
in.seekg(get(xcoffHeader.f_opthdr) - sizeof(aoutHeader),std::ios_base::cur);
if(verboseFlag)
{
std::cerr << "flags: " << std::hex << get(xcoffHeader.f_flags) << std::dec << std::endl;
std::cerr << "symptr: " << get(xcoffHeader.f_symptr) << std::endl;
std::cerr << "nsyms: " << get(xcoffHeader.f_nsyms) << std::endl;
}
in.read((char*) &xcoffHeader, sizeof(xcoffHeader));
assert((size_t)get(xcoffHeader.f_opthdr) >= sizeof(aoutHeader));
in.read((char*)&aoutHeader, sizeof(aoutHeader));
in.seekg(get(xcoffHeader.f_opthdr) - sizeof(aoutHeader),std::ios_base::cur);
if(verboseFlag)
{
std::cerr << "flags: " << std::hex << get(xcoffHeader.f_flags) << std::dec << std::endl;
std::cerr << "symptr: " << get(xcoffHeader.f_symptr) << std::endl;
std::cerr << "nsyms: " << get(xcoffHeader.f_nsyms) << std::endl;
}
std::map<std::string,external_scnhdr> xcoffSections;
std::map<std::string, int> xcoffSectionNumbers;
std::map<std::string,external_scnhdr> xcoffSections;
std::map<std::string, int> xcoffSectionNumbers;
int nSections = get(xcoffHeader.f_nscns);
for(int i=0;i<nSections;i++)
{
external_scnhdr xcoffSection;
in.read((char*) &xcoffSection, sizeof(xcoffSection));
int nSections = get(xcoffHeader.f_nscns);
for(int i=0;i<nSections;i++)
{
external_scnhdr xcoffSection;
in.read((char*) &xcoffSection, sizeof(xcoffSection));
if(verboseFlag)
{
std::cerr << "section: " << xcoffSection.s_name << std::endl;
std::cerr << " at: " << get(xcoffSection.s_scnptr) << std::endl;
std::cerr << " sz: " << get(xcoffSection.s_size) << std::endl;
}
xcoffSections[xcoffSection.s_name] = xcoffSection;
xcoffSectionNumbers[xcoffSection.s_name] = i+1;
}
if(verboseFlag)
{
std::cerr << "section: " << xcoffSection.s_name << std::endl;
std::cerr << " at: " << get(xcoffSection.s_scnptr) << std::endl;
std::cerr << " sz: " << get(xcoffSection.s_size) << std::endl;
}
xcoffSections[xcoffSection.s_name] = xcoffSection;
xcoffSectionNumbers[xcoffSection.s_name] = i+1;
}
std::vector<ImportLib> importLibs;
std::vector<int> importedSymbolIndices;
int totalImportedSyms = 0;
std::vector<ImportLib> importLibs;
std::vector<int> importedSymbolIndices;
int totalImportedSyms = 0;
std::vector<unsigned short> relocInstructions;
std::vector<unsigned short> relocInstructions;
{
external_scnhdr xcoffLoaderSection = xcoffSections[".loader"];
external_ldhdr xcoffLoaderHeader;
{
external_scnhdr xcoffLoaderSection = xcoffSections[".loader"];
external_ldhdr xcoffLoaderHeader;
char * loaderSectionPtr = (char*)alloca(get(xcoffLoaderSection.s_size));
in.seekg(get(xcoffLoaderSection.s_scnptr));
in.read(loaderSectionPtr, get(xcoffLoaderSection.s_size));
xcoffLoaderHeader = *(external_ldhdr*)loaderSectionPtr;
char * loaderSectionPtr = (char*)alloca(get(xcoffLoaderSection.s_size));
in.seekg(get(xcoffLoaderSection.s_scnptr));
in.read(loaderSectionPtr, get(xcoffLoaderSection.s_size));
xcoffLoaderHeader = *(external_ldhdr*)loaderSectionPtr;
char *p = loaderSectionPtr + get(xcoffLoaderHeader.l_impoff);
for(int i=0; i<get(xcoffLoaderHeader.l_nimpid); i++)
{
std::string path = p;
p += strlen(p) + 1;
std::string base = p;
p += strlen(p) + 1;
std::string mem = p;
p += strlen(p) + 1;
importLibs.push_back(ImportLib(path,base,mem));
if(verboseFlag)
std::cerr << "Import: " << path << ", " << base << ", " << mem << '\n';
}
char *p = loaderSectionPtr + get(xcoffLoaderHeader.l_impoff);
for(int i=0; i<get(xcoffLoaderHeader.l_nimpid); i++)
{
std::string path = p;
p += strlen(p) + 1;
std::string base = p;
p += strlen(p) + 1;
std::string mem = p;
p += strlen(p) + 1;
importLibs.push_back(ImportLib(path,base,mem));
if(verboseFlag)
std::cerr << "Import: " << path << ", " << base << ", " << mem << '\n';
}
external_ldsym *syms = (external_ldsym*) (loaderSectionPtr + sizeof(external_ldhdr));
for(int i=0; i<get(xcoffLoaderHeader.l_nsyms); i++)
{
std::string name;
external_ldsym& sym = syms[i];
external_ldsym *syms = (external_ldsym*) (loaderSectionPtr + sizeof(external_ldhdr));
for(int i=0; i<get(xcoffLoaderHeader.l_nsyms); i++)
{
std::string name;
external_ldsym& sym = syms[i];
if(get(sym._l._l_l._l_zeroes) == 0)
{
name = loaderSectionPtr + get(xcoffLoaderHeader.l_stoff)
+ get(sym._l._l_l._l_offset);
}
else
name = sym._l._l_name;
if(verboseFlag)
std::cerr << "Loader Symbol: " << name << std::endl;
if((get(sym.l_smtype) & 0xF8) == 0x40 /*L_IMPORT*/)
{
assert((get(sym.l_smtype) & 3) == 0 /*XTY_ER*/);
if(verboseFlag)
std::cerr << "... from file: " << get(sym.l_ifile) << std::endl;
importLibs[get(sym.l_ifile)].imports.push_back(name);
importLibs[get(sym.l_ifile)].xcoffImportIndices.push_back(i);
totalImportedSyms++;
}
}
importedSymbolIndices.resize(get(xcoffLoaderHeader.l_nsyms));
{
int symbolIndex = 0;
for(unsigned i=1;i<importLibs.size();i++)
{
for(unsigned j=0;j<importLibs[i].xcoffImportIndices.size();j++)
{
importedSymbolIndices[importLibs[i].xcoffImportIndices[j]] = symbolIndex;
symbolIndex++;
}
}
}
if(get(sym._l._l_l._l_zeroes) == 0)
{
name = loaderSectionPtr + get(xcoffLoaderHeader.l_stoff)
+ get(sym._l._l_l._l_offset);
}
else
name = sym._l._l_name;
if(verboseFlag)
std::cerr << "Loader Symbol: " << name << std::endl;
if((get(sym.l_smtype) & 0xF8) == 0x40 /*L_IMPORT*/)
{
assert((get(sym.l_smtype) & 3) == 0 /*XTY_ER*/);
if(verboseFlag)
std::cerr << "... from file: " << get(sym.l_ifile) << std::endl;
importLibs[get(sym.l_ifile)].imports.push_back(name);
importLibs[get(sym.l_ifile)].xcoffImportIndices.push_back(i);
totalImportedSyms++;
}
}
importedSymbolIndices.resize(get(xcoffLoaderHeader.l_nsyms));
{
int symbolIndex = 0;
for(unsigned i=1;i<importLibs.size();i++)
{
for(unsigned j=0;j<importLibs[i].xcoffImportIndices.size();j++)
{
importedSymbolIndices[importLibs[i].xcoffImportIndices[j]] = symbolIndex;
symbolIndex++;
}
}
}
int xcoffDataSecNumber = xcoffSectionNumbers[".data"];
int xcoffDataSecNumber = xcoffSectionNumbers[".data"];
external_ldrel *rels = (external_ldrel*) (loaderSectionPtr + sizeof(external_ldhdr) + get(xcoffLoaderHeader.l_nsyms) * sizeof(external_ldsym));
for(int i=0; i<get(xcoffLoaderHeader.l_nreloc); i++)
{
external_ldrel& rel = rels[i];
external_ldrel *rels = (external_ldrel*) (loaderSectionPtr + sizeof(external_ldhdr) + get(xcoffLoaderHeader.l_nsyms) * sizeof(external_ldsym));
for(int i=0; i<get(xcoffLoaderHeader.l_nreloc); i++)
{
external_ldrel& rel = rels[i];
if(verboseFlag)
{
std::cerr << "[" << i << "] reloc: " << std::hex << get(rel.l_vaddr) << " " << get(rel.l_symndx) << " " << get(rel.l_rtype) << " " << get(rel.l_rsecnm) << "\n";
}
assert(get(rel.l_rtype) == 0x1f00);
assert(get(rel.l_rsecnm) == xcoffDataSecNumber);
if(verboseFlag)
{
std::cerr << "[" << i << "] reloc: " << std::hex << get(rel.l_vaddr) << " " << get(rel.l_symndx) << " " << get(rel.l_rtype) << " " << get(rel.l_rsecnm) << "\n";
}
assert(get(rel.l_rtype) == 0x1f00);
assert(get(rel.l_rsecnm) == xcoffDataSecNumber);
int vaddr = get(rel.l_vaddr);
int vaddr = get(rel.l_vaddr);
relocInstructions.push_back(
PEFRelocComposeSetPosition_1st(vaddr));
relocInstructions.push_back(
PEFRelocComposeSetPosition_2nd(vaddr));
if(get(rel.l_symndx) == 0)
relocInstructions.push_back(PEFRelocComposeBySectC(1));
else if(get(rel.l_symndx) == 1 || get(rel.l_symndx) == 2)
relocInstructions.push_back(PEFRelocComposeBySectD(1));
else
{
int importIndex = importedSymbolIndices[get(rel.l_symndx) - 3];
relocInstructions.push_back(
PEFRelocComposeLgByImport_1st(importIndex));
relocInstructions.push_back(
PEFRelocComposeLgByImport_2nd(importIndex));
}
}
}
PEFContainerHeader pefHeader;
relocInstructions.push_back(
PEFRelocComposeSetPosition_1st(vaddr));
relocInstructions.push_back(
PEFRelocComposeSetPosition_2nd(vaddr));
if(get(rel.l_symndx) == 0)
relocInstructions.push_back(PEFRelocComposeBySectC(1));
else if(get(rel.l_symndx) == 1 || get(rel.l_symndx) == 2)
relocInstructions.push_back(PEFRelocComposeBySectD(1));
else
{
int importIndex = importedSymbolIndices[get(rel.l_symndx) - 3];
relocInstructions.push_back(
PEFRelocComposeLgByImport_1st(importIndex));
relocInstructions.push_back(
PEFRelocComposeLgByImport_2nd(importIndex));
}
}
}
PEFContainerHeader pefHeader;
memset(&pefHeader,0,sizeof(pefHeader));
memset(&pefHeader,0,sizeof(pefHeader));
pefHeader.tag1 = kPEFTag1;
pefHeader.tag2 = kPEFTag2;
pefHeader.architecture = 'pwpc';
pefHeader.formatVersion = kPEFVersion;
pefHeader.sectionCount = 3; // .text, .data, .loader
pefHeader.instSectionCount = 2; // .text, .data
pefHeader.tag1 = kPEFTag1;
pefHeader.tag2 = kPEFTag2;
pefHeader.architecture = 'pwpc';
pefHeader.formatVersion = kPEFVersion;
pefHeader.sectionCount = 3; // .text, .data, .loader
pefHeader.instSectionCount = 2; // .text, .data
PEFLoaderInfoHeader loaderInfoHeader;
memset(&loaderInfoHeader, 0, sizeof(loaderInfoHeader));
PEFLoaderInfoHeader loaderInfoHeader;
memset(&loaderInfoHeader, 0, sizeof(loaderInfoHeader));
loaderInfoHeader.mainSection = -1;
loaderInfoHeader.initSection = -1;
loaderInfoHeader.termSection = -1;
loaderInfoHeader.mainSection = -1;
loaderInfoHeader.initSection = -1;
loaderInfoHeader.termSection = -1;
loaderInfoHeader.mainSection = 1;
loaderInfoHeader.mainOffset = get(aoutHeader.entry);
loaderInfoHeader.mainSection = 1;
loaderInfoHeader.mainOffset = get(aoutHeader.entry);
PEFSectionHeader textSectionHeader, dataSectionHeader, loaderSectionHeader;
memset(&textSectionHeader, 0, sizeof(textSectionHeader));
memset(&dataSectionHeader, 0, sizeof(dataSectionHeader));
memset(&loaderSectionHeader, 0, sizeof(loaderSectionHeader));
int textSize = get(xcoffSections[".text"].s_size);
textSectionHeader.nameOffset = -1;
textSectionHeader.defaultAddress = 0;
textSectionHeader.totalLength = textSize;
textSectionHeader.unpackedLength = textSize;
textSectionHeader.containerLength = textSize;
textSectionHeader.containerOffset = sizeof(PEFContainerHeader) + 3*sizeof(PEFSectionHeader);
textSectionHeader.sectionKind = kPEFCodeSection;
textSectionHeader.shareKind = kPEFGlobalShare;
textSectionHeader.alignment = 2;
PEFSectionHeader textSectionHeader, dataSectionHeader, loaderSectionHeader;
memset(&textSectionHeader, 0, sizeof(textSectionHeader));
memset(&dataSectionHeader, 0, sizeof(dataSectionHeader));
memset(&loaderSectionHeader, 0, sizeof(loaderSectionHeader));
int textSize = get(xcoffSections[".text"].s_size);
textSectionHeader.nameOffset = -1;
textSectionHeader.defaultAddress = 0;
textSectionHeader.totalLength = textSize;
textSectionHeader.unpackedLength = textSize;
textSectionHeader.containerLength = textSize;
textSectionHeader.containerOffset = sizeof(PEFContainerHeader) + 3*sizeof(PEFSectionHeader);
textSectionHeader.sectionKind = kPEFCodeSection;
textSectionHeader.shareKind = kPEFGlobalShare;
textSectionHeader.alignment = 2;
int dataSize = get(xcoffSections[".data"].s_size);
dataSectionHeader.nameOffset = -1;
dataSectionHeader.defaultAddress = 0;
dataSectionHeader.totalLength = dataSize + get(xcoffSections[".bss"].s_size);
dataSectionHeader.unpackedLength = dataSize;
dataSectionHeader.containerLength = dataSize;
dataSectionHeader.containerOffset = sizeof(PEFContainerHeader) + 3*sizeof(PEFSectionHeader) + textSize;
dataSectionHeader.sectionKind = kPEFUnpackedDataSection;
dataSectionHeader.shareKind = kPEFProcessShare;
dataSectionHeader.alignment = 2;
int dataSize = get(xcoffSections[".data"].s_size);
dataSectionHeader.nameOffset = -1;
dataSectionHeader.defaultAddress = 0;
dataSectionHeader.totalLength = dataSize + get(xcoffSections[".bss"].s_size);
dataSectionHeader.unpackedLength = dataSize;
dataSectionHeader.containerLength = dataSize;
dataSectionHeader.containerOffset = sizeof(PEFContainerHeader) + 3*sizeof(PEFSectionHeader) + textSize;
dataSectionHeader.sectionKind = kPEFUnpackedDataSection;
dataSectionHeader.shareKind = kPEFProcessShare;
dataSectionHeader.alignment = 2;
std::vector<std::string> loaderStringTable;
int loaderStringTableSize = 0;
for(unsigned i=1;i<importLibs.size();i++)
{
ImportLib& imp = importLibs[i];
std::string name;
if(imp.mem != "")
name = imp.mem;
else
name = imp.base;
std::vector<std::string> loaderStringTable;
int loaderStringTableSize = 0;
for(unsigned i=1;i<importLibs.size();i++)
{
ImportLib& imp = importLibs[i];
std::string name;
if(imp.mem != "")
name = imp.mem;
else
name = imp.base;
if(verboseFlag)
{
std::cerr << "XCOFF name \"" << name << '"';
}
int dotIndex = name.rfind('.');
if(dotIndex)
{
name = name.substr(0,dotIndex);
if(name.substr(0,3) == "lib")
name = name.substr(3);
}
if(verboseFlag)
{
std::cerr << "XCOFF name \"" << name << '"';
}
int dotIndex = name.rfind('.');
if(dotIndex)
{
name = name.substr(0,dotIndex);
if(name.substr(0,3) == "lib")
name = name.substr(3);
}
if(name.length() > 6)
{
if(name.substr(name.length()-6,6) == "__weak")
{
name = name.substr(0,name.length()-6);
imp.weak = true;
}
}
if(name.length() > 5)
{
// the shared library name has been encoded as hex by MakeImport
// in order to avoid potential file name issues
// classic MacOS shared library names are in MacRoman and
// may contain wierd characters; the shared library name is used
// as the file name for the archive member, so there can be problems.
if(name.substr(0,5) == "imp__")
{
std::string realName;
int i;
int n = name.size();
for(i = 5; i < n && name[i] != '_'; i++)
;
++i;
for(; i + 1 < n && name[i] != '_'; i+=2)
{
char c1 = tolower(name[i]);
char c2 = tolower(name[i+1]);
assert(isdigit(c1) || (c1 >= 'a' && c1 <= 'f'));
assert(isdigit(c2) || (c2 >= 'a' && c2 <= 'f'));
int c = (c1 >= 'a' ? c1 - 'a' + 10 : c1 - '0') * 16
+ (c2 >= 'a' ? c2 - 'a' + 10 : c2 - '0');
realName += (char)c;
}
name = realName;
}
}
if(verboseFlag)
{
std::cerr << "PEF name \"" << name << '"';
if(imp.weak)
std::cerr << " (weak)";
std::cerr << " at " << std::hex << loaderStringTableSize << std::dec
<< std::endl;
}
importLibs[i].nameOffset = loaderStringTableSize;
loaderStringTable.push_back(name);
loaderStringTableSize += name.length() + 1;
for(unsigned j=0;j<importLibs[i].imports.size();j++)
{
name = importLibs[i].imports[j];
if(verboseFlag)
std::cerr << "Sym name \"" << name << "\" at " << std::hex
<< loaderStringTableSize << std::dec << std::endl;
importLibs[i].symNameOffsets.push_back(loaderStringTableSize);
loaderStringTable.push_back(name);
loaderStringTableSize += name.length() + 1;
}
}
if(name.length() > 6)
{
if(name.substr(name.length()-6,6) == "__weak")
{
name = name.substr(0,name.length()-6);
imp.weak = true;
}
}
if(name.length() > 5)
{
// the shared library name has been encoded as hex by MakeImport
// in order to avoid potential file name issues
// classic MacOS shared library names are in MacRoman and
// may contain wierd characters; the shared library name is used
// as the file name for the archive member, so there can be problems.
if(name.substr(0,5) == "imp__")
{
std::string realName;
int i;
int n = name.size();
for(i = 5; i < n && name[i] != '_'; i++)
;
++i;
for(; i + 1 < n && name[i] != '_'; i+=2)
{
char c1 = tolower(name[i]);
char c2 = tolower(name[i+1]);
assert(isdigit(c1) || (c1 >= 'a' && c1 <= 'f'));
assert(isdigit(c2) || (c2 >= 'a' && c2 <= 'f'));
int c = (c1 >= 'a' ? c1 - 'a' + 10 : c1 - '0') * 16
+ (c2 >= 'a' ? c2 - 'a' + 10 : c2 - '0');
realName += (char)c;
}
name = realName;
}
}
if(verboseFlag)
{
std::cerr << "PEF name \"" << name << '"';
if(imp.weak)
std::cerr << " (weak)";
std::cerr << " at " << std::hex << loaderStringTableSize << std::dec
<< std::endl;
}
importLibs[i].nameOffset = loaderStringTableSize;
loaderStringTable.push_back(name);
loaderStringTableSize += name.length() + 1;
for(unsigned j=0;j<importLibs[i].imports.size();j++)
{
name = importLibs[i].imports[j];
if(verboseFlag)
std::cerr << "Sym name \"" << name << "\" at " << std::hex
<< loaderStringTableSize << std::dec << std::endl;
importLibs[i].symNameOffsets.push_back(loaderStringTableSize);
loaderStringTable.push_back(name);
loaderStringTableSize += name.length() + 1;
}
}
loaderInfoHeader.importedLibraryCount = importLibs.size()-1;
loaderInfoHeader.totalImportedSymbolCount = totalImportedSyms;
loaderInfoHeader.relocSectionCount = 1; // data only
loaderInfoHeader.relocInstrOffset = sizeof(PEFLoaderInfoHeader)
+ sizeof(PEFImportedLibrary)*(importLibs.size()-1)
+ sizeof(PEFImportedSymbol)*totalImportedSyms
+ sizeof(PEFLoaderRelocationHeader);
if(verboseFlag)
{
std::cerr << "reloc instr offset: " << loaderInfoHeader.relocInstrOffset
<< " = " << sizeof(PEFLoaderInfoHeader)
<< " + " << sizeof(PEFImportedLibrary)*(importLibs.size()-1)
<< " + " << sizeof(PEFImportedSymbol)*totalImportedSyms
<< " + " << sizeof(PEFLoaderRelocationHeader)
<< std::endl;
}
loaderInfoHeader.loaderStringsOffset = loaderInfoHeader.relocInstrOffset
+ relocInstructions.size() * 2;
loaderInfoHeader.exportHashOffset = loaderInfoHeader.loaderStringsOffset
+ loaderStringTableSize;
loaderInfoHeader.importedLibraryCount = importLibs.size()-1;
loaderInfoHeader.totalImportedSymbolCount = totalImportedSyms;
loaderInfoHeader.relocSectionCount = 1; // data only
loaderInfoHeader.relocInstrOffset = sizeof(PEFLoaderInfoHeader)
+ sizeof(PEFImportedLibrary)*(importLibs.size()-1)
+ sizeof(PEFImportedSymbol)*totalImportedSyms
+ sizeof(PEFLoaderRelocationHeader);
if(verboseFlag)
{
std::cerr << "reloc instr offset: " << loaderInfoHeader.relocInstrOffset
<< " = " << sizeof(PEFLoaderInfoHeader)
<< " + " << sizeof(PEFImportedLibrary)*(importLibs.size()-1)
<< " + " << sizeof(PEFImportedSymbol)*totalImportedSyms
<< " + " << sizeof(PEFLoaderRelocationHeader)
<< std::endl;
}
loaderInfoHeader.loaderStringsOffset = loaderInfoHeader.relocInstrOffset
+ relocInstructions.size() * 2;
loaderInfoHeader.exportHashOffset = loaderInfoHeader.loaderStringsOffset
+ loaderStringTableSize;
PEFLoaderRelocationHeader dataRelocationHeader;
dataRelocationHeader.sectionIndex = 1;
dataRelocationHeader.reservedA = 0;
dataRelocationHeader.relocCount = relocInstructions.size();
dataRelocationHeader.firstRelocOffset = 0;
PEFLoaderRelocationHeader dataRelocationHeader;
dataRelocationHeader.sectionIndex = 1;
dataRelocationHeader.reservedA = 0;
dataRelocationHeader.relocCount = relocInstructions.size();
dataRelocationHeader.firstRelocOffset = 0;
loaderSectionHeader.nameOffset = -1;
loaderSectionHeader.defaultAddress = 0;
loaderSectionHeader.totalLength = 0;
loaderSectionHeader.unpackedLength = 0;
loaderSectionHeader.containerLength = loaderInfoHeader.exportHashOffset + 4;
loaderSectionHeader.containerOffset = sizeof(PEFContainerHeader) + 3*sizeof(PEFSectionHeader)
+ textSize + dataSize;
loaderSectionHeader.sectionKind = kPEFLoaderSection;
loaderSectionHeader.shareKind = kPEFGlobalShare;
loaderSectionHeader.alignment = 2;
std::ofstream out(outFn);
if(verboseFlag)
std::cerr << "Writing Headers..." << std::flush;
loaderSectionHeader.nameOffset = -1;
loaderSectionHeader.defaultAddress = 0;
loaderSectionHeader.totalLength = 0;
loaderSectionHeader.unpackedLength = 0;
loaderSectionHeader.containerLength = loaderInfoHeader.exportHashOffset + 4;
loaderSectionHeader.containerOffset = sizeof(PEFContainerHeader) + 3*sizeof(PEFSectionHeader)
+ textSize + dataSize;
loaderSectionHeader.sectionKind = kPEFLoaderSection;
loaderSectionHeader.shareKind = kPEFGlobalShare;
loaderSectionHeader.alignment = 2;
std::ofstream out(outFn);
if(verboseFlag)
std::cerr << "Writing Headers..." << std::flush;
eswap(&pefHeader);
out.write((char*)&pefHeader, sizeof(pefHeader));
eswap(&textSectionHeader);
out.write((char*)&textSectionHeader, sizeof(textSectionHeader));
eswap(&dataSectionHeader);
out.write((char*)&dataSectionHeader, sizeof(dataSectionHeader));
eswap(&loaderSectionHeader);
out.write((char*)&loaderSectionHeader, sizeof(loaderSectionHeader));
if(verboseFlag)
std::cerr << "done.\nCopying text and data..." << std::flush;
{
char *buf = new char[textSize];
in.seekg(get(xcoffSections[".text"].s_scnptr));
in.read(buf, textSize);
out.write(buf, textSize);
delete[] buf;
}
{
char *buf = new char[dataSize];
in.seekg(get(xcoffSections[".data"].s_scnptr));
in.read(buf, dataSize);
out.write(buf, dataSize);
delete[] buf;
}
if(verboseFlag)
std::cerr << "done.\n";
eswap(&loaderInfoHeader);
out.write((char*)&loaderInfoHeader, sizeof(loaderInfoHeader));
int firstImportedSymbol = 0;
if(verboseFlag)
std::cerr << "imports..." << std::flush;
for(unsigned i=1;i<importLibs.size();i++)
{
PEFImportedLibrary impLib;
memset(&impLib,0,sizeof(impLib));
impLib.nameOffset = importLibs[i].nameOffset;
impLib.importedSymbolCount = importLibs[i].imports.size();
impLib.firstImportedSymbol= firstImportedSymbol;
firstImportedSymbol += impLib.importedSymbolCount;
if(importLibs[i].weak)
impLib.options = kPEFWeakImportLibMask;
eswap(&impLib);
out.write((char*)&impLib, sizeof(impLib));
}
for(unsigned i=1;i<importLibs.size();i++)
{
for(unsigned j=0;j<importLibs[i].imports.size();j++)
{
PEFImportedSymbol sym;
sym.classAndName = PEFComposeImportedSymbol(kPEFTVectorSymbol /* ### */,
importLibs[i].symNameOffsets[j]);
eswap(&sym);
out.write((char*)&sym, sizeof(sym));
}
}
if(verboseFlag)
std::cerr << "done.\n";
if(verboseFlag)
std::cerr << "relocations..." << std::flush;
eswap(&dataRelocationHeader);
out.write((char*)&dataRelocationHeader, sizeof(dataRelocationHeader));
for(unsigned i=0;i<relocInstructions.size();i++)
{
short insn = relocInstructions[i];
eswap(&insn, "s");
out.write((char*)&insn, sizeof(insn));
}
if(verboseFlag)
{
std::cerr << "done.\n";
std::cerr << "strings..." << std::flush;
}
for(unsigned i=0;i<loaderStringTable.size();i++)
{
out.write(loaderStringTable[i].c_str(),loaderStringTable[i].length()+1);
}
if(verboseFlag)
std::cerr << "done.\n";
{
int zero = 0;
out.write((char*)&zero, 4);
}
eswap(&pefHeader);
out.write((char*)&pefHeader, sizeof(pefHeader));
eswap(&textSectionHeader);
out.write((char*)&textSectionHeader, sizeof(textSectionHeader));
eswap(&dataSectionHeader);
out.write((char*)&dataSectionHeader, sizeof(dataSectionHeader));
eswap(&loaderSectionHeader);
out.write((char*)&loaderSectionHeader, sizeof(loaderSectionHeader));
if(verboseFlag)
std::cerr << "done.\nCopying text and data..." << std::flush;
{
char *buf = new char[textSize];
in.seekg(get(xcoffSections[".text"].s_scnptr));
in.read(buf, textSize);
out.write(buf, textSize);
delete[] buf;
}
{
char *buf = new char[dataSize];
in.seekg(get(xcoffSections[".data"].s_scnptr));
in.read(buf, dataSize);
out.write(buf, dataSize);
delete[] buf;
}
if(verboseFlag)
std::cerr << "done.\n";
eswap(&loaderInfoHeader);
out.write((char*)&loaderInfoHeader, sizeof(loaderInfoHeader));
int firstImportedSymbol = 0;
if(verboseFlag)
std::cerr << "imports..." << std::flush;
for(unsigned i=1;i<importLibs.size();i++)
{
PEFImportedLibrary impLib;
memset(&impLib,0,sizeof(impLib));
impLib.nameOffset = importLibs[i].nameOffset;
impLib.importedSymbolCount = importLibs[i].imports.size();
impLib.firstImportedSymbol= firstImportedSymbol;
firstImportedSymbol += impLib.importedSymbolCount;
if(importLibs[i].weak)
impLib.options = kPEFWeakImportLibMask;
eswap(&impLib);
out.write((char*)&impLib, sizeof(impLib));
}
for(unsigned i=1;i<importLibs.size();i++)
{
for(unsigned j=0;j<importLibs[i].imports.size();j++)
{
PEFImportedSymbol sym;
sym.classAndName = PEFComposeImportedSymbol(kPEFTVectorSymbol /* ### */,
importLibs[i].symNameOffsets[j]);
eswap(&sym);
out.write((char*)&sym, sizeof(sym));
}
}
if(verboseFlag)
std::cerr << "done.\n";
if(verboseFlag)
std::cerr << "relocations..." << std::flush;
eswap(&dataRelocationHeader);
out.write((char*)&dataRelocationHeader, sizeof(dataRelocationHeader));
for(unsigned i=0;i<relocInstructions.size();i++)
{
short insn = relocInstructions[i];
eswap(&insn, "s");
out.write((char*)&insn, sizeof(insn));
}
if(verboseFlag)
{
std::cerr << "done.\n";
std::cerr << "strings..." << std::flush;
}
for(unsigned i=0;i<loaderStringTable.size();i++)
{
out.write(loaderStringTable[i].c_str(),loaderStringTable[i].length()+1);
}
if(verboseFlag)
std::cerr << "done.\n";
{
int zero = 0;
out.write((char*)&zero, 4);
}
}
int main (int argc, char * const argv[]) {
bool hadInput = false;
std::string inputFn;
bool hadOutput = false;
std::string outputFn = "";
for(int i=1;i<argc;i++)
{
std::string arg = argv[i];
if(arg == "-v")
verboseFlag = true;
else if(arg == "-o")
{
i++;
if(i >= argc)
{
std::cerr << "makepef: -o requires an argument.\n";
return 1;
}
if(hadOutput)
{
std::cerr << "makepef: -o can only be used once.\n";
return 1;
}
outputFn = argv[i];
hadOutput = true;
}
else
{
if(hadInput)
{
std::cerr << "makepef: can only handle one input file.\n";
return 1;
}
inputFn = argv[i];
hadInput = true;
}
}
if(!hadInput)
{
std::cerr << "makepef: no input file specified.\n";
return 1;
}
if(!hadOutput)
{
std::cerr << "makepef: no output file specified.\n";
return 1;
}
mkpef(inputFn, outputFn);
bool hadInput = false;
std::string inputFn;
bool hadOutput = false;
std::string outputFn = "";
for(int i=1;i<argc;i++)
{
std::string arg = argv[i];
if(arg == "-v")
verboseFlag = true;
else if(arg == "-o")
{
i++;
if(i >= argc)
{
std::cerr << "makepef: -o requires an argument.\n";
return 1;
}
if(hadOutput)
{
std::cerr << "makepef: -o can only be used once.\n";
return 1;
}
outputFn = argv[i];
hadOutput = true;
}
else
{
if(hadInput)
{
std::cerr << "makepef: can only handle one input file.\n";
return 1;
}
inputFn = argv[i];
hadInput = true;
}
}
if(!hadInput)
{
std::cerr << "makepef: no input file specified.\n";
return 1;
}
if(!hadOutput)
{
std::cerr << "makepef: no output file specified.\n";
return 1;
}
mkpef(inputFn, outputFn);
return 0;
}

View File

@@ -21,9 +21,9 @@
*/
#define __MACTYPES__
#define __TYPES__
typedef uint8_t UInt8;
typedef int8_t SInt8;
typedef uint16_t UInt16;
typedef uint8_t UInt8;
typedef int8_t SInt8;
typedef uint16_t UInt16;
typedef int16_t SInt16;
typedef uint32_t UInt32;
typedef int32_t SInt32;
@@ -46,55 +46,55 @@ typedef struct {} FSSpec, *FSSpecPtr;
/* Deal with differences between versions of PEFBinaryFormat.h */
#ifndef PEFRelocComposeSetPosition_1st
#define PEFRelocComposeSetPosition_1st(fullOffset) \
( 0xA000 | ((UInt16) (((UInt32)(fullOffset)) >> 16) ) )
( 0xA000 | ((UInt16) (((UInt32)(fullOffset)) >> 16) ) )
#define PEFRelocComposeSetPosition_2nd(fullOffset) \
( (UInt16) ((UInt32)(fullOffset) & 0xFFFF) )
( (UInt16) ((UInt32)(fullOffset) & 0xFFFF) )
#define PEFRelocComposeLgByImport_1st(fullIndex) \
( 0xA400 | ((UInt16) (((UInt32)(fullIndex)) >> 16) ) )
( 0xA400 | ((UInt16) (((UInt32)(fullIndex)) >> 16) ) )
#define PEFRelocComposeLgByImport_2nd(fullIndex) \
( (UInt16) ((UInt32)(fullIndex) & 0xFFFF) )
( (UInt16) ((UInt32)(fullIndex) & 0xFFFF) )
#endif
template <typename T>
void eswap(T *data, const char * format)
{
int endianTest = 1;
if(*(char*)&endianTest == 0)
return;
int endianTest = 1;
if(*(char*)&endianTest == 0)
return;
char *p = reinterpret_cast<char*>(data);
const char *q = format;
while(char c = *q++)
{
assert(p <= reinterpret_cast<char*>(data) + sizeof(T));
if(c == 'L')
{
std::swap(p[0], p[3]);
std::swap(p[1], p[2]);
p += 4;
}
else if(c == 's')
{
std::swap(p[0], p[1]);
p += 2;
}
else if(c == '*')
{
return;
}
else
{
assert(c == '.');
++p;
}
}
char *p = reinterpret_cast<char*>(data);
const char *q = format;
while(char c = *q++)
{
assert(p <= reinterpret_cast<char*>(data) + sizeof(T));
if(c == 'L')
{
std::swap(p[0], p[3]);
std::swap(p[1], p[2]);
p += 4;
}
else if(c == 's')
{
std::swap(p[0], p[1]);
p += 2;
}
else if(c == '*')
{
return;
}
else
{
assert(c == '.');
++p;
}
}
assert(p == reinterpret_cast<char*>(data) + sizeof(T));
assert(p == reinterpret_cast<char*>(data) + sizeof(T));
}
#define DEFINE_ESWAP(T, S) \
inline void eswap(T* data) { eswap(data, S); }
inline void eswap(T* data) { eswap(data, S); }
DEFINE_ESWAP(PEFContainerHeader, "LLLLLLLLssL")
DEFINE_ESWAP(PEFSectionHeader, "LLLLLL....")
@@ -107,37 +107,37 @@ DEFINE_ESWAP(PEFExportedSymbol, "LLs")
struct CFragResourceMember {
uint32_t architecture;
uint16_t reservedA;
uint8_t reservedB;
uint8_t updateLevel;
uint32_t currentVersion;
uint32_t oldDefVersion;
uint32_t uUsage1;
uint16_t uUsage2;
uint8_t usage;
uint8_t where;
uint32_t offset;
uint32_t length;
uint32_t uWhere1;
uint16_t uWhere2;
uint16_t extensionCount;
uint16_t memberSize;
unsigned char name[16];
uint32_t architecture;
uint16_t reservedA;
uint8_t reservedB;
uint8_t updateLevel;
uint32_t currentVersion;
uint32_t oldDefVersion;
uint32_t uUsage1;
uint16_t uUsage2;
uint8_t usage;
uint8_t where;
uint32_t offset;
uint32_t length;
uint32_t uWhere1;
uint16_t uWhere2;
uint16_t extensionCount;
uint16_t memberSize;
unsigned char name[16];
};
struct CFragResource {
uint32_t reservedA;
uint32_t reservedB;
uint16_t reservedC;
uint16_t version;
uint32_t reservedD;
uint32_t reservedE;
uint32_t reservedF;
uint32_t reservedG;
uint16_t reservedH;
uint16_t memberCount;
CFragResourceMember firstMember;
uint32_t reservedA;
uint32_t reservedB;
uint16_t reservedC;
uint16_t version;
uint32_t reservedD;
uint32_t reservedE;
uint32_t reservedF;
uint32_t reservedG;
uint16_t reservedH;
uint16_t memberCount;
CFragResourceMember firstMember;
};

View File

@@ -21,13 +21,13 @@
/********************** FILE HEADER **********************/
struct external_filehdr {
char f_magic[2]; /* magic number */
char f_nscns[2]; /* number of sections */
char f_timdat[4]; /* time & date stamp */
char f_symptr[4]; /* file pointer to symtab */
char f_nsyms[4]; /* number of symtab entries */
char f_opthdr[2]; /* sizeof(optional hdr) */
char f_flags[2]; /* flags */
char f_magic[2]; /* magic number */
char f_nscns[2]; /* number of sections */
char f_timdat[4]; /* time & date stamp */
char f_symptr[4]; /* file pointer to symtab */
char f_nsyms[4]; /* number of symtab entries */
char f_opthdr[2]; /* sizeof(optional hdr) */
char f_flags[2]; /* flags */
};
/* IBM RS/6000 */
@@ -35,12 +35,12 @@ struct external_filehdr {
#define U802ROMAGIC 0735 /* readonly sharable text segments */
#define U802TOCMAGIC 0737 /* readonly text segments and TOC */
#define BADMAG(x) \
((x).f_magic != U802ROMAGIC && (x).f_magic != U802WRMAGIC && \
(x).f_magic != U802TOCMAGIC)
#define BADMAG(x) \
((x).f_magic != U802ROMAGIC && (x).f_magic != U802WRMAGIC && \
(x).f_magic != U802TOCMAGIC)
#define FILHDR struct external_filehdr
#define FILHSZ 20
#define FILHDR struct external_filehdr
#define FILHSZ 20
/********************** AOUT "OPTIONAL HEADER" **********************/
@@ -48,28 +48,28 @@ struct external_filehdr {
typedef struct
{
unsigned char magic[2]; /* type of file */
unsigned char vstamp[2]; /* version stamp */
unsigned char tsize[4]; /* text size in bytes, padded to FW bdry */
unsigned char dsize[4]; /* initialized data " " */
unsigned char bsize[4]; /* uninitialized data " " */
unsigned char entry[4]; /* entry pt. */
unsigned char text_start[4]; /* base of text used for this file */
unsigned char data_start[4]; /* base of data used for this file */
unsigned char o_toc[4]; /* address of TOC */
unsigned char o_snentry[2]; /* section number of entry point */
unsigned char o_sntext[2]; /* section number of .text section */
unsigned char o_sndata[2]; /* section number of .data section */
unsigned char o_sntoc[2]; /* section number of TOC */
unsigned char o_snloader[2]; /* section number of .loader section */
unsigned char o_snbss[2]; /* section number of .bss section */
unsigned char o_algntext[2]; /* .text alignment */
unsigned char o_algndata[2]; /* .data alignment */
unsigned char o_modtype[2]; /* module type (??) */
unsigned char o_cputype[2]; /* cpu type */
unsigned char o_maxstack[4]; /* max stack size (??) */
unsigned char o_maxdata[4]; /* max data size (??) */
unsigned char o_resv2[12]; /* reserved */
unsigned char magic[2]; /* type of file */
unsigned char vstamp[2]; /* version stamp */
unsigned char tsize[4]; /* text size in bytes, padded to FW bdry */
unsigned char dsize[4]; /* initialized data " " */
unsigned char bsize[4]; /* uninitialized data " " */
unsigned char entry[4]; /* entry pt. */
unsigned char text_start[4]; /* base of text used for this file */
unsigned char data_start[4]; /* base of data used for this file */
unsigned char o_toc[4]; /* address of TOC */
unsigned char o_snentry[2]; /* section number of entry point */
unsigned char o_sntext[2]; /* section number of .text section */
unsigned char o_sndata[2]; /* section number of .data section */
unsigned char o_sntoc[2]; /* section number of TOC */
unsigned char o_snloader[2]; /* section number of .loader section */
unsigned char o_snbss[2]; /* section number of .bss section */
unsigned char o_algntext[2]; /* .text alignment */
unsigned char o_algndata[2]; /* .data alignment */
unsigned char o_modtype[2]; /* module type (??) */
unsigned char o_cputype[2]; /* cpu type */
unsigned char o_maxstack[4]; /* max stack size (??) */
unsigned char o_maxdata[4]; /* max data size (??) */
unsigned char o_resv2[12]; /* reserved */
}
AOUTHDR;
@@ -81,20 +81,20 @@ AOUTHDR;
struct external_scnhdr {
char s_name[8]; /* section name */
char s_paddr[4]; /* physical address, aliased s_nlib */
char s_vaddr[4]; /* virtual address */
char s_size[4]; /* section size */
char s_scnptr[4]; /* file ptr to raw data for section */
char s_relptr[4]; /* file ptr to relocation */
char s_lnnoptr[4]; /* file ptr to line numbers */
char s_nreloc[2]; /* number of relocation entries */
char s_nlnno[2]; /* number of line number entries*/
char s_flags[4]; /* flags */
char s_name[8]; /* section name */
char s_paddr[4]; /* physical address, aliased s_nlib */
char s_vaddr[4]; /* virtual address */
char s_size[4]; /* section size */
char s_scnptr[4]; /* file ptr to raw data for section */
char s_relptr[4]; /* file ptr to relocation */
char s_lnnoptr[4]; /* file ptr to line numbers */
char s_nreloc[2]; /* number of relocation entries */
char s_nlnno[2]; /* number of line number entries*/
char s_flags[4]; /* flags */
};
#define SCNHDR struct external_scnhdr
#define SCNHSZ 40
#define SCNHDR struct external_scnhdr
#define SCNHSZ 40
/********************** LINE NUMBERS **********************/
@@ -104,23 +104,23 @@ struct external_scnhdr {
* symbol table index of the function name.
*/
struct external_lineno {
union {
char l_symndx[4]; /* function name symbol index, iff l_lnno == 0*/
char l_paddr[4]; /* (physical) address of line number */
} l_addr;
char l_lnno[2]; /* line number */
union {
char l_symndx[4]; /* function name symbol index, iff l_lnno == 0*/
char l_paddr[4]; /* (physical) address of line number */
} l_addr;
char l_lnno[2]; /* line number */
};
#define LINENO struct external_lineno
#define LINESZ 6
#define LINENO struct external_lineno
#define LINESZ 6
/********************** SYMBOLS **********************/
#define E_SYMNMLEN 8 /* # characters in a symbol name */
#define E_FILNMLEN 14 /* # characters in a file name */
#define E_DIMNUM 4 /* # array dimensions in auxiliary entry */
#define E_SYMNMLEN 8 /* # characters in a symbol name */
#define E_FILNMLEN 14 /* # characters in a file name */
#define E_DIMNUM 4 /* # array dimensions in auxiliary entry */
struct external_syment
{
@@ -140,33 +140,33 @@ struct external_syment
#define N_BTMASK (017)
#define N_TMASK (060)
#define N_BTSHFT (4)
#define N_TSHIFT (2)
#define N_BTMASK (017)
#define N_TMASK (060)
#define N_BTSHFT (4)
#define N_TSHIFT (2)
union external_auxent {
struct {
char x_tagndx[4]; /* str, un, or enum tag indx */
union {
struct {
char x_lnno[2]; /* declaration line number */
char x_size[2]; /* str/union/array size */
} x_lnsz;
char x_fsize[4]; /* size of function */
} x_misc;
union {
struct { /* if ISFCN, tag, or .bb */
char x_lnnoptr[4]; /* ptr to fcn line # */
char x_endndx[4]; /* entry ndx past block end */
} x_fcn;
struct { /* if ISARY, up to 4 dimen. */
char x_dimen[E_DIMNUM][2];
} x_ary;
} x_fcnary;
char x_tvndx[2]; /* tv index */
} x_sym;
struct {
char x_tagndx[4]; /* str, un, or enum tag indx */
union {
struct {
char x_lnno[2]; /* declaration line number */
char x_size[2]; /* str/union/array size */
} x_lnsz;
char x_fsize[4]; /* size of function */
} x_misc;
union {
struct { /* if ISFCN, tag, or .bb */
char x_lnnoptr[4]; /* ptr to fcn line # */
char x_endndx[4]; /* entry ndx past block end */
} x_fcn;
struct { /* if ISARY, up to 4 dimen. */
char x_dimen[E_DIMNUM][2];
} x_ary;
} x_fcnary;
char x_tvndx[2]; /* tv index */
} x_sym;
struct {
union {
@@ -179,35 +179,35 @@ union external_auxent {
char x_ftype[1];
} x_file;
struct {
char x_scnlen[4]; /* section length */
char x_nreloc[2]; /* # relocation entries */
char x_nlinno[2]; /* # line numbers */
} x_scn;
struct {
char x_scnlen[4]; /* section length */
char x_nreloc[2]; /* # relocation entries */
char x_nlinno[2]; /* # line numbers */
} x_scn;
struct {
char x_tvfill[4]; /* tv fill value */
char x_tvlen[2]; /* length of .tv */
char x_tvran[2][2]; /* tv range */
} x_tv; /* info about .tv section (in auxent of symbol .tv)) */
char x_tvfill[4]; /* tv fill value */
char x_tvlen[2]; /* length of .tv */
char x_tvran[2][2]; /* tv range */
} x_tv; /* info about .tv section (in auxent of symbol .tv)) */
struct {
unsigned char x_scnlen[4];
unsigned char x_parmhash[4];
unsigned char x_snhash[2];
unsigned char x_smtyp[1];
unsigned char x_smclas[1];
unsigned char x_stab[4];
unsigned char x_snstab[2];
} x_csect;
struct {
unsigned char x_scnlen[4];
unsigned char x_parmhash[4];
unsigned char x_snhash[2];
unsigned char x_smtyp[1];
unsigned char x_smclas[1];
unsigned char x_stab[4];
unsigned char x_snstab[2];
} x_csect;
};
#define SYMENT struct external_syment
#define SYMESZ 18
#define AUXENT union external_auxent
#define AUXESZ 18
#define DBXMASK 0x80 /* for dbx storage mask */
#define SYMENT struct external_syment
#define SYMESZ 18
#define AUXENT union external_auxent
#define AUXESZ 18
#define DBXMASK 0x80 /* for dbx storage mask */
#define SYMNAME_IN_DEBUG(symptr) ((symptr)->n_sclass & DBXMASK)
@@ -255,10 +255,10 @@ struct external_ldsym
{
bfd_byte _l_name[E_SYMNMLEN];
struct
{
bfd_byte _l_zeroes[4];
bfd_byte _l_offset[4];
} _l_l;
{
bfd_byte _l_zeroes[4];
bfd_byte _l_offset[4];
} _l_l;
} _l;
bfd_byte l_value[4];
bfd_byte l_scnum[2];

View File

@@ -6,45 +6,45 @@
void byte(std::ostream& out, int byte)
{
out.put((unsigned char)byte);
out.put((unsigned char)byte);
}
void word(std::ostream& out, int word)
{
byte(out,(word >> 8) & 0xFF);
byte(out,word & 0xFF);
byte(out,(word >> 8) & 0xFF);
byte(out,word & 0xFF);
}
void ostype(std::ostream& out, ResType type)
{
longword(out, type);
longword(out, type);
}
void longword(std::ostream& out, int longword)
{
byte(out,(longword >> 24) & 0xFF);
byte(out,(longword >> 16) & 0xFF);
byte(out,(longword >> 8) & 0xFF);
byte(out,longword & 0xFF);
byte(out,(longword >> 24) & 0xFF);
byte(out,(longword >> 16) & 0xFF);
byte(out,(longword >> 8) & 0xFF);
byte(out,longword & 0xFF);
}
int byte(std::istream& in)
{
return in.get() & 0xFF;
return in.get() & 0xFF;
}
int word(std::istream& in)
{
int a = byte(in);
int b = byte(in);
return (a << 8) | b;
int a = byte(in);
int b = byte(in);
return (a << 8) | b;
}
ResType ostype(std::istream& in)
{
return longword(in);
return longword(in);
}
int longword(std::istream& in)
{
int a = byte(in);
int b = byte(in);
int c = byte(in);
int d = byte(in);
return (a << 24) | (b << 16) | (c << 8) | d;
int a = byte(in);
int b = byte(in);
int c = byte(in);
int d = byte(in);
return (a << 24) | (b << 16) | (c << 8) | d;
}

View File

@@ -18,16 +18,16 @@
find_package(Boost COMPONENTS filesystem system REQUIRED)
add_library(ResourceFiles
ResourceFork.h ResourceFork.cc
BinaryIO.h BinaryIO.cc
ResType.h ResType.cc
ResourceFile.h ResourceFile.cc
)
ResourceFork.h ResourceFork.cc
BinaryIO.h BinaryIO.cc
ResType.h ResType.cc
ResourceFile.h ResourceFile.cc
)
target_link_libraries(ResourceFiles ${Boost_LIBRARIES} ${CMAKE_INSTALL_PREFIX}/lib/libhfs.a)
target_include_directories(ResourceFiles PUBLIC .
PRIVATE ${CMAKE_INSTALL_PREFIX}/include
${Boost_INCLUDE_DIR})
PRIVATE ${CMAKE_INSTALL_PREFIX}/include
${Boost_INCLUDE_DIR})
find_package(Boost COMPONENTS program_options REQUIRED)

View File

@@ -11,134 +11,134 @@ static po::options_description desc;
map<string,ResourceFile::Format> formats {
#ifdef __APPLE__
{"real", ResourceFile::Format::real},
{"real", ResourceFile::Format::real},
#endif
{"macbin", ResourceFile::Format::macbin},
{"basilisk", ResourceFile::Format::basilisk},
{"applesingle", ResourceFile::Format::applesingle},
{"underscore_appledouble", ResourceFile::Format::underscore_appledouble}
{"macbin", ResourceFile::Format::macbin},
{"basilisk", ResourceFile::Format::basilisk},
{"applesingle", ResourceFile::Format::applesingle},
{"underscore_appledouble", ResourceFile::Format::underscore_appledouble}
};
map<ResourceFile::Format,string> reverseFormats;
static void usage()
{
std::cerr << "Usage: " << "ResInfo [options] input-file\n";
std::cerr << desc << std::endl;
std::cerr << "Available Resource Fork formats are:\n";
for(auto p : formats)
std::cerr << " " << p.first << std::endl;
std::cerr << "Usage: " << "ResInfo [options] input-file\n";
std::cerr << desc << std::endl;
std::cerr << "Available Resource Fork formats are:\n";
for(auto p : formats)
std::cerr << " " << p.first << std::endl;
}
int main(int argc, char *argv[])
{
desc.add_options()
("help,h", "show this help message")
("type,t", "print file type")
("creator,c", "print creator code")
("all,a", "print all info")
("format,f", "print format")
("count,n", "print number of resources")
("size,s", "show data fork size")
("filename,l", "echo input file name")
("set-format,F", po::value<string>(), "resource fork format)")
;
po::options_description hidden, alldesc;
hidden.add_options()
("input", po::value<std::vector<string>>(), "input file" )
;
alldesc.add(desc).add(hidden);
desc.add_options()
("help,h", "show this help message")
("type,t", "print file type")
("creator,c", "print creator code")
("all,a", "print all info")
("format,f", "print format")
("count,n", "print number of resources")
("size,s", "show data fork size")
("filename,l", "echo input file name")
("set-format,F", po::value<string>(), "resource fork format)")
;
po::options_description hidden, alldesc;
hidden.add_options()
("input", po::value<std::vector<string>>(), "input file" )
;
alldesc.add(desc).add(hidden);
po::variables_map options;
try
{
auto parsed = po::command_line_parser(argc, argv)
.options(alldesc)
.positional(po::positional_options_description().add("input", -1))
.style(po::command_line_style::default_style)
.run();
po::variables_map options;
try
{
auto parsed = po::command_line_parser(argc, argv)
.options(alldesc)
.positional(po::positional_options_description().add("input", -1))
.style(po::command_line_style::default_style)
.run();
po::store(parsed, options);
}
catch(po::error& e)
{
std::cerr << "ERROR: " << e.what() << std::endl << std::endl;
usage();
return 1;
}
po::store(parsed, options);
}
catch(po::error& e)
{
std::cerr << "ERROR: " << e.what() << std::endl << std::endl;
usage();
return 1;
}
po::notify(options);
po::notify(options);
if(options.count("help") || !options.count("input"))
{
usage();
return 0;
}
for(auto p : formats)
reverseFormats[p.second] = p.first;
if(options.count("help") || !options.count("input"))
{
usage();
return 0;
}
for(auto p : formats)
reverseFormats[p.second] = p.first;
bool showFilename = options.count("filename");
bool showType = options.count("type") != 0;
bool showCreator = options.count("creator") != 0;
bool showFormat = options.count("format") != 0;
bool showCount = options.count("count") != 0;
bool showSize = options.count("size") != 0;
bool showFilename = options.count("filename");
bool showType = options.count("type") != 0;
bool showCreator = options.count("creator") != 0;
bool showFormat = options.count("format") != 0;
bool showCount = options.count("count") != 0;
bool showSize = options.count("size") != 0;
ResourceFile::Format format = ResourceFile::Format::autodetect;
if(options.count("all"))
showType = showCreator = showFormat = showCount = showSize = true;
if(options.count("set-format"))
{
string s = options["set-format"].as<string>();
if(formats.find(s) != formats.end())
format = formats[s];
else
{
std::cerr << "Unknown format " << s << std::endl << std::endl;
usage();
exit(1);
}
}
if(options.count("input"))
for(std::string fn : options["input"].as<std::vector<std::string>>())
{
ResourceFile rsrcFile(fn, format);
if(!rsrcFile.read())
{
std::cerr << "Can't read file.\n";
return 1;
}
std::ostringstream out;
if(showType)
out << " " << rsrcFile.type;
if(showCreator)
out << " " << rsrcFile.creator;
if(showFormat)
out << " " << reverseFormats[rsrcFile.format];
if(showCount)
out << " " << rsrcFile.resources.resources.size();
if(showSize)
out << " " << rsrcFile.data.size();
ResourceFile::Format format = ResourceFile::Format::autodetect;
if(options.count("all"))
showType = showCreator = showFormat = showCount = showSize = true;
if(options.count("set-format"))
{
string s = options["set-format"].as<string>();
if(formats.find(s) != formats.end())
format = formats[s];
else
{
std::cerr << "Unknown format " << s << std::endl << std::endl;
usage();
exit(1);
}
}
if(options.count("input"))
for(std::string fn : options["input"].as<std::vector<std::string>>())
{
ResourceFile rsrcFile(fn, format);
if(!rsrcFile.read())
{
std::cerr << "Can't read file.\n";
return 1;
}
std::ostringstream out;
if(showType)
out << " " << rsrcFile.type;
if(showCreator)
out << " " << rsrcFile.creator;
if(showFormat)
out << " " << reverseFormats[rsrcFile.format];
if(showCount)
out << " " << rsrcFile.resources.resources.size();
if(showSize)
out << " " << rsrcFile.data.size();
string str = out.str();
if(str.size())
{
if(showFilename)
std::cout << fn << ": ";
std::cout << out.str().substr(1) << std::endl;
}
else
{
if(showFilename)
std::cout << fn << std::endl;
}
}
string str = out.str();
if(str.size())
{
if(showFilename)
std::cout << fn << ": ";
std::cout << out.str().substr(1) << std::endl;
}
else
{
if(showFilename)
std::cout << fn << std::endl;
}
}
return 0;
}

View File

@@ -4,55 +4,55 @@
ResType::ResType(const std::string &str)
{
auto p = str.begin();
auto e = str.end();
auto p = str.begin();
auto e = str.end();
assert(str.size() == 4);
assert(str.size() == 4);
x = 0;
while(p != e)
{
x <<= 8;
x |= (*p) & 0xFF;
++p;
}
x = 0;
while(p != e)
{
x <<= 8;
x |= (*p) & 0xFF;
++p;
}
}
ResType::ResType(const char *s)
{
auto p = s;
auto e = s + 4;
auto p = s;
auto e = s + 4;
assert(s[0] && s[1] && s[2] && s[3] && !s[4]);
assert(s[0] && s[1] && s[2] && s[3] && !s[4]);
x = 0;
while(p != e)
{
x <<= 8;
x |= (*p) & 0xFF;
++p;
}
x = 0;
while(p != e)
{
x <<= 8;
x |= (*p) & 0xFF;
++p;
}
}
ResType::operator std::string()
{
char c1 = static_cast<char>(x >> 24);
char c2 = static_cast<char>(x >> 16);
char c3 = static_cast<char>(x >> 8);
char c4 = static_cast<char>(x);
char c1 = static_cast<char>(x >> 24);
char c2 = static_cast<char>(x >> 16);
char c3 = static_cast<char>(x >> 8);
char c4 = static_cast<char>(x);
return std::string{ c1, c2, c3, c4 };
return std::string{ c1, c2, c3, c4 };
}
std::ostream &operator<<(std::ostream &out, ResType t)
{
char c1 = static_cast<char>((int)t >> 24);
char c2 = static_cast<char>((int)t >> 16);
char c3 = static_cast<char>((int)t >> 8);
char c4 = static_cast<char>((int)t);
char c1 = static_cast<char>((int)t >> 24);
char c2 = static_cast<char>((int)t >> 16);
char c3 = static_cast<char>((int)t >> 8);
char c4 = static_cast<char>((int)t);
out << "'" << c1 << c2 << c3 << c4 << "'";
return out;
out << "'" << c1 << c2 << c3 << c4 << "'";
return out;
}

View File

@@ -6,30 +6,30 @@
class ResType
{
int x;
int x;
public:
ResType() : x(0) {}
ResType(int x) : x(x) {}
ResType(const std::string& s);
ResType(const char* s);
ResType() : x(0) {}
ResType(int x) : x(x) {}
ResType(const std::string& s);
ResType(const char* s);
operator int() const { return x; }
bool operator<(ResType y) const { return x < y.x; }
operator int() const { return x; }
bool operator<(ResType y) const { return x < y.x; }
operator std::string();
operator std::string();
};
std::ostream& operator<<(std::ostream& out, ResType t);
struct ResRef : public std::pair<ResType, short>
{
ResRef() : std::pair<ResType, short>(ResType(), 0) {}
ResRef(ResType t, int id) : std::pair<ResType, short>(t,id) {}
ResRef() : std::pair<ResType, short>(ResType(), 0) {}
ResRef(ResType t, int id) : std::pair<ResType, short>(t,id) {}
ResType& type() { return first; }
ResType type() const { return first; }
short& id() { return second; }
short id() const { return second; }
ResType& type() { return first; }
ResType type() const { return first; }
short& id() { return second; }
short id() const { return second; }
};
#endif // RESTYPE_H

File diff suppressed because it is too large Load Diff

View File

@@ -11,44 +11,44 @@
class ResourceFile
{
public:
enum class Format
{
autodetect,
enum class Format
{
autodetect,
#ifdef __APPLE__
real,
real,
#endif
macbin,
diskimage,
basilisk,
applesingle,
underscore_appledouble,
percent_appledouble
};
macbin,
diskimage,
basilisk,
applesingle,
underscore_appledouble,
percent_appledouble
};
ResourceFile();
ResourceFile(std::string path, Format f = Format::autodetect);
~ResourceFile();
ResourceFile();
ResourceFile(std::string path, Format f = Format::autodetect);
~ResourceFile();
bool assign(std::string path, Format f = Format::autodetect);
bool assign(std::string path, Format f = Format::autodetect);
bool read(std::istream& in, Format f);
bool write(std::ostream& in, Format f);
bool read(std::istream& in, Format f);
bool write(std::ostream& in, Format f);
bool read();
bool write();
bool read();
bool write();
static bool hasPlainDataFork(Format f);
bool hasPlainDataFork();
static bool hasPlainDataFork(Format f);
bool hasPlainDataFork();
static bool isSingleFork(Format f);
static bool isSingleFork(Format f);
std::string pathstring;
std::string filename;
Format format;
ResType type;
ResType creator;
Resources resources;
std::string data;
std::string pathstring;
std::string filename;
Format format;
ResType type;
ResType creator;
Resources resources;
std::string data;
};
#endif // RESOURCEFILE_H

View File

@@ -7,156 +7,156 @@
void Resources::addResources(const Resources& res)
{
for(auto& rr : res.resources)
addResource(rr.second);
for(auto& rr : res.resources)
addResource(rr.second);
}
void Resources::writeFork(std::ostream& out) const
{
std::streampos start = out.tellp();
longword(out,0x100);
longword(out,0);
longword(out,0);
longword(out,0);
for(int i = 0; i < 0x100 - 16; i++)
byte(out, 0);
std::streampos start = out.tellp();
longword(out,0x100);
longword(out,0);
longword(out,0);
longword(out,0);
for(int i = 0; i < 0x100 - 16; i++)
byte(out, 0);
std::map< ResType, std::map<int, int> > resourceInfos;
std::streampos datastart = out.tellp();
for(auto& rr : resources)
{
const Resource& r = rr.second;
const std::string& data = r.getData();
unsigned offset = out.tellp() - datastart;
offset = (r.getAttr() << 24) | (offset & 0xFFFFFF);
resourceInfos[ r.getType() ][ r.getID() ] = (int)offset;
longword(out, data.size());
out << data;
}
std::streampos dataend = out.tellp();
std::map< ResType, std::map<int, int> > resourceInfos;
std::streampos datastart = out.tellp();
for(auto& rr : resources)
{
const Resource& r = rr.second;
const std::string& data = r.getData();
unsigned offset = out.tellp() - datastart;
offset = (r.getAttr() << 24) | (offset & 0xFFFFFF);
resourceInfos[ r.getType() ][ r.getID() ] = (int)offset;
longword(out, data.size());
out << data;
}
std::streampos dataend = out.tellp();
// while(out.tellp() % 0x100)
// out.put(0);
std::streampos resmap = out.tellp();
for(int i = 0; i < 16+4+2+2; i++)
byte(out, 0);
word(out,16+4+2+2+2+2); // offset to resource type list
std::streampos resnameOffset = out.tellp();
word(out,0);
std::streampos typelist = out.tellp();
word(out,resourceInfos.size() - 1);
for(std::map< ResType, std::map<int, int> >::iterator p = resourceInfos.begin();
p != resourceInfos.end(); ++p)
{
if(p->second.size())
{
ostype(out,p->first);
word(out,p->second.size()-1);
word(out,0); // replaced later
}
}
int typeIndex = 0;
int nameOffset = 0;
for(std::map< ResType, std::map<int, int> >::iterator p = resourceInfos.begin();
p != resourceInfos.end(); ++p)
{
if(p->second.size())
{
std::streampos pos = out.tellp();
out.seekp((int)typelist + 2 + 8 * typeIndex + 6);
word(out, pos - typelist);
out.seekp(pos);
typeIndex++;
std::streampos resmap = out.tellp();
for(int i = 0; i < 16+4+2+2; i++)
byte(out, 0);
word(out,16+4+2+2+2+2); // offset to resource type list
std::streampos resnameOffset = out.tellp();
word(out,0);
std::streampos typelist = out.tellp();
word(out,resourceInfos.size() - 1);
for(std::map< ResType, std::map<int, int> >::iterator p = resourceInfos.begin();
p != resourceInfos.end(); ++p)
{
if(p->second.size())
{
ostype(out,p->first);
word(out,p->second.size()-1);
word(out,0); // replaced later
}
}
int typeIndex = 0;
int nameOffset = 0;
for(std::map< ResType, std::map<int, int> >::iterator p = resourceInfos.begin();
p != resourceInfos.end(); ++p)
{
if(p->second.size())
{
std::streampos pos = out.tellp();
out.seekp((int)typelist + 2 + 8 * typeIndex + 6);
word(out, pos - typelist);
out.seekp(pos);
typeIndex++;
for(std::map<int,int>::iterator q = p->second.begin(); q != p->second.end(); ++q)
{
std::string name = resources.find(ResRef(p->first, q->first))->second.getName();
word(out,q->first);
if(name.size() == 0)
word(out,-1);
else
{
word(out, nameOffset);
nameOffset += (name.size() > 255 ? 255 : name.size()) + 1;
}
longword(out,q->second);
longword(out,0);
}
}
}
std::streampos resnames = out.tellp();
out.seekp(resnameOffset);
word(out, resnames - resmap);
out.seekp(resnames);
for(std::map<int,int>::iterator q = p->second.begin(); q != p->second.end(); ++q)
{
std::string name = resources.find(ResRef(p->first, q->first))->second.getName();
word(out,q->first);
if(name.size() == 0)
word(out,-1);
else
{
word(out, nameOffset);
nameOffset += (name.size() > 255 ? 255 : name.size()) + 1;
}
longword(out,q->second);
longword(out,0);
}
}
}
std::streampos resnames = out.tellp();
out.seekp(resnameOffset);
word(out, resnames - resmap);
out.seekp(resnames);
for(std::map< ResType, std::map<int, int> >::iterator p = resourceInfos.begin();
p != resourceInfos.end(); ++p)
{
for(std::map<int,int>::iterator q = p->second.begin(); q != p->second.end(); ++q)
{
std::string name = resources.find(ResRef(p->first, q->first))->second.getName();
if(name.size() > 0)
{
int sz = name.size() > 255 ? 255 : name.size();
byte(out, sz);
for(int i = 0; i < sz; i++)
byte(out, name[i]);
}
}
}
for(std::map< ResType, std::map<int, int> >::iterator p = resourceInfos.begin();
p != resourceInfos.end(); ++p)
{
for(std::map<int,int>::iterator q = p->second.begin(); q != p->second.end(); ++q)
{
std::string name = resources.find(ResRef(p->first, q->first))->second.getName();
if(name.size() > 0)
{
int sz = name.size() > 255 ? 255 : name.size();
byte(out, sz);
for(int i = 0; i < sz; i++)
byte(out, name[i]);
}
}
}
std::streampos end = out.tellp();
out.seekp(start + std::streampos(4));
longword(out, resmap - start);
longword(out, dataend - start - std::streampos(0x100));
longword(out, end - resmap);
out.seekp(end);
std::streampos end = out.tellp();
out.seekp(start + std::streampos(4));
longword(out, resmap - start);
longword(out, dataend - start - std::streampos(0x100));
longword(out, end - resmap);
out.seekp(end);
}
Resources::Resources(std::istream &in)
{
std::streampos start = in.tellg();
int resdataOffset = longword(in);
int resmapOffset = longword(in);
std::streampos start = in.tellg();
int resdataOffset = longword(in);
int resmapOffset = longword(in);
in.seekg(start + std::streampos(resmapOffset + 16 + 4 + 2 + 2));
int typeListOffset = word(in);
int nameListOffset = word(in);
int nTypes = (word(in) + 1) & 0xFFFF;
in.seekg(start + std::streampos(resmapOffset + 16 + 4 + 2 + 2));
int typeListOffset = word(in);
int nameListOffset = word(in);
int nTypes = (word(in) + 1) & 0xFFFF;
for(int i = 0; i < nTypes; i++)
{
in.seekg(start + std::streampos(resmapOffset + typeListOffset + 2 + i * 8));
std::string type = ostype(in);
int nRes = (word(in) + 1) & 0xFFFF;
int refListOffset = word(in);
for(int i = 0; i < nTypes; i++)
{
in.seekg(start + std::streampos(resmapOffset + typeListOffset + 2 + i * 8));
std::string type = ostype(in);
int nRes = (word(in) + 1) & 0xFFFF;
int refListOffset = word(in);
for(int j = 0; j < nRes; j++)
{
in.seekg(start + std::streampos(resmapOffset + typeListOffset + refListOffset + j * 12));
int id = (short) word(in);
int nameOffset = word(in);
int attr = byte(in);
int off1 = byte(in);
int off2 = byte(in);
int off3 = byte(in);
int offset = (off1 << 16) | (off2 << 8) | off3;
std::string name;
if(nameOffset != 0xFFFF)
{
in.seekg(start + std::streampos(resmapOffset + nameListOffset + nameOffset));
int nameLen = byte(in);
char buf[256];
in.read(buf, nameLen);
name = std::string(buf, nameLen);
}
for(int j = 0; j < nRes; j++)
{
in.seekg(start + std::streampos(resmapOffset + typeListOffset + refListOffset + j * 12));
int id = (short) word(in);
int nameOffset = word(in);
int attr = byte(in);
int off1 = byte(in);
int off2 = byte(in);
int off3 = byte(in);
int offset = (off1 << 16) | (off2 << 8) | off3;
std::string name;
if(nameOffset != 0xFFFF)
{
in.seekg(start + std::streampos(resmapOffset + nameListOffset + nameOffset));
int nameLen = byte(in);
char buf[256];
in.read(buf, nameLen);
name = std::string(buf, nameLen);
}
in.seekg(start + std::streampos(resdataOffset + offset));
int size = longword(in);
std::vector<char> tmp(size);
in.read(tmp.data(), size);
std::string data(tmp.data(), size);
in.seekg(start + std::streampos(resdataOffset + offset));
int size = longword(in);
std::vector<char> tmp(size);
in.read(tmp.data(), size);
std::string data(tmp.data(), size);
addResource(Resource(type, id, data, name, attr));
}
}
addResource(Resource(type, id, data, name, attr));
}
}
}

View File

@@ -7,43 +7,43 @@
class Resource
{
ResType type;
short id;
std::string name;
std::string data;
int attr;
ResType type;
short id;
std::string name;
std::string data;
int attr;
public:
Resource() {}
Resource(ResType type, int id, std::string data, std::string name = "", int attr = 0)
: type(type), id(id), name(name), data(data), attr(attr) {}
Resource() {}
Resource(ResType type, int id, std::string data, std::string name = "", int attr = 0)
: type(type), id(id), name(name), data(data), attr(attr) {}
const std::string& getData() const { return data; }
inline ResType getType() const { return type; }
inline int getID() const { return id; }
inline ResRef getTypeAndID() const { return ResRef(type, id); }
std::string getName() const { return name; }
int getAttr() const { return attr; }
const std::string& getData() const { return data; }
inline ResType getType() const { return type; }
inline int getID() const { return id; }
inline ResRef getTypeAndID() const { return ResRef(type, id); }
std::string getName() const { return name; }
int getAttr() const { return attr; }
};
class Fork
{
public:
virtual void writeFork(std::ostream& out) const { }
virtual ~Fork() {}
virtual void writeFork(std::ostream& out) const { }
virtual ~Fork() {}
};
class Resources : public Fork
{
public:
std::map<ResRef, Resource> resources;
std::map<ResRef, Resource> resources;
Resources() {}
Resources(std::istream& in);
void writeFork(std::ostream& out) const;
void addResource(Resource res) { resources[res.getTypeAndID()] = res; }
void addResources(const Resources& res);
Resources() {}
Resources(std::istream& in);
void writeFork(std::ostream& out) const;
void addResource(Resource res) { resources[res.getTypeAndID()] = res; }
void addResources(const Resources& res);
unsigned countResources() const { return resources.size(); }
unsigned countResources() const { return resources.size(); }
};
#endif // RESOURCEFORK_H

View File

@@ -18,9 +18,9 @@
find_package(Boost COMPONENTS wave filesystem system thread regex program_options)
# Look for bison.
# We need Version 3, and Mac OS X still comes with an outdated version (2.3).
# So we just add the path where the homebrew package manager installs its
# "keg-only" version. Shouldn't hurt on Linux.
# We need Version 3, and Mac OS X still comes with an outdated version (2.3).
# So we just add the path where the homebrew package manager installs its
# "keg-only" version. Shouldn't hurt on Linux.
set(CMAKE_PROGRAM_PATH ${CMAKE_PROGRAM_PATH} "/usr/local/opt/bison/bin")
find_package(BISON 3.0.2)
@@ -30,8 +30,8 @@ if(Boost_FOUND AND BISON_FOUND)
include_directories(. ${CMAKE_CURRENT_BINARY_DIR})
set(BISON_OUTPUTS ${CMAKE_CURRENT_BINARY_DIR}/RezParser.generated.cc ${CMAKE_CURRENT_BINARY_DIR}/RezParser.generated.hh
${CMAKE_CURRENT_BINARY_DIR}/location.hh ${CMAKE_CURRENT_BINARY_DIR}/position.hh
${CMAKE_CURRENT_BINARY_DIR}/stack.hh)
${CMAKE_CURRENT_BINARY_DIR}/location.hh ${CMAKE_CURRENT_BINARY_DIR}/position.hh
${CMAKE_CURRENT_BINARY_DIR}/stack.hh)
add_custom_command(OUTPUT ${BISON_OUTPUTS}
COMMAND ${BISON_EXECUTABLE}
@@ -42,36 +42,36 @@ add_custom_command(OUTPUT ${BISON_OUTPUTS}
add_library(RezLib
RezParser.yy
${BISON_OUTPUTS}
RezParser.yy
${BISON_OUTPUTS}
RezLexer.h
RezLexer.cc
RezLexerWaveToken.h
RezLexerNextToken.cc
RezLexer.h
RezLexer.cc
RezLexerWaveToken.h
RezLexerNextToken.cc
RezWorld.cc
RezWorld.h
RezWorld.cc
RezWorld.h
ResourceDefinitions.cc
ResourceDefinitions.h
ResourceDefinitions.cc
ResourceDefinitions.h
Expression.cc
Expression.h
Expression.cc
Expression.h
ResourceCompiler.cc
ResourceCompiler.h
ResourceCompiler.cc
ResourceCompiler.h
ResSpec.h
ResSpec.h
Diagnostic.h Diagnostic.cc
)
Diagnostic.h Diagnostic.cc
)
target_link_libraries(RezLib ResourceFiles ${Boost_LIBRARIES})
target_include_directories(RezLib PRIVATE ${Boost_INCLUDE_DIR})
add_executable(Rez
Rez.cc
)
Rez.cc
)
target_link_libraries(Rez RezLib ResourceFiles ${Boost_LIBRARIES})
target_include_directories(Rez PRIVATE ${Boost_INCLUDE_DIR})
@@ -80,5 +80,5 @@ install(TARGETS Rez RUNTIME DESTINATION bin)
add_subdirectory(Test)
else(Boost_FOUND AND BISON_FOUND)
message(WARNING "Rez compiler will not be built; both boost and Bison 3.0.2 are required")
message(WARNING "Rez compiler will not be built; both boost and Bison 3.0.2 are required")
endif(Boost_FOUND AND BISON_FOUND)

View File

@@ -5,7 +5,7 @@ Diagnostic::Diagnostic()
}
Diagnostic::Diagnostic(Severity sev, std::string msg, yy::location loc)
: severity(sev), message(msg), location(loc)
: severity(sev), message(msg), location(loc)
{
}
@@ -13,16 +13,16 @@ Diagnostic::Diagnostic(Severity sev, std::string msg, yy::location loc)
std::ostream &operator<<(std::ostream &out, const Diagnostic &d)
{
//return out << d.location << ": " << d.message;
const yy::location& loc = d.location;
if (loc.begin.filename)
out << *loc.begin.filename << ':';
out << loc.begin.line << ':' << loc.begin.column;
out << ": ";
if(d.severity >= Diagnostic::error)
out << "error";
else
out << "warning";
out << ": " << d.message;
return out;
//return out << d.location << ": " << d.message;
const yy::location& loc = d.location;
if (loc.begin.filename)
out << *loc.begin.filename << ':';
out << loc.begin.line << ':' << loc.begin.column;
out << ": ";
if(d.severity >= Diagnostic::error)
out << "error";
else
out << "warning";
out << ": " << d.message;
return out;
}

View File

@@ -8,22 +8,22 @@
class Diagnostic
{
public:
enum Severity
{
warning,
error,
fatalError
};
enum Severity
{
warning,
error,
fatalError
};
Diagnostic();
Diagnostic(Severity sev, std::string msg, yy::location loc);
Diagnostic();
Diagnostic(Severity sev, std::string msg, yy::location loc);
private:
Severity severity;
std::string message;
yy::location location;
Severity severity;
std::string message;
yy::location location;
friend std::ostream& operator<<(std::ostream&, const Diagnostic&);
friend std::ostream& operator<<(std::ostream&, const Diagnostic&);
};
std::ostream& operator<<(std::ostream&, const Diagnostic&);

View File

@@ -7,14 +7,14 @@
int Expression::evaluateInt(ResourceCompiler *ctx)
{
error(ctx, "Expected an integer or integer expression here.");
return 0;
error(ctx, "Expected an integer or integer expression here.");
return 0;
}
std::string Expression::evaluateString(ResourceCompiler *ctx)
{
error(ctx, "Expected a string or string expression here.");
return "";
error(ctx, "Expected a string or string expression here.");
return "";
}
Expression::~Expression()
@@ -23,7 +23,7 @@ Expression::~Expression()
void Expression::error(ResourceCompiler *ctx, std::string err)
{
ctx->problem(Diagnostic(Diagnostic::Severity::error, err, location));
ctx->problem(Diagnostic(Diagnostic::Severity::error, err, location));
}
@@ -33,7 +33,7 @@ StringExpr::~StringExpr()
std::string StringExpr::evaluateString(ResourceCompiler *ctx)
{
return str;
return str;
}
@@ -43,13 +43,13 @@ IntExpr::~IntExpr()
int IntExpr::evaluateInt(ResourceCompiler *ctx)
{
return val;
return val;
}
void CompoundExpr::addItem(ExprPtr item)
{
items.push_back(item);
items.push_back(item);
}
CompoundExpr::~CompoundExpr()
@@ -63,46 +63,46 @@ BinaryExpr::~BinaryExpr()
int BinaryExpr::evaluateInt(ResourceCompiler *ctx)
{
switch(op)
{
case BinaryOp::XOR:
return a->evaluateInt(ctx) ^ b->evaluateInt(ctx);
case BinaryOp::OR:
return a->evaluateInt(ctx) | b->evaluateInt(ctx);
case BinaryOp::AND:
return a->evaluateInt(ctx) & b->evaluateInt(ctx);
case BinaryOp::SHIFTLEFT:
return a->evaluateInt(ctx) << b->evaluateInt(ctx);
case BinaryOp::SHIFTRIGHT:
return a->evaluateInt(ctx) >> b->evaluateInt(ctx);
case BinaryOp::EQUAL:
return a->evaluateInt(ctx) == b->evaluateInt(ctx);
case BinaryOp::NOTEQUAL:
return a->evaluateInt(ctx) != b->evaluateInt(ctx);
case BinaryOp::PLUS:
return a->evaluateInt(ctx) + b->evaluateInt(ctx);
case BinaryOp::MINUS:
return a->evaluateInt(ctx) - b->evaluateInt(ctx);
case BinaryOp::MULTIPLY:
return a->evaluateInt(ctx) * b->evaluateInt(ctx);
case BinaryOp::DIVIDE:
return a->evaluateInt(ctx) / b->evaluateInt(ctx);
default:
error(ctx, "Expected an integer or integer expression here.");
return 0;
}
switch(op)
{
case BinaryOp::XOR:
return a->evaluateInt(ctx) ^ b->evaluateInt(ctx);
case BinaryOp::OR:
return a->evaluateInt(ctx) | b->evaluateInt(ctx);
case BinaryOp::AND:
return a->evaluateInt(ctx) & b->evaluateInt(ctx);
case BinaryOp::SHIFTLEFT:
return a->evaluateInt(ctx) << b->evaluateInt(ctx);
case BinaryOp::SHIFTRIGHT:
return a->evaluateInt(ctx) >> b->evaluateInt(ctx);
case BinaryOp::EQUAL:
return a->evaluateInt(ctx) == b->evaluateInt(ctx);
case BinaryOp::NOTEQUAL:
return a->evaluateInt(ctx) != b->evaluateInt(ctx);
case BinaryOp::PLUS:
return a->evaluateInt(ctx) + b->evaluateInt(ctx);
case BinaryOp::MINUS:
return a->evaluateInt(ctx) - b->evaluateInt(ctx);
case BinaryOp::MULTIPLY:
return a->evaluateInt(ctx) * b->evaluateInt(ctx);
case BinaryOp::DIVIDE:
return a->evaluateInt(ctx) / b->evaluateInt(ctx);
default:
error(ctx, "Expected an integer or integer expression here.");
return 0;
}
}
std::string BinaryExpr::evaluateString(ResourceCompiler *ctx)
{
switch(op)
{
case BinaryOp::CONCAT:
return a->evaluateString(ctx) + b->evaluateString(ctx);
default:
error(ctx, "Expected a string or string expression here.");
return "";
}
switch(op)
{
case BinaryOp::CONCAT:
return a->evaluateString(ctx) + b->evaluateString(ctx);
default:
error(ctx, "Expected a string or string expression here.");
return "";
}
}
@@ -112,122 +112,122 @@ UnaryExpr::~UnaryExpr()
int UnaryExpr::evaluateInt(ResourceCompiler *ctx)
{
switch(op)
{
case UnaryOp::MINUS:
return -a->evaluateInt(ctx);
case UnaryOp::COMPLEMENT:
return ~a->evaluateInt(ctx);
default:
error(ctx, "Expected an integer or integer expression here.");
return 0;
}
switch(op)
{
case UnaryOp::MINUS:
return -a->evaluateInt(ctx);
case UnaryOp::COMPLEMENT:
return ~a->evaluateInt(ctx);
default:
error(ctx, "Expected an integer or integer expression here.");
return 0;
}
}
IdentifierExpr::IdentifierExpr(std::string id, yy::location loc)
: Expression(loc), id(id)
: Expression(loc), id(id)
{
}
void IdentifierExpr::addArgument(ExprPtr e)
{
arguments.push_back(e);
arguments.push_back(e);
}
ExprPtr IdentifierExpr::lookup(ResourceCompiler *ctx)
{
Subscripts sub;
for(auto arg : arguments)
sub.addSubscript(arg->evaluateInt(ctx));
ExprPtr val = ctx->lookupIdentifier(id, sub);
if(!val)
error(ctx, "Identifier \"" + id + "\" is not defined.");
return val;
Subscripts sub;
for(auto arg : arguments)
sub.addSubscript(arg->evaluateInt(ctx));
ExprPtr val = ctx->lookupIdentifier(id, sub);
if(!val)
error(ctx, "Identifier \"" + id + "\" is not defined.");
return val;
}
int IdentifierExpr::evaluateInt(ResourceCompiler *ctx)
{
if(ctx->isPrePass())
return 0;
if(ExprPtr e = lookup(ctx))
return e->evaluateInt(ctx);
else
return 0;
if(ctx->isPrePass())
return 0;
if(ExprPtr e = lookup(ctx))
return e->evaluateInt(ctx);
else
return 0;
}
std::string IdentifierExpr::evaluateString(ResourceCompiler *ctx)
{
if(ExprPtr e = lookup(ctx))
return e->evaluateString(ctx);
else
return "";
if(ExprPtr e = lookup(ctx))
return e->evaluateString(ctx);
else
return "";
}
CaseExpr::CaseExpr(const std::string &tag, CompoundExprPtr expr, yy::location loc)
: Expression(loc), tag(tag), expr(expr)
: Expression(loc), tag(tag), expr(expr)
{
}
int CountOfExpr::evaluateInt(ResourceCompiler *ctx)
{
assert(arg->arguments.size() == 0);
return ctx->getArrayCount(arg->id);
assert(arg->arguments.size() == 0);
return ctx->getArrayCount(arg->id);
}
int ArrayIndexExpr::evaluateInt(ResourceCompiler *ctx)
{
assert(arg->arguments.size() == 0);
return ctx->getArrayIndex(arg->id);
assert(arg->arguments.size() == 0);
return ctx->getArrayIndex(arg->id);
}
std::string ReadExpr::evaluateString(ResourceCompiler *ctx)
{
std::string filename = arg->evaluateString(ctx);
std::ifstream instream(filename);
std::string filename = arg->evaluateString(ctx);
std::ifstream instream(filename);
if(!instream)
{
ctx->problem(Diagnostic(Diagnostic::Severity::error, "could not $$read file " + filename, location));
}
return std::string(std::istreambuf_iterator<char>(instream.rdbuf()),
std::istreambuf_iterator<char>());
return std::string(std::istreambuf_iterator<char>(instream.rdbuf()),
std::istreambuf_iterator<char>());
}
int UnimplementedExpr::evaluateInt(ResourceCompiler *ctx)
{
std::cerr << msg << std::endl;
return 0;
std::cerr << msg << std::endl;
return 0;
}
std::string UnimplementedExpr::evaluateString(ResourceCompiler *ctx)
{
std::cerr << msg << std::endl;
return "";
std::cerr << msg << std::endl;
return "";
}
PeekExpr::PeekExpr(ExprPtr addr, ExprPtr offset, ExprPtr size, yy::location loc)
: Expression(loc), addr(addr), offset(offset), size(size)
: Expression(loc), addr(addr), offset(offset), size(size)
{
}
PeekExpr::PeekExpr(ExprPtr addr, int size, yy::location loc)
: Expression(loc),
addr(addr),
offset(std::make_shared<IntExpr>(0,loc)),
size(std::make_shared<IntExpr>(size,loc))
: Expression(loc),
addr(addr),
offset(std::make_shared<IntExpr>(0,loc)),
size(std::make_shared<IntExpr>(size,loc))
{
}
int PeekExpr::evaluateInt(ResourceCompiler *ctx)
{
int p = addr->evaluateInt(ctx) + offset->evaluateInt(ctx);
int s = size->evaluateInt(ctx);
int p = addr->evaluateInt(ctx) + offset->evaluateInt(ctx);
int s = size->evaluateInt(ctx);
return ctx->peek(p, s);
return ctx->peek(p, s);
}

View File

@@ -20,12 +20,12 @@ typedef std::shared_ptr<CaseExpr> CaseExprPtr;
enum class BinaryOp
{
XOR, OR, AND, SHIFTLEFT, SHIFTRIGHT, EQUAL, NOTEQUAL, PLUS, MINUS, MULTIPLY, DIVIDE, CONCAT
XOR, OR, AND, SHIFTLEFT, SHIFTRIGHT, EQUAL, NOTEQUAL, PLUS, MINUS, MULTIPLY, DIVIDE, CONCAT
};
enum class UnaryOp
{
MINUS, COMPLEMENT
MINUS, COMPLEMENT
};
class TypeError
@@ -35,138 +35,138 @@ class TypeError
class Expression
{
public:
yy::location location;
yy::location location;
Expression(yy::location loc) : location(loc) {}
Expression(yy::location loc) : location(loc) {}
virtual int evaluateInt(ResourceCompiler *ctx);
virtual std::string evaluateString(ResourceCompiler *ctx);
virtual ~Expression();
virtual int evaluateInt(ResourceCompiler *ctx);
virtual std::string evaluateString(ResourceCompiler *ctx);
virtual ~Expression();
void error(ResourceCompiler *ctx, std::string err);
void error(ResourceCompiler *ctx, std::string err);
};
class StringExpr : public Expression
{
std::string str;
std::string str;
public:
StringExpr(const std::string& str, yy::location loc) : Expression(loc), str(str) {}
~StringExpr();
virtual std::string evaluateString(ResourceCompiler *ctx);
StringExpr(const std::string& str, yy::location loc) : Expression(loc), str(str) {}
~StringExpr();
virtual std::string evaluateString(ResourceCompiler *ctx);
};
class IntExpr : public Expression
{
int val;
int val;
public:
IntExpr(int val, yy::location loc) : Expression(loc), val(val) {}
~IntExpr();
IntExpr(int val, yy::location loc) : Expression(loc), val(val) {}
~IntExpr();
virtual int evaluateInt(ResourceCompiler *ctx);
virtual int evaluateInt(ResourceCompiler *ctx);
};
class CompoundExpr : public Expression
{
std::vector<ExprPtr> items;
std::vector<ExprPtr> items;
public:
CompoundExpr(yy::location loc) : Expression(loc) {}
CompoundExpr(yy::location loc) : Expression(loc) {}
void addItem(ExprPtr item);
ExprPtr getItem(int i) const { return items[i]; }
int size() const { return items.size(); }
void addItem(ExprPtr item);
ExprPtr getItem(int i) const { return items[i]; }
int size() const { return items.size(); }
~CompoundExpr();
~CompoundExpr();
};
class CaseExpr : public Expression
{
std::string tag;
CompoundExprPtr expr;
friend class SwitchField;
std::string tag;
CompoundExprPtr expr;
friend class SwitchField;
public:
CaseExpr(const std::string& tag, CompoundExprPtr expr, yy::location loc);
CaseExpr(const std::string& tag, CompoundExprPtr expr, yy::location loc);
};
class BinaryExpr : public Expression
{
BinaryOp op;
ExprPtr a, b;
BinaryOp op;
ExprPtr a, b;
public:
BinaryExpr(BinaryOp op, ExprPtr a, ExprPtr b, yy::location loc)
: Expression(loc), op(op), a(a), b(b) {}
~BinaryExpr();
BinaryExpr(BinaryOp op, ExprPtr a, ExprPtr b, yy::location loc)
: Expression(loc), op(op), a(a), b(b) {}
~BinaryExpr();
virtual int evaluateInt(ResourceCompiler *ctx);
virtual std::string evaluateString(ResourceCompiler *ctx);
virtual int evaluateInt(ResourceCompiler *ctx);
virtual std::string evaluateString(ResourceCompiler *ctx);
};
class UnaryExpr : public Expression
{
UnaryOp op;
ExprPtr a;
UnaryOp op;
ExprPtr a;
public:
UnaryExpr(UnaryOp op, ExprPtr a, yy::location loc)
: Expression(loc), op(op), a(a) {}
~UnaryExpr();
UnaryExpr(UnaryOp op, ExprPtr a, yy::location loc)
: Expression(loc), op(op), a(a) {}
~UnaryExpr();
virtual int evaluateInt(ResourceCompiler *ctx);
virtual int evaluateInt(ResourceCompiler *ctx);
};
class IdentifierExpr : public Expression
{
public:
std::string id;
std::vector<ExprPtr> arguments;
IdentifierExpr(std::string id, yy::location loc);
std::string id;
std::vector<ExprPtr> arguments;
IdentifierExpr(std::string id, yy::location loc);
void addArgument(ExprPtr e);
ExprPtr lookup(ResourceCompiler *ctx);
virtual int evaluateInt(ResourceCompiler *ctx);
virtual std::string evaluateString(ResourceCompiler *ctx);
void addArgument(ExprPtr e);
ExprPtr lookup(ResourceCompiler *ctx);
virtual int evaluateInt(ResourceCompiler *ctx);
virtual std::string evaluateString(ResourceCompiler *ctx);
};
class CountOfExpr : public Expression
{
IdentifierExprPtr arg;
IdentifierExprPtr arg;
public:
CountOfExpr(IdentifierExprPtr arg, yy::location loc) : Expression(loc), arg(arg) {}
virtual int evaluateInt(ResourceCompiler *ctx);
CountOfExpr(IdentifierExprPtr arg, yy::location loc) : Expression(loc), arg(arg) {}
virtual int evaluateInt(ResourceCompiler *ctx);
};
class ArrayIndexExpr : public Expression
{
IdentifierExprPtr arg;
IdentifierExprPtr arg;
public:
ArrayIndexExpr(IdentifierExprPtr arg, yy::location loc) : Expression(loc), arg(arg) {}
virtual int evaluateInt(ResourceCompiler *ctx);
ArrayIndexExpr(IdentifierExprPtr arg, yy::location loc) : Expression(loc), arg(arg) {}
virtual int evaluateInt(ResourceCompiler *ctx);
};
class ReadExpr : public Expression
{
ExprPtr arg;
ExprPtr arg;
public:
ReadExpr(ExprPtr arg, yy::location loc) : Expression(loc), arg(arg) {}
virtual std::string evaluateString(ResourceCompiler *ctx);
ReadExpr(ExprPtr arg, yy::location loc) : Expression(loc), arg(arg) {}
virtual std::string evaluateString(ResourceCompiler *ctx);
};
class UnimplementedExpr : public Expression
{
std::string msg;
std::string msg;
public:
UnimplementedExpr(std::string msg, yy::location loc) : Expression(loc), msg(msg) {}
virtual int evaluateInt(ResourceCompiler *ctx);
virtual std::string evaluateString(ResourceCompiler *ctx);
UnimplementedExpr(std::string msg, yy::location loc) : Expression(loc), msg(msg) {}
virtual int evaluateInt(ResourceCompiler *ctx);
virtual std::string evaluateString(ResourceCompiler *ctx);
};
class PeekExpr : public Expression
{
ExprPtr addr;
ExprPtr offset;
ExprPtr size;
ExprPtr addr;
ExprPtr offset;
ExprPtr size;
public:
PeekExpr(ExprPtr addr, ExprPtr offset, ExprPtr size, yy::location loc);
PeekExpr(ExprPtr addr, int size, yy::location loc);
virtual int evaluateInt(ResourceCompiler *ctx);
PeekExpr(ExprPtr addr, ExprPtr offset, ExprPtr size, yy::location loc);
PeekExpr(ExprPtr addr, int size, yy::location loc);
virtual int evaluateInt(ResourceCompiler *ctx);
};
#endif // EXPRESSION_H

View File

@@ -6,19 +6,19 @@
class ResSpec : public ResRef
{
int attr_;
std::string name_;
int attr_;
std::string name_;
public:
ResSpec() : attr_(0) {}
ResSpec(ResType type, int id, int attr = 0, std::string name = "")
: ResRef(type, id), attr_(attr), name_(name)
{}
ResSpec() : attr_(0) {}
ResSpec(ResType type, int id, int attr = 0, std::string name = "")
: ResRef(type, id), attr_(attr), name_(name)
{}
int& attr() { return attr_; }
int attr() const { return attr_; }
std::string& name() { return name_; }
const std::string& name() const { return name_; }
int& attr() { return attr_; }
int attr() const { return attr_; }
std::string& name() { return name_; }
const std::string& name() const { return name_; }
};
#endif // REZSPEC_H

View File

@@ -5,164 +5,164 @@
#include "Diagnostic.h"
ResourceCompiler::ResourceCompiler(
RezWorld& world, TypeDefinitionPtr type, CompoundExprPtr body, bool verboseFlag)
: world(world),
typeDefinition(type),
body(body),
currentField(nullptr)
RezWorld& world, TypeDefinitionPtr type, CompoundExprPtr body, bool verboseFlag)
: world(world),
typeDefinition(type),
body(body),
currentField(nullptr)
{
this->verboseFlag = verboseFlag;
this->verboseFlag = verboseFlag;
}
BinaryOutput::BinaryOutput()
: verboseFlag(false)
: verboseFlag(false)
{
reset(true);
reset(true);
}
void BinaryOutput::reset(bool prePass)
{
currentOffset = 0;
if(!prePass)
prePassData = std::move(data);
data.clear();
this->prePass = prePass;
currentOffset = 0;
if(!prePass)
prePassData = std::move(data);
data.clear();
this->prePass = prePass;
}
std::string BinaryOutput::resourceData()
{
return std::string(data.begin(), data.end());
return std::string(data.begin(), data.end());
}
void BinaryOutput::write(int nBits, int value)
{
if(verboseFlag)
std::cout << "[" << nBits << " bits] = " << std::hex << value << std::dec << std::endl;
if(verboseFlag)
std::cout << "[" << nBits << " bits] = " << std::hex << value << std::dec << std::endl;
unsigned mask = 1 << (nBits-1);
unsigned mask = 1 << (nBits-1);
for(int i = 0; i < nBits; i++)
{
bool bit = (value & mask) != 0;
for(int i = 0; i < nBits; i++)
{
bool bit = (value & mask) != 0;
if(currentOffset % 8 == 0)
data.push_back(bit ? 0x80 : 0);
else if(bit)
data.back() |= (0x80 >> (currentOffset % 8));
++currentOffset;
if(currentOffset % 8 == 0)
data.push_back(bit ? 0x80 : 0);
else if(bit)
data.back() |= (0x80 >> (currentOffset % 8));
++currentOffset;
mask >>= 1;
}
mask >>= 1;
}
//currentOffset += nBits;
//currentOffset += nBits;
}
int BinaryOutput::peek(int bitPos, int size)
{
unsigned bytePos = bitPos / 8;
unsigned endBytePos = (bitPos + size - 1) / 8 + 1;
unsigned bytePos = bitPos / 8;
unsigned endBytePos = (bitPos + size - 1) / 8 + 1;
unsigned bitPosInByte = bitPos % 8;
unsigned outPos = 32 - size;
unsigned bitPosInByte = bitPos % 8;
unsigned outPos = 32 - size;
unsigned val = 0;
unsigned val = 0;
for(unsigned i = bytePos; i != endBytePos; ++i)
{
unsigned byte;
if(i < data.size())
byte = data[i];
else if(i < prePassData.size())
byte = prePassData[i];
else
byte = 0;
for(unsigned i = bytePos; i != endBytePos; ++i)
{
unsigned byte;
if(i < data.size())
byte = data[i];
else if(i < prePassData.size())
byte = prePassData[i];
else
byte = 0;
unsigned read = byte << (bitPosInByte + 24);
val |= (read >> outPos);
unsigned read = byte << (bitPosInByte + 24);
val |= (read >> outPos);
outPos += 8 - bitPosInByte;
outPos += 8 - bitPosInByte;
bitPosInByte = 0;
}
bitPosInByte = 0;
}
return val;
return val;
}
ExprPtr ResourceCompiler::lookupIdentifier(std::string name, const Subscripts &sub)
{
if(currentField)
{
if(ExprPtr val = currentField->lookupNamedValue(name))
{
return val;
}
}
if(currentField)
{
if(ExprPtr val = currentField->lookupNamedValue(name))
{
return val;
}
}
auto p = labelValues.find(std::make_pair(name, sub));
if(p != labelValues.end())
return p->second;
auto p = labelValues.find(std::make_pair(name, sub));
if(p != labelValues.end())
return p->second;
//std::cerr << "ID lookup failed: " << name << std::endl;
//std::cerr << "ID lookup failed: " << name << std::endl;
return nullptr;
return nullptr;
}
void ResourceCompiler::defineLabel(const std::string &name)
{
labelValues[std::make_pair(name,currentSubscripts)] = std::make_shared<IntExpr>(currentOffset, yy::location());
labelValues[std::make_pair(name,currentSubscripts)] = std::make_shared<IntExpr>(currentOffset, yy::location());
}
void ResourceCompiler::compile()
{
if(verboseFlag) std::cout << "(first pass)\n";
reset(true);
typeDefinition->compile(body, this, true);
if(verboseFlag) std::cout << "(second pass)\n";
if(verboseFlag) std::cout << "(first pass)\n";
reset(true);
typeDefinition->compile(body, this, true);
if(verboseFlag) std::cout << "(second pass)\n";
reset(false);
typeDefinition->compile(body, this, false);
if(verboseFlag) std::cout << "(done)\n";
reset(false);
typeDefinition->compile(body, this, false);
if(verboseFlag) std::cout << "(done)\n";
}
int ResourceCompiler::getArrayCount(const std::string &name)
{
Subscripts sub = currentSubscripts;
for(;;)
{
auto p = arrayCounts.find(std::make_pair(name, sub));
if(p != arrayCounts.end())
return p->second;
Subscripts sub = currentSubscripts;
for(;;)
{
auto p = arrayCounts.find(std::make_pair(name, sub));
if(p != arrayCounts.end())
return p->second;
if(sub.empty())
return 0; /* ### */
sub.popSubscript();
}
if(sub.empty())
return 0; /* ### */
sub.popSubscript();
}
}
int ResourceCompiler::getArrayIndex(const std::string &arrayName)
{
return curArrayIndices[arrayName];
return curArrayIndices[arrayName];
}
void ResourceCompiler::problem(Diagnostic d)
{
if(!prePass)
world.problem(d);
if(!prePass)
world.problem(d);
}
void ResourceCompiler::beginArrayScope(std::string &arrayName, int index)
{
if(arrayName != "")
{
curArrayIndices[arrayName] = index;
int& count = arrayCounts[std::make_pair(arrayName, currentSubscripts)];
if(count < index)
count = index;
arrayCounts[std::make_pair(arrayName, Subscripts())] = count;
//std::cout << "count for " << arrayName << " is " << count << std::endl;
}
currentSubscripts.addSubscript(index);
if(arrayName != "")
{
curArrayIndices[arrayName] = index;
int& count = arrayCounts[std::make_pair(arrayName, currentSubscripts)];
if(count < index)
count = index;
arrayCounts[std::make_pair(arrayName, Subscripts())] = count;
//std::cout << "count for " << arrayName << " is " << count << std::endl;
}
currentSubscripts.addSubscript(index);
}
Subscripts::Subscripts()
@@ -175,26 +175,26 @@ Subscripts::~Subscripts()
void Subscripts::addSubscript(int x)
{
subscripts.push_back(x);
subscripts.push_back(x);
}
void Subscripts::popSubscript()
{
subscripts.pop_back();
subscripts.pop_back();
}
bool Subscripts::operator<(const Subscripts &other) const
{
if(subscripts.size() < other.subscripts.size())
return true;
if(other.subscripts.size() < subscripts.size())
return false;
for(int i = 0, n = subscripts.size(); i < n; i++)
{
if(subscripts[i] < other.subscripts[i])
return true;
else if(subscripts[i] > other.subscripts[i])
return false;
}
return false;
if(subscripts.size() < other.subscripts.size())
return true;
if(other.subscripts.size() < subscripts.size())
return false;
for(int i = 0, n = subscripts.size(); i < n; i++)
{
if(subscripts[i] < other.subscripts[i])
return true;
else if(subscripts[i] > other.subscripts[i])
return false;
}
return false;
}

View File

@@ -10,83 +10,83 @@ class Diagnostic;
class Subscripts
{
std::vector<int> subscripts;
std::vector<int> subscripts;
public:
Subscripts();
~Subscripts();
Subscripts();
~Subscripts();
void addSubscript(int x);
void popSubscript();
bool operator<(const Subscripts& other) const;
bool empty() const { return subscripts.empty(); }
void addSubscript(int x);
void popSubscript();
bool operator<(const Subscripts& other) const;
bool empty() const { return subscripts.empty(); }
};
class BinaryOutput
{
protected:
int currentOffset;
std::vector<unsigned char> data;
std::vector<unsigned char> prePassData;
bool verboseFlag;
bool prePass;
int currentOffset;
std::vector<unsigned char> data;
std::vector<unsigned char> prePassData;
bool verboseFlag;
bool prePass;
public:
BinaryOutput();
void reset(bool prePass);
BinaryOutput();
void reset(bool prePass);
std::string resourceData();
std::string resourceData();
void reserve(int nBits) { write(nBits, 0); }
void write(int nBits, int value);
int tell() { return currentOffset; }
void reserve(int nBits) { write(nBits, 0); }
void write(int nBits, int value);
int tell() { return currentOffset; }
int peek(int bitPos, int size);
int peek(int bitPos, int size);
bool isPrePass() { return prePass; }
bool isPrePass() { return prePass; }
};
class ResourceCompiler : public BinaryOutput
{
RezWorld& world;
TypeDefinitionPtr typeDefinition;
CompoundExprPtr body;
std::map<std::pair<std::string, Subscripts>, ExprPtr> labelValues;
std::map<std::pair<std::string, Subscripts>, int> arrayCounts;
std::map<std::string, int> curArrayIndices;
Field* currentField;
Subscripts currentSubscripts;
RezWorld& world;
TypeDefinitionPtr typeDefinition;
CompoundExprPtr body;
std::map<std::pair<std::string, Subscripts>, ExprPtr> labelValues;
std::map<std::pair<std::string, Subscripts>, int> arrayCounts;
std::map<std::string, int> curArrayIndices;
Field* currentField;
Subscripts currentSubscripts;
void beginArrayScope(std::string& arrayName, int index);
void beginArrayScope(std::string& arrayName, int index);
public:
ResourceCompiler(RezWorld& world, TypeDefinitionPtr type, CompoundExprPtr body, bool verboseFlag);
ResourceCompiler(RezWorld& world, TypeDefinitionPtr type, CompoundExprPtr body, bool verboseFlag);
ExprPtr lookupIdentifier(std::string name, const Subscripts& sub = Subscripts());
ExprPtr lookupIdentifier(std::string name, const Subscripts& sub = Subscripts());
void defineLabel(const std::string& name);
void compile();
void defineLabel(const std::string& name);
void compile();
int getArrayCount(const std::string& arrayName);
int getArrayIndex(const std::string& arrayName);
int getArrayCount(const std::string& arrayName);
int getArrayIndex(const std::string& arrayName);
class FieldScope
{
ResourceCompiler *compiler;
public:
FieldScope(ResourceCompiler* compiler, Field *field)
: compiler(compiler) { compiler->currentField = field; }
~FieldScope() { compiler->currentField = nullptr; }
};
class FieldScope
{
ResourceCompiler *compiler;
public:
FieldScope(ResourceCompiler* compiler, Field *field)
: compiler(compiler) { compiler->currentField = field; }
~FieldScope() { compiler->currentField = nullptr; }
};
class ArrayScope
{
ResourceCompiler *compiler;
public:
ArrayScope(ResourceCompiler* compiler, std::string& arrayName, int index)
: compiler(compiler) { compiler->beginArrayScope(arrayName, index); }
~ArrayScope() { compiler->currentSubscripts.popSubscript(); }
};
class ArrayScope
{
ResourceCompiler *compiler;
public:
ArrayScope(ResourceCompiler* compiler, std::string& arrayName, int index)
: compiler(compiler) { compiler->beginArrayScope(arrayName, index); }
~ArrayScope() { compiler->currentSubscripts.popSubscript(); }
};
void problem(Diagnostic d);
void problem(Diagnostic d);
};

View File

@@ -8,10 +8,10 @@
std::ostream &operator<<(std::ostream &out, TypeSpec ts)
{
out << ts.getType();
if(ts.hasID())
out << " (" << ts.getID() << ")";
return out;
out << ts.getType();
if(ts.hasID())
out << " (" << ts.getID() << ")";
return out;
}
@@ -22,38 +22,38 @@ FieldList::~FieldList()
void FieldList::addField(FieldPtr field, yy::location loc)
{
field->location = loc;
fields.push_back(field);
field->location = loc;
fields.push_back(field);
}
void FieldList::addLabel(std::string name, yy::location loc)
{
addField(std::make_shared<LabelField>(name), loc);
addField(std::make_shared<LabelField>(name), loc);
}
void FieldList::compile(ExprPtr expr, ResourceCompiler *compiler, bool prePass)
{
CompoundExprPtr compound = std::dynamic_pointer_cast<CompoundExpr>(expr);
assert(compound);
CompoundExprPtr compound = std::dynamic_pointer_cast<CompoundExpr>(expr);
assert(compound);
int i = 0;
for(FieldPtr f : fields)
{
if(f->needsValue())
{
if(i >= compound->size())
compiler->problem(Diagnostic(Diagnostic::error,"not enough values specified", compound->location));
else
f->compile(compound->getItem(i++), compiler, prePass);
}
else
f->compile(nullptr, compiler, prePass);
}
if(i < compound->size())
{
compiler->problem(Diagnostic(Diagnostic::error,"extra value specified",
compound->getItem(i)->location));
}
int i = 0;
for(FieldPtr f : fields)
{
if(f->needsValue())
{
if(i >= compound->size())
compiler->problem(Diagnostic(Diagnostic::error,"not enough values specified", compound->location));
else
f->compile(compound->getItem(i++), compiler, prePass);
}
else
f->compile(nullptr, compiler, prePass);
}
if(i < compound->size())
{
compiler->problem(Diagnostic(Diagnostic::error,"extra value specified",
compound->getItem(i)->location));
}
}
@@ -61,282 +61,282 @@ void FieldList::compile(ExprPtr expr, ResourceCompiler *compiler, bool prePass)
void SimpleField::addNamedValue(std::string n)
{
if(lastNamedValue)
addNamedValue(n, std::make_shared<BinaryExpr>(
BinaryOp::PLUS, lastNamedValue, std::make_shared<IntExpr>(1, yy::location()), yy::location()));
else
addNamedValue(n, std::make_shared<IntExpr>(0, yy::location()));
if(lastNamedValue)
addNamedValue(n, std::make_shared<BinaryExpr>(
BinaryOp::PLUS, lastNamedValue, std::make_shared<IntExpr>(1, yy::location()), yy::location()));
else
addNamedValue(n, std::make_shared<IntExpr>(0, yy::location()));
}
void SimpleField::addNamedValue(std::string n, ExprPtr val)
{
namedValues[n] = val;
lastNamedValue = val;
namedValues[n] = val;
lastNamedValue = val;
}
ExprPtr SimpleField::lookupNamedValue(std::string n)
{
auto p = namedValues.find(n);
if(p != namedValues.end())
return p->second;
else
return nullptr;
auto p = namedValues.find(n);
if(p != namedValues.end())
return p->second;
else
return nullptr;
}
bool SimpleField::needsValue()
{
return !value;
return !value;
}
void SimpleField::compile(ExprPtr expr, ResourceCompiler *compiler, bool prePass)
{
switch(type)
{
case Type::bitstring:
case Type::boolean:
case Type::byte:
case Type::integer:
case Type::longint:
compileInt(expr, compiler, prePass);
break;
case Type::string:
case Type::wstring:
case Type::pstring:
case Type::char_:
compileString(expr, compiler, prePass);
break;
switch(type)
{
case Type::bitstring:
case Type::boolean:
case Type::byte:
case Type::integer:
case Type::longint:
compileInt(expr, compiler, prePass);
break;
case Type::string:
case Type::wstring:
case Type::pstring:
case Type::char_:
compileString(expr, compiler, prePass);
break;
case Type::rect:
case Type::point:
compileCompound(expr, compiler, prePass);
break;
case Type::rect:
case Type::point:
compileCompound(expr, compiler, prePass);
break;
}
}
}
void SimpleField::compileString(ExprPtr expr, ResourceCompiler *compiler, bool prePass)
{
std::string str;
{
ResourceCompiler::FieldScope scope(compiler, this);
str = (value ? value : expr)->evaluateString(compiler);
}
std::string str;
{
ResourceCompiler::FieldScope scope(compiler, this);
str = (value ? value : expr)->evaluateString(compiler);
}
if(arrayCount || type == Type::char_)
{
unsigned requestedSize = type == Type::char_ ? 1 : arrayCount->evaluateInt(compiler);
if(requestedSize < str.size())
str.erase(str.begin() + requestedSize, str.end());
else if(requestedSize > str.size())
str.insert(str.end(),requestedSize - str.size(), '\0');
}
if(arrayCount || type == Type::char_)
{
unsigned requestedSize = type == Type::char_ ? 1 : arrayCount->evaluateInt(compiler);
if(requestedSize < str.size())
str.erase(str.begin() + requestedSize, str.end());
else if(requestedSize > str.size())
str.insert(str.end(),requestedSize - str.size(), '\0');
}
int count = str.size();
int count = str.size();
if(type == Type::pstring)
{
if(count > 255)
{
str.erase(str.begin() + 255, str.end());
count = 255;
}
compiler->write(8, count);
}
else if(type == Type::wstring)
{
if(count > 65535)
{
str.erase(str.begin() + 65535, str.end());
count = 65535;
}
compiler->write(16, count);
}
if(type == Type::pstring)
{
if(count > 255)
{
str.erase(str.begin() + 255, str.end());
count = 255;
}
compiler->write(8, count);
}
else if(type == Type::wstring)
{
if(count > 65535)
{
str.erase(str.begin() + 65535, str.end());
count = 65535;
}
compiler->write(16, count);
}
for(char c : str)
compiler->write(8, c);
for(char c : str)
compiler->write(8, c);
}
void SimpleField::compileInt(ExprPtr expr, ResourceCompiler *compiler, bool prePass)
{
int bitSize = 0;
int bitSize = 0;
switch(type)
{
case Type::bitstring:
bitSize = arrayCount->evaluateInt(compiler);
break;
case Type::boolean:
bitSize = 1;
break;
case Type::byte:
bitSize = 8;
break;
case Type::integer:
bitSize = 16;
break;
case Type::longint:
bitSize = 32;
break;
default:
assert(false);
}
switch(type)
{
case Type::bitstring:
bitSize = arrayCount->evaluateInt(compiler);
break;
case Type::boolean:
bitSize = 1;
break;
case Type::byte:
bitSize = 8;
break;
case Type::integer:
bitSize = 16;
break;
case Type::longint:
bitSize = 32;
break;
default:
assert(false);
}
int actualValue = 0;
ResourceCompiler::FieldScope scope(compiler, this);
actualValue = (value ? value : expr)->evaluateInt(compiler);
int actualValue = 0;
ResourceCompiler::FieldScope scope(compiler, this);
actualValue = (value ? value : expr)->evaluateInt(compiler);
compiler->write(bitSize, actualValue);
compiler->write(bitSize, actualValue);
}
void SimpleField::compileCompound(ExprPtr expr, ResourceCompiler *compiler, bool prePass)
{
ExprPtr val = value ? value : expr;
if(IdentifierExprPtr id = std::dynamic_pointer_cast<IdentifierExpr>(val))
{
ResourceCompiler::FieldScope scope(compiler, this);
val = id->lookup(compiler);
}
ExprPtr val = value ? value : expr;
if(IdentifierExprPtr id = std::dynamic_pointer_cast<IdentifierExpr>(val))
{
ResourceCompiler::FieldScope scope(compiler, this);
val = id->lookup(compiler);
}
int count = 0;
switch(type)
{
case Type::rect:
count = 4;
break;
case Type::point:
count = 2;
break;
default:
assert(false);
}
int count = 0;
switch(type)
{
case Type::rect:
count = 4;
break;
case Type::point:
count = 2;
break;
default:
assert(false);
}
CompoundExprPtr compound = std::dynamic_pointer_cast<CompoundExpr>(val);
if(!compound || compound->size() != count)
{
expr->error(compiler, std::string("expected ") + (type == Type::rect ? "rect {t,l,b,r}." : "point {v,h}."));
return;
}
assert(compound);
assert(compound->size() == count);
CompoundExprPtr compound = std::dynamic_pointer_cast<CompoundExpr>(val);
if(!compound || compound->size() != count)
{
expr->error(compiler, std::string("expected ") + (type == Type::rect ? "rect {t,l,b,r}." : "point {v,h}."));
return;
}
assert(compound);
assert(compound->size() == count);
for(int i = 0; i < count; i++)
{
int x = compound->getItem(i)->evaluateInt(compiler);
compiler->write(16, x);
}
for(int i = 0; i < count; i++)
{
int x = compound->getItem(i)->evaluateInt(compiler);
compiler->write(16, x);
}
}
ArrayField::ArrayField(std::string name, ExprPtr count)
: name(name), arrayCount(count)
: name(name), arrayCount(count)
{
}
void ArrayField::compile(ExprPtr expr, ResourceCompiler *compiler, bool prePass)
{
CompoundExprPtr compound = std::dynamic_pointer_cast<CompoundExpr>(expr);
assert(compound);
CompoundExprPtr compound = std::dynamic_pointer_cast<CompoundExpr>(expr);
assert(compound);
int i = 0;
int n = compound->size();
int i = 0;
int n = compound->size();
int iterations = 0;
while(i < n)
{
++iterations;
ResourceCompiler::ArrayScope scope(compiler, name, iterations);
for(FieldPtr f : fields)
{
if(f->needsValue())
{
assert(i < n);
f->compile(compound->getItem(i++), compiler, prePass);
}
else
f->compile(nullptr, compiler, prePass);
}
}
int iterations = 0;
while(i < n)
{
++iterations;
ResourceCompiler::ArrayScope scope(compiler, name, iterations);
for(FieldPtr f : fields)
{
if(f->needsValue())
{
assert(i < n);
f->compile(compound->getItem(i++), compiler, prePass);
}
else
f->compile(nullptr, compiler, prePass);
}
}
if(!prePass && arrayCount)
{
int expected = arrayCount->evaluateInt(compiler);
assert(expected == iterations);
}
if(!prePass && arrayCount)
{
int expected = arrayCount->evaluateInt(compiler);
assert(expected == iterations);
}
}
LabelField::LabelField(std::string name)
: name(name)
: name(name)
{
}
bool LabelField::needsValue()
{
return false;
return false;
}
void LabelField::compile(ExprPtr expr, ResourceCompiler *compiler, bool prePass)
{
compiler->defineLabel(name);
compiler->defineLabel(name);
}
void SwitchField::addCase(const std::string name, FieldListPtr alternative)
{
cases[name] = alternative;
cases[name] = alternative;
}
void SwitchField::compile(ExprPtr expr, ResourceCompiler *compiler, bool prePass)
{
CaseExprPtr caseExpr = std::dynamic_pointer_cast<CaseExpr>(expr);
assert(caseExpr);
CaseExprPtr caseExpr = std::dynamic_pointer_cast<CaseExpr>(expr);
assert(caseExpr);
FieldListPtr caseDefinition = cases[caseExpr->tag];
assert(caseDefinition);
FieldListPtr caseDefinition = cases[caseExpr->tag];
assert(caseDefinition);
caseDefinition->compile(caseExpr->expr, compiler, prePass);
caseDefinition->compile(caseExpr->expr, compiler, prePass);
}
FillAlignField::FillAlignField(FillAlignField::Type type, bool isAlign, ExprPtr count)
: type(type), count(count), isAlign(isAlign)
: type(type), count(count), isAlign(isAlign)
{
}
bool FillAlignField::needsValue()
{
return false;
return false;
}
void FillAlignField::compile(ExprPtr expr, ResourceCompiler *compiler, bool prePass)
{
int bitSize;
switch(type)
{
case Type::bit: bitSize = 1; break;
case Type::nibble: bitSize = 4; break;
case Type::byte: bitSize = 8; break;
case Type::word: bitSize = 16; break;
case Type::long_: bitSize = 32; break;
}
int bitSize;
switch(type)
{
case Type::bit: bitSize = 1; break;
case Type::nibble: bitSize = 4; break;
case Type::byte: bitSize = 8; break;
case Type::word: bitSize = 16; break;
case Type::long_: bitSize = 32; break;
}
int actualCount = 1;
if(count)
actualCount = count->evaluateInt(compiler);
int actualCount = 1;
if(count)
actualCount = count->evaluateInt(compiler);
for(int i = 0; i < actualCount; i++)
{
int n;
if(isAlign)
{
int mask = bitSize - 1;
int pos = compiler->tell();
n = ((pos + mask) & ~mask) - pos;
}
else
n = bitSize;
compiler->write(n, 0);
}
for(int i = 0; i < actualCount; i++)
{
int n;
if(isAlign)
{
int mask = bitSize - 1;
int pos = compiler->tell();
n = ((pos + mask) & ~mask) - pos;
}
else
n = bitSize;
compiler->write(n, 0);
}
}

View File

@@ -12,29 +12,29 @@
class TypeSpec
{
ResType type;
int id;
ResType type;
int id;
public:
static const int noID = 65536;
static const int noID = 65536;
TypeSpec() : id(noID) {}
TypeSpec(ResType type) : type(type), id(noID) {}
TypeSpec(ResType type, int id) : type(type), id(id) {}
TypeSpec() : id(noID) {}
TypeSpec(ResType type) : type(type), id(noID) {}
TypeSpec(ResType type, int id) : type(type), id(id) {}
ResType getType() const { return type; }
int getID() const { return id; }
ResType getType() const { return type; }
int getID() const { return id; }
bool hasID() const { return id != noID; }
bool hasID() const { return id != noID; }
bool operator<(TypeSpec y) const
{
if(type < y.type)
return true;
else if(y.type < type)
return false;
else
return id < y.id;
}
bool operator<(TypeSpec y) const
{
if(type < y.type)
return true;
else if(y.type < type)
return false;
else
return id < y.id;
}
};
std::ostream& operator<<(std::ostream& out, TypeSpec ts);
@@ -45,85 +45,85 @@ class ResourceCompiler;
class Field
{
public:
yy::location location;
yy::location location;
virtual ~Field() = default;
virtual ~Field() = default;
virtual bool needsValue() { return true; }
virtual bool needsValue() { return true; }
virtual void compile(ExprPtr expr, ResourceCompiler *compiler, bool prePass) = 0;
virtual void compile(ExprPtr expr, ResourceCompiler *compiler, bool prePass) = 0;
virtual ExprPtr lookupNamedValue(std::string) { return nullptr; }
virtual ExprPtr lookupNamedValue(std::string) { return nullptr; }
};
typedef std::shared_ptr<Field> FieldPtr;
class SimpleField : public Field
{
public:
enum class Type
{
boolean, byte, integer, longint, rect, point, char_,
pstring, wstring, string, bitstring
};
enum class Type
{
boolean, byte, integer, longint, rect, point, char_,
pstring, wstring, string, bitstring
};
enum class Attrs
{
none = 0, hex = 1, key = 2, unsigned_ = 4, literal = 8, binary = 16
};
enum class Attrs
{
none = 0, hex = 1, key = 2, unsigned_ = 4, literal = 8, binary = 16
};
Type type;
Attrs attrs = Attrs::none;
ExprPtr arrayCount;
Type type;
Attrs attrs = Attrs::none;
ExprPtr arrayCount;
ExprPtr value;
std::map<std::string, ExprPtr> namedValues;
ExprPtr lastNamedValue;
ExprPtr value;
std::map<std::string, ExprPtr> namedValues;
ExprPtr lastNamedValue;
void addNamedValue(std::string n);
void addNamedValue(std::string n, ExprPtr val);
ExprPtr lookupNamedValue(std::string);
void addNamedValue(std::string n);
void addNamedValue(std::string n, ExprPtr val);
ExprPtr lookupNamedValue(std::string);
virtual bool needsValue();
virtual void compile(ExprPtr expr, ResourceCompiler *compiler, bool prePass);
virtual bool needsValue();
virtual void compile(ExprPtr expr, ResourceCompiler *compiler, bool prePass);
private:
void compileString(ExprPtr expr, ResourceCompiler *compiler, bool prePass);
void compileInt(ExprPtr expr, ResourceCompiler *compiler, bool prePass);
void compileCompound(ExprPtr expr, ResourceCompiler *compiler, bool prePass);
void compileString(ExprPtr expr, ResourceCompiler *compiler, bool prePass);
void compileInt(ExprPtr expr, ResourceCompiler *compiler, bool prePass);
void compileCompound(ExprPtr expr, ResourceCompiler *compiler, bool prePass);
};
typedef std::shared_ptr<SimpleField> SimpleFieldPtr;
class FillAlignField : public Field
{
public:
enum class Type
{
bit, nibble, byte, word, long_
};
enum class Type
{
bit, nibble, byte, word, long_
};
FillAlignField(Type type, bool isAlign, ExprPtr count = ExprPtr());
virtual bool needsValue();
virtual void compile(ExprPtr expr, ResourceCompiler *compiler, bool prePass);
FillAlignField(Type type, bool isAlign, ExprPtr count = ExprPtr());
virtual bool needsValue();
virtual void compile(ExprPtr expr, ResourceCompiler *compiler, bool prePass);
private:
Type type;
ExprPtr count;
bool isAlign;
Type type;
ExprPtr count;
bool isAlign;
};
inline SimpleField::Attrs operator|(SimpleField::Attrs a, SimpleField::Attrs b)
{
return SimpleField::Attrs( int(a) | int(b) );
return SimpleField::Attrs( int(a) | int(b) );
}
class LabelField : public Field
{
std::string name;
std::string name;
public:
LabelField(std::string name);
LabelField(std::string name);
virtual bool needsValue();
virtual void compile(ExprPtr expr, ResourceCompiler *compiler, bool prePass);
virtual bool needsValue();
virtual void compile(ExprPtr expr, ResourceCompiler *compiler, bool prePass);
};
typedef std::shared_ptr<LabelField> LabelFieldPtr;
@@ -131,35 +131,35 @@ typedef std::shared_ptr<LabelField> LabelFieldPtr;
class FieldList : public Field
{
protected:
std::vector<FieldPtr> fields;
std::vector<FieldPtr> fields;
public:
virtual ~FieldList();
void addField(FieldPtr field, yy::location loc);
void addLabel(std::string name, yy::location loc);
virtual ~FieldList();
void addField(FieldPtr field, yy::location loc);
void addLabel(std::string name, yy::location loc);
virtual void compile(ExprPtr expr, ResourceCompiler *compiler, bool prePass);
virtual void compile(ExprPtr expr, ResourceCompiler *compiler, bool prePass);
};
typedef std::shared_ptr<FieldList> FieldListPtr;
class ArrayField : public FieldList
{
std::string name;
ExprPtr arrayCount;
std::string name;
ExprPtr arrayCount;
public:
ArrayField(std::string name /* or empty */, ExprPtr count /* may be null*/);
ArrayField(std::string name /* or empty */, ExprPtr count /* may be null*/);
virtual void compile(ExprPtr expr, ResourceCompiler *compiler, bool prePass);
virtual void compile(ExprPtr expr, ResourceCompiler *compiler, bool prePass);
};
typedef std::shared_ptr<ArrayField> ArrayFieldPtr;
class SwitchField : public Field
{
std::map<std::string, FieldListPtr> cases;
std::map<std::string, FieldListPtr> cases;
public:
void addCase(const std::string name, FieldListPtr alternative);
void addCase(const std::string name, FieldListPtr alternative);
virtual void compile(ExprPtr expr, ResourceCompiler *compiler, bool prePass);
virtual void compile(ExprPtr expr, ResourceCompiler *compiler, bool prePass);
};
typedef std::shared_ptr<SwitchField> SwitchFieldPtr;

View File

@@ -19,157 +19,157 @@ static po::options_description desc;
static void usage()
{
std::cerr << "Usage: " << "Rez [options] input-file\n";
std::cerr << desc << std::endl;
std::cerr << "Usage: " << "Rez [options] input-file\n";
std::cerr << desc << std::endl;
}
static void CopyBinaryResources(RezWorld& world, const std::string& fn)
{
ResourceFile copyRsrc(fn);
if(!copyRsrc.read())
{
world.problem(Diagnostic(Diagnostic::error, "Could not read binary resource file " + fn, yy::location()));
}
else if(world.verboseFlag)
{
std::cerr << "Read " << copyRsrc.resources.countResources() << " resources from " << fn << "\n";
}
ResourceFile copyRsrc(fn);
if(!copyRsrc.read())
{
world.problem(Diagnostic(Diagnostic::error, "Could not read binary resource file " + fn, yy::location()));
}
else if(world.verboseFlag)
{
std::cerr << "Read " << copyRsrc.resources.countResources() << " resources from " << fn << "\n";
}
world.getResources().addResources(copyRsrc.resources);
world.getResources().addResources(copyRsrc.resources);
}
int main(int argc, const char *argv[])
{
desc.add_options()
("help,h", "show this help message")
("output,o", po::value<std::string>()->default_value("rez.output.rsrc"), "output file")
("append,a", "append to existing output file")
("type,t", po::value<std::string>()->default_value("rsrc"), "output file finder type code")
("creator,c", po::value<std::string>()->default_value("RSED"), "output file finder creator code")
("define,D", po::value<std::vector<std::string>>(), "predefine preprocessor symbol")
("include,I", po::value<std::vector<std::string>>(), "add include file path")
("copy", po::value<std::vector<std::string>>(), "copy resources from other resource file")
("cc", po::value<std::vector<std::string>>(), "also write output to another file")
("debug,d", "debug logging")
("data", po::value<std::string>(), "copy data fork from another file")
;
po::options_description hidden, alldesc;
hidden.add_options()
("input", po::value<std::vector<std::string>>(), "input file" )
;
alldesc.add(desc).add(hidden);
desc.add_options()
("help,h", "show this help message")
("output,o", po::value<std::string>()->default_value("rez.output.rsrc"), "output file")
("append,a", "append to existing output file")
("type,t", po::value<std::string>()->default_value("rsrc"), "output file finder type code")
("creator,c", po::value<std::string>()->default_value("RSED"), "output file finder creator code")
("define,D", po::value<std::vector<std::string>>(), "predefine preprocessor symbol")
("include,I", po::value<std::vector<std::string>>(), "add include file path")
("copy", po::value<std::vector<std::string>>(), "copy resources from other resource file")
("cc", po::value<std::vector<std::string>>(), "also write output to another file")
("debug,d", "debug logging")
("data", po::value<std::string>(), "copy data fork from another file")
;
po::options_description hidden, alldesc;
hidden.add_options()
("input", po::value<std::vector<std::string>>(), "input file" )
;
alldesc.add(desc).add(hidden);
po::variables_map options;
try
{
auto parsed = po::command_line_parser(argc, argv)
.options(alldesc)
.positional(po::positional_options_description().add("input", -1))
.style(po::command_line_style::default_style)
.run();
po::variables_map options;
try
{
auto parsed = po::command_line_parser(argc, argv)
.options(alldesc)
.positional(po::positional_options_description().add("input", -1))
.style(po::command_line_style::default_style)
.run();
po::store(parsed, options);
}
catch(po::error& e)
{
std::cerr << "ERROR: " << e.what() << std::endl << std::endl;
usage();
return 1;
}
po::store(parsed, options);
}
catch(po::error& e)
{
std::cerr << "ERROR: " << e.what() << std::endl << std::endl;
usage();
return 1;
}
po::notify(options);
po::notify(options);
if(options.count("help")
|| (!options.count("input") && !options.count("copy")
&& !options.count("output")))
{
usage();
return 0;
}
if(options.count("help")
|| (!options.count("input") && !options.count("copy")
&& !options.count("output")))
{
usage();
return 0;
}
RezWorld world;
RezWorld world;
if(options.count("debug"))
world.verboseFlag = true;
if(options.count("debug"))
world.verboseFlag = true;
std::string outfile = options["output"].as<std::string>();
ResourceFile rsrcFile(outfile);
std::string outfile = options["output"].as<std::string>();
ResourceFile rsrcFile(outfile);
if(options.count("append"))
{
rsrcFile.read();
if(options.count("append"))
{
rsrcFile.read();
world.getResources().addResources(rsrcFile.resources);
}
world.getResources().addResources(rsrcFile.resources);
}
if(options.count("data"))
{
std::string fn = options["data"].as<std::string>();
ResourceFile dataFile(fn);
if(!dataFile.read())
world.problem(Diagnostic(Diagnostic::error, "Could not read dataresource file " + fn, yy::location()));
rsrcFile.data = dataFile.data;
}
if(options.count("data"))
{
std::string fn = options["data"].as<std::string>();
ResourceFile dataFile(fn);
if(!dataFile.read())
world.problem(Diagnostic(Diagnostic::error, "Could not read dataresource file " + fn, yy::location()));
rsrcFile.data = dataFile.data;
}
if(options.count("copy"))
for(std::string fn : options["copy"].as<std::vector<std::string>>())
CopyBinaryResources(world, fn);
if(options.count("copy"))
for(std::string fn : options["copy"].as<std::vector<std::string>>())
CopyBinaryResources(world, fn);
if(options.count("input"))
for(std::string fn : options["input"].as<std::vector<std::string>>())
{
fs::path path(fn);
if(path.extension() == ".rsrc" || path.extension() == ".bin")
{
CopyBinaryResources(world, fn);
}
else
{
try
{
RezLexer lexer(world, fn);
if(options.count("input"))
for(std::string fn : options["input"].as<std::vector<std::string>>())
{
fs::path path(fn);
if(path.extension() == ".rsrc" || path.extension() == ".bin")
{
CopyBinaryResources(world, fn);
}
else
{
try
{
RezLexer lexer(world, fn);
if(options.count("define"))
for(std::string define : options["define"].as<std::vector<std::string>>())
lexer.addDefine(define);
if(options.count("include"))
for(std::string path : options["include"].as<std::vector<std::string>>())
lexer.addIncludePath(path);
if(options.count("define"))
for(std::string define : options["define"].as<std::vector<std::string>>())
lexer.addDefine(define);
if(options.count("include"))
for(std::string path : options["include"].as<std::vector<std::string>>())
lexer.addIncludePath(path);
if(world.verboseFlag)
{
std::cerr << "Compiling " << fn << "...\n";
}
if(world.verboseFlag)
{
std::cerr << "Compiling " << fn << "...\n";
}
RezParser parser(lexer, world);
parser.parse();
}
catch(...)
{
world.problem(Diagnostic(Diagnostic::fatalError,"unknown error",yy::location(&fn)));
}
}
}
RezParser parser(lexer, world);
parser.parse();
}
catch(...)
{
world.problem(Diagnostic(Diagnostic::fatalError,"unknown error",yy::location(&fn)));
}
}
}
if(world.hadErrors)
return 1;
if(world.hadErrors)
return 1;
rsrcFile.resources = world.getResources();
rsrcFile.creator = options["creator"].as<std::string>();
rsrcFile.type = options["type"].as<std::string>();
rsrcFile.resources = world.getResources();
rsrcFile.creator = options["creator"].as<std::string>();
rsrcFile.type = options["type"].as<std::string>();
if(world.verboseFlag)
{
std::cerr << "Writing " << rsrcFile.resources.countResources() << " resources.\n";
}
rsrcFile.write();
if(world.verboseFlag)
{
std::cerr << "Writing " << rsrcFile.resources.countResources() << " resources.\n";
}
rsrcFile.write();
if(options.count("cc"))
for(std::string ccFile : options["cc"].as<std::vector<std::string>>())
{
rsrcFile.assign(ccFile);
rsrcFile.write();
}
if(options.count("cc"))
for(std::string ccFile : options["cc"].as<std::vector<std::string>>())
{
rsrcFile.assign(ccFile);
rsrcFile.write();
}
return 0;
return 0;
}

View File

@@ -15,112 +15,112 @@ using namespace boost::wave;
static std::string readContents(std::istream&& instream)
{
instream.unsetf(std::ios::skipws);
instream.unsetf(std::ios::skipws);
return std::string(std::istreambuf_iterator<char>(instream.rdbuf()),
std::istreambuf_iterator<char>());
return std::string(std::istreambuf_iterator<char>(instream.rdbuf()),
std::istreambuf_iterator<char>());
}
static std::string preFilter(std::string str)
{
boost::regex endif("#endif[^\r\n]*");
str = boost::regex_replace(str, endif, "#endif");
boost::regex endif("#endif[^\r\n]*");
str = boost::regex_replace(str, endif, "#endif");
boost::regex dollar_escape("\\\\\\$([a-zA-Z0-9][a-zA-Z0-9])");
str = boost::regex_replace(str, dollar_escape, "\\\\0x$1");
boost::regex dollar_escape("\\\\\\$([a-zA-Z0-9][a-zA-Z0-9])");
str = boost::regex_replace(str, dollar_escape, "\\\\0x$1");
if(str.size() == 0 || str[str.size()-1] != '\n')
str += "\n";
return str;
if(str.size() == 0 || str[str.size()-1] != '\n')
str += "\n";
return str;
}
struct load_file_to_string_filtered
{
template <typename IterContextT>
class inner
{
public:
template <typename PositionT>
static void init_iterators(IterContextT &iter_ctx,
PositionT const &act_pos, language_support language)
{
typedef typename IterContextT::iterator_type iterator_type;
template <typename IterContextT>
class inner
{
public:
template <typename PositionT>
static void init_iterators(IterContextT &iter_ctx,
PositionT const &act_pos, language_support language)
{
typedef typename IterContextT::iterator_type iterator_type;
// read in the file
std::ifstream instream(iter_ctx.filename.c_str());
if (!instream.is_open()) {
BOOST_WAVE_THROW_CTX(iter_ctx.ctx, preprocess_exception,
bad_include_file, iter_ctx.filename.c_str(), act_pos);
return;
}
// read in the file
std::ifstream instream(iter_ctx.filename.c_str());
if (!instream.is_open()) {
BOOST_WAVE_THROW_CTX(iter_ctx.ctx, preprocess_exception,
bad_include_file, iter_ctx.filename.c_str(), act_pos);
return;
}
iter_ctx.instring = preFilter(readContents(std::move(instream)));
iter_ctx.instring = preFilter(readContents(std::move(instream)));
iter_ctx.first = iterator_type(
iter_ctx.instring.begin(), iter_ctx.instring.end(),
PositionT(iter_ctx.filename), language);
iter_ctx.last = iterator_type();
}
iter_ctx.first = iterator_type(
iter_ctx.instring.begin(), iter_ctx.instring.end(),
PositionT(iter_ctx.filename), language);
iter_ctx.last = iterator_type();
}
private:
std::string instring;
};
private:
std::string instring;
};
};
typedef wave::cpplexer::lex_iterator<
wave::cpplexer::lex_token<> >
lex_iterator_type;
wave::cpplexer::lex_token<> >
lex_iterator_type;
typedef wave::context<
std::string::iterator, lex_iterator_type,
load_file_to_string_filtered>
context_type;
std::string::iterator, lex_iterator_type,
load_file_to_string_filtered>
context_type;
typedef context_type::iterator_type pp_iterator_type;
struct RezLexer::Priv
{
std::string input;
context_type ctx;
pp_iterator_type iter;
std::string input;
context_type ctx;
pp_iterator_type iter;
Priv(std::string data, std::string name)
: input(data), ctx(input.begin(), input.end(), name.c_str())
{
}
Priv(std::string data, std::string name)
: input(data), ctx(input.begin(), input.end(), name.c_str())
{
}
};
static std::string readInitial(RezWorld& world, std::string filename)
{
std::ifstream in(filename);
if(!in.is_open())
{
world.problem(Diagnostic(Diagnostic::error,
"could not open " + filename, yy::location()));
}
return readContents(std::move(in));
std::ifstream in(filename);
if(!in.is_open())
{
world.problem(Diagnostic(Diagnostic::error,
"could not open " + filename, yy::location()));
}
return readContents(std::move(in));
}
RezLexer::RezLexer(RezWorld& world, std::string filename)
: RezLexer(world, filename, readInitial(world,filename))
: RezLexer(world, filename, readInitial(world,filename))
{
}
RezLexer::RezLexer(RezWorld& world, std::string filename, const std::string &data)
: world(world), curFile(filename), lastLocation(&curFile)
: world(world), curFile(filename), lastLocation(&curFile)
{
pImpl.reset(new Priv(preFilter(data), filename));
pImpl.reset(new Priv(preFilter(data), filename));
pImpl->ctx.add_macro_definition("DeRez=0");
pImpl->ctx.add_macro_definition("Rez=1");
pImpl->ctx.add_macro_definition("true=1");
pImpl->ctx.add_macro_definition("false=0");
pImpl->ctx.add_macro_definition("TRUE=1");
pImpl->ctx.add_macro_definition("FALSE=0");
pImpl->ctx.add_macro_definition("DeRez=0");
pImpl->ctx.add_macro_definition("Rez=1");
pImpl->ctx.add_macro_definition("true=1");
pImpl->ctx.add_macro_definition("false=0");
pImpl->ctx.add_macro_definition("TRUE=1");
pImpl->ctx.add_macro_definition("FALSE=0");
pImpl->iter = pImpl->ctx.begin();
pImpl->iter = pImpl->ctx.begin();
}
RezLexer::~RezLexer()
@@ -132,61 +132,61 @@ RezLexer::~RezLexer()
void RezLexer::addDefine(std::string str)
{
pImpl->ctx.add_macro_definition(str);
pImpl->ctx.add_macro_definition(str);
}
void RezLexer::addIncludePath(std::string path)
{
std::size_t pos = path.find(':');
if(pos == std::string::npos)
{
pImpl->ctx.add_include_path(path.c_str());
}
else
{
addIncludePath(path.substr(0,pos));
addIncludePath(path.substr(pos + 1));
}
std::size_t pos = path.find(':');
if(pos == std::string::npos)
{
pImpl->ctx.add_include_path(path.c_str());
}
else
{
addIncludePath(path.substr(0,pos));
addIncludePath(path.substr(pos + 1));
}
}
bool RezLexer::atEnd()
{
return pImpl->iter == pImpl->ctx.end();
return pImpl->iter == pImpl->ctx.end();
}
RezLexer::WaveToken RezLexer::nextWave()
{
try
{
if(pImpl->iter == pImpl->ctx.end())
return WaveToken();
else
{
WaveToken tok = *pImpl->iter++;
return tok;
}
}
catch(const preprocess_exception& e)
{
curFile = e.file_name();
auto yypos = yy::position(&curFile, e.line_no(), e.column_no());
yy::location loc(yypos);
lastLocation = loc;
try
{
if(pImpl->iter == pImpl->ctx.end())
return WaveToken();
else
{
WaveToken tok = *pImpl->iter++;
return tok;
}
}
catch(const preprocess_exception& e)
{
curFile = e.file_name();
auto yypos = yy::position(&curFile, e.line_no(), e.column_no());
yy::location loc(yypos);
lastLocation = loc;
world.problem(Diagnostic(
e.severity_level(e.get_errorcode()) >= util::severity_error
? Diagnostic::error
: Diagnostic::warning,
preprocess_exception::error_text(e.get_errorcode()), loc));
if(e.is_recoverable())
return nextWave();
else
return WaveToken();
}
world.problem(Diagnostic(
e.severity_level(e.get_errorcode()) >= util::severity_error
? Diagnostic::error
: Diagnostic::warning,
preprocess_exception::error_text(e.get_errorcode()), loc));
if(e.is_recoverable())
return nextWave();
else
return WaveToken();
}
}
RezLexer::WaveToken RezLexer::peekWave()
{
return pImpl->iter == pImpl->ctx.end() ? WaveToken() : *pImpl->iter;
return pImpl->iter == pImpl->ctx.end() ? WaveToken() : *pImpl->iter;
}

View File

@@ -11,28 +11,28 @@ class RezWorld;
class RezLexer
{
RezWorld& world;
struct Priv;
std::unique_ptr<Priv> pImpl;
RezWorld& world;
struct Priv;
std::unique_ptr<Priv> pImpl;
std::string curFile;
yy::location lastLocation;
std::string curFile;
yy::location lastLocation;
class WaveToken;
class WaveToken;
bool atEnd();
WaveToken nextWave();
WaveToken peekWave();
bool atEnd();
WaveToken nextWave();
WaveToken peekWave();
public:
RezLexer(RezWorld& world, std::string filename);
RezLexer(RezWorld& world, std::string filename, const std::string& data);
~RezLexer();
RezLexer(RezWorld& world, std::string filename);
RezLexer(RezWorld& world, std::string filename, const std::string& data);
~RezLexer();
RezSymbol nextToken();
RezSymbol nextToken();
void addDefine(std::string str);
void addIncludePath(std::string path);
void addDefine(std::string str);
void addIncludePath(std::string path);
};
#endif // REZLEXER_H

View File

@@ -9,287 +9,287 @@ using namespace boost::wave;
static int readInt(const char *str, const char *end = NULL, int baseOverride = 0)
{
int x = 0;
int x = 0;
int base = 10;
int base = 10;
if(baseOverride)
base = baseOverride;
else if(*str == '0')
{
base = 8;
++str;
if(*str == 'x' || *str == 'X')
{
base = 16;
++str;
}
if(*str == 'b' || *str == 'B')
{
base = 2;
++str;
}
}
else if(*str == 'b' || *str == 'B')
{
base = 2;
++str;
}
if(baseOverride)
base = baseOverride;
else if(*str == '0')
{
base = 8;
++str;
if(*str == 'x' || *str == 'X')
{
base = 16;
++str;
}
if(*str == 'b' || *str == 'B')
{
base = 2;
++str;
}
}
else if(*str == 'b' || *str == 'B')
{
base = 2;
++str;
}
while(str != end && *str)
{
x *= base;
if(*str >= 'a' && *str <= 'z')
x += *str - 'a' + 10;
else if(*str >= 'A' && *str <= 'Z')
x += *str - 'A' + 10;
else if(*str >= '0' && *str <= '9')
x += *str - '0';
str++;
}
while(str != end && *str)
{
x *= base;
if(*str >= 'a' && *str <= 'z')
x += *str - 'a' + 10;
else if(*str >= 'A' && *str <= 'Z')
x += *str - 'A' + 10;
else if(*str >= '0' && *str <= '9')
x += *str - '0';
str++;
}
return x;
return x;
}
static int readCharLit(const char *str)
{
const char *p = str + 1;
const char *e = str + strlen(str) - 1;
const char *p = str + 1;
const char *e = str + strlen(str) - 1;
if(e - p != 4)
std::cout << "warning: CHAR LITERAL " << str << "\n";
if(e - p != 4)
std::cout << "warning: CHAR LITERAL " << str << "\n";
int x = 0;
while(p != e)
{
x <<= 8;
x |= (*p) & 0xFF;
++p;
}
return x;
int x = 0;
while(p != e)
{
x <<= 8;
x |= (*p) & 0xFF;
++p;
}
return x;
}
static std::string readStringLit(const char *str)
{
const char *p = str + 1;
const char *e = str + strlen(str) - 1;
const char *p = str + 1;
const char *e = str + strlen(str) - 1;
std::ostringstream out;
std::ostringstream out;
while(p != e)
{
if(*p == '\\')
{
++p;
if(p != e)
{
switch(*p)
{
case 'n':
out << '\n'; ++p;
break;
case 'r':
out << '\r'; ++p;
break;
case 't':
out << '\t'; ++p;
break;
case '0':
case '1':
case '2':
case '3':
if(p + 3 > e)
continue;
if(p[0] == '0' && (p[1] == 'x' || p[1] == 'X'))
{
if(p + 4 > e)
continue;
out << (char)readInt(p+2, p+4, 16);
p += 4;
}
else
{
out << (char)readInt(p, p+3, 8);
p += 3;
}
break;
case '$':
{
if(p + 3 > e)
continue;
out << (char)readInt(p+1, p+3, 16);
p += 3;
}
break;
}
}
}
else
{
out << *p++;
}
}
while(p != e)
{
if(*p == '\\')
{
++p;
if(p != e)
{
switch(*p)
{
case 'n':
out << '\n'; ++p;
break;
case 'r':
out << '\r'; ++p;
break;
case 't':
out << '\t'; ++p;
break;
case '0':
case '1':
case '2':
case '3':
if(p + 3 > e)
continue;
if(p[0] == '0' && (p[1] == 'x' || p[1] == 'X'))
{
if(p + 4 > e)
continue;
out << (char)readInt(p+2, p+4, 16);
p += 4;
}
else
{
out << (char)readInt(p, p+3, 8);
p += 3;
}
break;
case '$':
{
if(p + 3 > e)
continue;
out << (char)readInt(p+1, p+3, 16);
p += 3;
}
break;
}
}
}
else
{
out << *p++;
}
}
return out.str();
return out.str();
}
RezSymbol RezLexer::nextToken()
{
for(auto tok = nextWave(); tok != T_EOI && tok != T_EOF; tok = nextWave())
{
if(IS_CATEGORY(tok, WhiteSpaceTokenType))
continue;
else if(IS_CATEGORY(tok, EOLTokenType))
continue;
else if(tok == T_PP_LINE)
{
while(tok != T_EOI && tok != T_EOF && !IS_CATEGORY(tok, EOLTokenType))
tok = nextWave();
continue;
}
else
{
//std::cout << "{" << std::hex << (token_id)tok << std::dec << "|" << tok.get_value() << "}\n";
for(auto tok = nextWave(); tok != T_EOI && tok != T_EOF; tok = nextWave())
{
if(IS_CATEGORY(tok, WhiteSpaceTokenType))
continue;
else if(IS_CATEGORY(tok, EOLTokenType))
continue;
else if(tok == T_PP_LINE)
{
while(tok != T_EOI && tok != T_EOF && !IS_CATEGORY(tok, EOLTokenType))
tok = nextWave();
continue;
}
else
{
//std::cout << "{" << std::hex << (token_id)tok << std::dec << "|" << tok.get_value() << "}\n";
auto pos = tok.get_position();
curFile = pos.get_file().c_str();
auto yypos = yy::position(&curFile, pos.get_line(), pos.get_column());
yy::location loc(yypos);
lastLocation = loc;
auto pos = tok.get_position();
curFile = pos.get_file().c_str();
auto yypos = yy::position(&curFile, pos.get_line(), pos.get_column());
yy::location loc(yypos);
lastLocation = loc;
if(tok == (UnknownTokenType | '"'))
{
return RezParser::make_STRINGLIT("Hello, world.", loc);
}
else if(IS_CATEGORY(tok, IdentifierTokenType) || IS_CATEGORY(tok, KeywordTokenType) || IS_CATEGORY(tok, BoolLiteralTokenType))
{
typedef decltype(&RezParser::make_TYPE) memfun;
if(tok == (UnknownTokenType | '"'))
{
return RezParser::make_STRINGLIT("Hello, world.", loc);
}
else if(IS_CATEGORY(tok, IdentifierTokenType) || IS_CATEGORY(tok, KeywordTokenType) || IS_CATEGORY(tok, BoolLiteralTokenType))
{
typedef decltype(&RezParser::make_TYPE) memfun;
#define KEYWORD(upper, lower) \
{ lower, &RezParser::make_ ## upper }
static std::unordered_map<std::string, memfun> keywords = {
KEYWORD(TYPE, "type"),
KEYWORD(RESOURCE, "resource"),
KEYWORD(DATA, "data"),
KEYWORD(READ, "read"),
KEYWORD(INCLUDE, "include"),
KEYWORD(CHANGE, "change"),
KEYWORD(DELETE, "delete"),
static std::unordered_map<std::string, memfun> keywords = {
KEYWORD(TYPE, "type"),
KEYWORD(RESOURCE, "resource"),
KEYWORD(DATA, "data"),
KEYWORD(READ, "read"),
KEYWORD(INCLUDE, "include"),
KEYWORD(CHANGE, "change"),
KEYWORD(DELETE, "delete"),
KEYWORD(ARRAY,"array"),
KEYWORD(SWITCH, "switch"),
KEYWORD(CASE, "case"),
KEYWORD(AS, "as"),
KEYWORD(FILL,"fill"),
KEYWORD(ALIGN, "align"),
KEYWORD(HEX,"hex"),
KEYWORD(KEY, "key"),
KEYWORD(WIDE,"wide"),
KEYWORD(UNSIGNED, "unsigned"),
KEYWORD(ARRAY,"array"),
KEYWORD(SWITCH, "switch"),
KEYWORD(CASE, "case"),
KEYWORD(AS, "as"),
KEYWORD(FILL,"fill"),
KEYWORD(ALIGN, "align"),
KEYWORD(HEX,"hex"),
KEYWORD(KEY, "key"),
KEYWORD(WIDE,"wide"),
KEYWORD(UNSIGNED, "unsigned"),
KEYWORD(BINARY, "binary"),
KEYWORD(LITERAL, "literal"),
KEYWORD(BOOLEAN, "boolean"),
KEYWORD(BIT, "bit"),
KEYWORD(NIBBLE, "nibble"),
KEYWORD(BYTE, "byte"),
KEYWORD(CHAR, "char"),
KEYWORD(WORD, "word"),
KEYWORD(INTEGER, "integer"),
KEYWORD(LONG, "long"),
KEYWORD(LONGINT, "longint"),
KEYWORD(PSTRING, "pstring"),
KEYWORD(PSTRING, "wstring"),
KEYWORD(STRING, "string"),
KEYWORD(POINT, "point"),
KEYWORD(RECT, "rect"),
KEYWORD(BITSTRING, "bitstring"),
KEYWORD(LITERAL, "literal"),
KEYWORD(BOOLEAN, "boolean"),
KEYWORD(BIT, "bit"),
KEYWORD(NIBBLE, "nibble"),
KEYWORD(BYTE, "byte"),
KEYWORD(CHAR, "char"),
KEYWORD(WORD, "word"),
KEYWORD(INTEGER, "integer"),
KEYWORD(LONG, "long"),
KEYWORD(LONGINT, "longint"),
KEYWORD(PSTRING, "pstring"),
KEYWORD(PSTRING, "wstring"),
KEYWORD(STRING, "string"),
KEYWORD(POINT, "point"),
KEYWORD(RECT, "rect"),
KEYWORD(BITSTRING, "bitstring"),
KEYWORD(INTEGER, "int"),
KEYWORD(DOLLAR, "$"),
KEYWORD(INTEGER, "int"),
KEYWORD(DOLLAR, "$"),
KEYWORD(FUN_COUNTOF, "$$countof"),
KEYWORD(FUN_ARRAYINDEX, "$$arrayindex"),
KEYWORD(FUN_READ, "$$read"),
KEYWORD(FUN_BITFIELD, "$$bitfield"),
KEYWORD(FUN_WORD, "$$word"),
KEYWORD(FUN_BYTE, "$$byte"),
KEYWORD(FUN_LONG, "$$long"),
};
KEYWORD(FUN_COUNTOF, "$$countof"),
KEYWORD(FUN_ARRAYINDEX, "$$arrayindex"),
KEYWORD(FUN_READ, "$$read"),
KEYWORD(FUN_BITFIELD, "$$bitfield"),
KEYWORD(FUN_WORD, "$$word"),
KEYWORD(FUN_BYTE, "$$byte"),
KEYWORD(FUN_LONG, "$$long"),
};
std::string s = tok.get_value().c_str();
if(s.size() >= 2 && s[0] == '$' && std::all_of(s.begin()+1, s.end(), [](char c) { return isxdigit(c); }))
return RezParser::make_INTLIT(readInt(s.c_str()+1, nullptr, 16), loc);
std::string s = tok.get_value().c_str();
if(s.size() >= 2 && s[0] == '$' && std::all_of(s.begin()+1, s.end(), [](char c) { return isxdigit(c); }))
return RezParser::make_INTLIT(readInt(s.c_str()+1, nullptr, 16), loc);
std::string lower = s;
std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
auto p = keywords.find(lower);
if(p == keywords.end())
{
//std::cout << "id: " << s << std::endl;
return RezParser::make_IDENTIFIER(lower, loc);
}
else
{
//std::cout << "key: " << s << std::endl;
return (*p->second)(loc);
}
}
else if(tok == T_INTLIT)
{
if(tok.get_value() == "0")
{
auto tok2 = peekWave();
while(tok2 != T_EOI && tok2 != T_EOF && IS_CATEGORY(tok2, WhiteSpaceTokenType))
nextWave(), tok2 = peekWave();
std::string lower = s;
std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
auto p = keywords.find(lower);
if(p == keywords.end())
{
//std::cout << "id: " << s << std::endl;
return RezParser::make_IDENTIFIER(lower, loc);
}
else
{
//std::cout << "key: " << s << std::endl;
return (*p->second)(loc);
}
}
else if(tok == T_INTLIT)
{
if(tok.get_value() == "0")
{
auto tok2 = peekWave();
while(tok2 != T_EOI && tok2 != T_EOF && IS_CATEGORY(tok2, WhiteSpaceTokenType))
nextWave(), tok2 = peekWave();
//std::cout << "!" << std::hex << (token_id)tok2 << std::dec << "|" << tok2.get_value() << "!\n";
static boost::regex binlit("[bB][01]+");
if(tok2 == T_IDENTIFIER && boost::regex_match(tok2.get_value().c_str(), binlit))
tok = nextWave();
}
return RezParser::make_INTLIT(readInt(tok.get_value().c_str()), loc);
}
else
{
#define NOVAL_TOK(name) \
//std::cout << "!" << std::hex << (token_id)tok2 << std::dec << "|" << tok2.get_value() << "!\n";
static boost::regex binlit("[bB][01]+");
if(tok2 == T_IDENTIFIER && boost::regex_match(tok2.get_value().c_str(), binlit))
tok = nextWave();
}
return RezParser::make_INTLIT(readInt(tok.get_value().c_str()), loc);
}
else
{
#define NOVAL_TOK(name) \
case T_ ## name: /*std::cout << #name << std::endl;*/ return RezParser::make_ ## name(loc)
switch(token_id(tok))
{
case T_INTLIT: return RezParser::make_INTLIT(readInt(tok.get_value().c_str()), loc);
switch(token_id(tok))
{
case T_INTLIT: return RezParser::make_INTLIT(readInt(tok.get_value().c_str()), loc);
case T_CHARLIT: return RezParser::make_CHARLIT(readCharLit(tok.get_value().c_str()), loc);
case T_STRINGLIT: return RezParser::make_STRINGLIT(readStringLit(tok.get_value().c_str()), loc);
case T_CHARLIT: return RezParser::make_CHARLIT(readCharLit(tok.get_value().c_str()), loc);
case T_STRINGLIT: return RezParser::make_STRINGLIT(readStringLit(tok.get_value().c_str()), loc);
NOVAL_TOK(LEFTBRACE);
NOVAL_TOK(RIGHTBRACE);
NOVAL_TOK(LEFTBRACKET);
NOVAL_TOK(RIGHTBRACKET);
NOVAL_TOK(LEFTPAREN);
NOVAL_TOK(RIGHTPAREN);
NOVAL_TOK(SEMICOLON);
NOVAL_TOK(COMMA);
NOVAL_TOK(PLUS);
NOVAL_TOK(MINUS);
NOVAL_TOK(DIVIDE);
NOVAL_TOK(STAR);
NOVAL_TOK(ASSIGN);
NOVAL_TOK(COLON);
NOVAL_TOK(SHIFTLEFT);
NOVAL_TOK(SHIFTRIGHT);
NOVAL_TOK(EQUAL);
NOVAL_TOK(NOTEQUAL);
NOVAL_TOK(AND);
NOVAL_TOK(OR);
NOVAL_TOK(XOR);
NOVAL_TOK(COMPL);
NOVAL_TOK(LEFTBRACE);
NOVAL_TOK(RIGHTBRACE);
NOVAL_TOK(LEFTBRACKET);
NOVAL_TOK(RIGHTBRACKET);
NOVAL_TOK(LEFTPAREN);
NOVAL_TOK(RIGHTPAREN);
NOVAL_TOK(SEMICOLON);
NOVAL_TOK(COMMA);
NOVAL_TOK(PLUS);
NOVAL_TOK(MINUS);
NOVAL_TOK(DIVIDE);
NOVAL_TOK(STAR);
NOVAL_TOK(ASSIGN);
NOVAL_TOK(COLON);
NOVAL_TOK(SHIFTLEFT);
NOVAL_TOK(SHIFTRIGHT);
NOVAL_TOK(EQUAL);
NOVAL_TOK(NOTEQUAL);
NOVAL_TOK(AND);
NOVAL_TOK(OR);
NOVAL_TOK(XOR);
NOVAL_TOK(COMPL);
default:
default:
return RezParser::make_BADTOKEN(tok.get_value().c_str(), loc);
}
return RezParser::make_BADTOKEN(tok.get_value().c_str(), loc);
}
}
}
}
return RezParser::symbol_type(RezParser::token_type(0), yy::location());
}
}
}
return RezParser::symbol_type(RezParser::token_type(0), yy::location());
}

View File

@@ -8,8 +8,8 @@
class RezLexer::WaveToken : public boost::wave::cpplexer::lex_token<>
{
public:
WaveToken() = default;
WaveToken(const boost::wave::cpplexer::lex_token<> & o) : boost::wave::cpplexer::lex_token<>(o) {}
WaveToken() = default;
WaveToken(const boost::wave::cpplexer::lex_token<> & o) : boost::wave::cpplexer::lex_token<>(o) {}
};
#endif // REZLEXERWAVETOKEN_H

View File

@@ -7,52 +7,52 @@
#include "Diagnostic.h"
RezWorld::RezWorld()
: verboseFlag(false), hadErrors(false)
: verboseFlag(false), hadErrors(false)
{
}
void RezWorld::addTypeDefinition(TypeSpec spec, TypeDefinitionPtr type)
{
if(!type)
return;
types[spec] = type;
if(!type)
return;
types[spec] = type;
}
TypeDefinitionPtr RezWorld::getTypeDefinition(ResType type, int id, yy::location loc)
{
auto p = types.find(TypeSpec(type, id));
if(p != types.end())
return p->second;
p = types.find(TypeSpec(type));
if(p != types.end())
return p->second;
problem(Diagnostic(Diagnostic::Severity::error, "Can't find type definition for '" + std::string(type) + "'", loc));
auto p = types.find(TypeSpec(type, id));
if(p != types.end())
return p->second;
p = types.find(TypeSpec(type));
if(p != types.end())
return p->second;
problem(Diagnostic(Diagnostic::Severity::error, "Can't find type definition for '" + std::string(type) + "'", loc));
return nullptr;
return nullptr;
}
void RezWorld::addResource(ResSpec spec, CompoundExprPtr body, yy::location loc)
{
if(verboseFlag)
std::cout << "RESOURCE " << spec.type() << "(" << spec.id() << ", " << "\"" << spec.name() << "\"" << spec.attr() << ")" << std::endl;
TypeDefinitionPtr def = getTypeDefinition(spec.type(), spec.id(), loc);
if(!def)
return;
ResourceCompiler compiler(*this, def, body, verboseFlag);
compiler.compile();
if(verboseFlag)
std::cout << "RESOURCE " << spec.type() << "(" << spec.id() << ", " << "\"" << spec.name() << "\"" << spec.attr() << ")" << std::endl;
TypeDefinitionPtr def = getTypeDefinition(spec.type(), spec.id(), loc);
if(!def)
return;
ResourceCompiler compiler(*this, def, body, verboseFlag);
compiler.compile();
resources.addResource(Resource(spec.type(), spec.id(), compiler.resourceData(), spec.name(), spec.attr()));
resources.addResource(Resource(spec.type(), spec.id(), compiler.resourceData(), spec.name(), spec.attr()));
}
void RezWorld::addData(ResSpec spec, const std::string &data, yy::location loc)
{
if(verboseFlag)
std::cout << "DATA " << spec.type() << "(" << spec.id() << ", " << "\"" << spec.name() << "\"" << spec.attr() << ")" << std::endl;
resources.addResource(Resource(spec.type(), spec.id(), data, spec.name(), spec.attr()));
if(verboseFlag)
std::cout << "DATA " << spec.type() << "(" << spec.id() << ", " << "\"" << spec.name() << "\"" << spec.attr() << ")" << std::endl;
resources.addResource(Resource(spec.type(), spec.id(), data, spec.name(), spec.attr()));
}
void RezWorld::problem(Diagnostic d)
{
hadErrors = true;
std::cerr << d << std::endl;
hadErrors = true;
std::cerr << d << std::endl;
}

View File

@@ -13,30 +13,30 @@ class Diagnostic;
class RezWorld
{
friend class RezParser;
friend class RezParser;
std::map<TypeSpec, TypeDefinitionPtr> types;
std::stack<FieldListPtr> fieldLists;
std::stack<IdentifierExprPtr> functionCalls;
std::stack<SwitchFieldPtr> switches;
std::map<TypeSpec, TypeDefinitionPtr> types;
std::stack<FieldListPtr> fieldLists;
std::stack<IdentifierExprPtr> functionCalls;
std::stack<SwitchFieldPtr> switches;
Resources resources;
Resources resources;
public:
RezWorld();
void addTypeDefinition(TypeSpec spec, TypeDefinitionPtr type);
RezWorld();
void addTypeDefinition(TypeSpec spec, TypeDefinitionPtr type);
TypeDefinitionPtr getTypeDefinition(ResType type, int id, yy::location loc);
TypeDefinitionPtr getTypeDefinition(ResType type, int id, yy::location loc);
void addResource(ResSpec spec, CompoundExprPtr body, yy::location loc);
void addData(ResSpec spec, const std::string& data, yy::location loc);
void addResource(ResSpec spec, CompoundExprPtr body, yy::location loc);
void addData(ResSpec spec, const std::string& data, yy::location loc);
Resources& getResources() { return resources; }
Resources& getResources() { return resources; }
bool verboseFlag;
bool hadErrors;
bool verboseFlag;
bool hadErrors;
void problem(Diagnostic d);
void problem(Diagnostic d);
};

View File

@@ -12,89 +12,89 @@
BOOST_AUTO_TEST_SUITE(LexSuite)
#define CHECKSYM(TOKEN, TYPE, VAL) \
do { \
RezSymbol t = lex.nextToken(); \
BOOST_CHECK_EQUAL(t.token(), TOKEN); \
if(t.token() == TOKEN) \
BOOST_CHECK_EQUAL(t.value.as<TYPE>(), VAL); \
} while(0)
#define CHECKSYM_(TOKEN) \
do { \
RezSymbol t = lex.nextToken(); \
BOOST_CHECK_EQUAL(t.token(), TOKEN); \
} while(0)
#define CHECKSYM(TOKEN, TYPE, VAL) \
do { \
RezSymbol t = lex.nextToken(); \
BOOST_CHECK_EQUAL(t.token(), TOKEN); \
if(t.token() == TOKEN) \
BOOST_CHECK_EQUAL(t.value.as<TYPE>(), VAL); \
} while(0)
#define CHECKSYM_(TOKEN) \
do { \
RezSymbol t = lex.nextToken(); \
BOOST_CHECK_EQUAL(t.token(), TOKEN); \
} while(0)
BOOST_AUTO_TEST_CASE(moveBisonSymbol)
{
// Bison 3.2 contains a bug in the move constructor for its symbol type.
// It will crash when used.
// Unfortunately, there is no copy constructor any more, so it's hard to avoid.
std::string filename = "foo";
yy::location loc(&filename, 0,0);
auto sym = RezParser::make_INTLIT(42, loc);
auto sym2 = std::move(sym);
// Bison 3.2 contains a bug in the move constructor for its symbol type.
// It will crash when used.
// Unfortunately, there is no copy constructor any more, so it's hard to avoid.
std::string filename = "foo";
yy::location loc(&filename, 0,0);
auto sym = RezParser::make_INTLIT(42, loc);
auto sym2 = std::move(sym);
}
BOOST_AUTO_TEST_CASE(moveRezSymbol)
{
// This tests my workaround for the bison bug;
// RezSymbol derives from bison's symbol type and reimplements all move constructors
std::string filename = "foo";
yy::location loc(&filename, 0,0);
RezSymbol sym = RezParser::make_INTLIT(42, loc);
auto sym2 = std::move(sym);
// This tests my workaround for the bison bug;
// RezSymbol derives from bison's symbol type and reimplements all move constructors
std::string filename = "foo";
yy::location loc(&filename, 0,0);
RezSymbol sym = RezParser::make_INTLIT(42, loc);
auto sym2 = std::move(sym);
}
BOOST_AUTO_TEST_CASE(basicInt)
{
RezWorld world;
RezLexer lex(world, "test", "123 0x456 0xaBcd9\n");
RezWorld world;
RezLexer lex(world, "test", "123 0x456 0xaBcd9\n");
CHECKSYM(RezParser::token::INTLIT, int, 123);
CHECKSYM(RezParser::token::INTLIT, int, 0x456);
CHECKSYM(RezParser::token::INTLIT, int, 0xabcd9);
CHECKSYM_(0);
CHECKSYM(RezParser::token::INTLIT, int, 123);
CHECKSYM(RezParser::token::INTLIT, int, 0x456);
CHECKSYM(RezParser::token::INTLIT, int, 0xabcd9);
CHECKSYM_(0);
}
BOOST_AUTO_TEST_CASE(alternateHex)
{
RezWorld world;
RezLexer lex(world, "test", "$456 $aBcd9\n");
RezWorld world;
RezLexer lex(world, "test", "$456 $aBcd9\n");
CHECKSYM(RezParser::token::INTLIT, int, 0x456);
CHECKSYM(RezParser::token::INTLIT, int, 0xabcd9);
CHECKSYM_(0);
CHECKSYM(RezParser::token::INTLIT, int, 0x456);
CHECKSYM(RezParser::token::INTLIT, int, 0xabcd9);
CHECKSYM_(0);
}
BOOST_AUTO_TEST_CASE(noNewlineAtEOF)
{
RezWorld world;
RezLexer lex(world, "test", "123 456");
CHECKSYM(RezParser::token::INTLIT, int, 123);
CHECKSYM(RezParser::token::INTLIT, int, 456);
CHECKSYM_(0);
RezWorld world;
RezLexer lex(world, "test", "123 456");
CHECKSYM(RezParser::token::INTLIT, int, 123);
CHECKSYM(RezParser::token::INTLIT, int, 456);
CHECKSYM_(0);
}
BOOST_AUTO_TEST_CASE(strings)
{
RezWorld world;
RezLexer lex(world, "test", R"rez(
"Hello, world."
"Foo \n"
"\r Quux"
"\001\002\003"
"\0x42\0x43"
"Blah \$5F"
)rez" "\n");
CHECKSYM(RezParser::token::STRINGLIT, std::string, "Hello, world.");
CHECKSYM(RezParser::token::STRINGLIT, std::string, "Foo \n");
CHECKSYM(RezParser::token::STRINGLIT, std::string, "\r Quux");
CHECKSYM(RezParser::token::STRINGLIT, std::string, "\001\002\003");
CHECKSYM(RezParser::token::STRINGLIT, std::string, "\x42\x43");
CHECKSYM(RezParser::token::STRINGLIT, std::string, "Blah \x5F");
CHECKSYM_(0);
RezWorld world;
RezLexer lex(world, "test", R"rez(
"Hello, world."
"Foo \n"
"\r Quux"
"\001\002\003"
"\0x42\0x43"
"Blah \$5F"
)rez" "\n");
CHECKSYM(RezParser::token::STRINGLIT, std::string, "Hello, world.");
CHECKSYM(RezParser::token::STRINGLIT, std::string, "Foo \n");
CHECKSYM(RezParser::token::STRINGLIT, std::string, "\r Quux");
CHECKSYM(RezParser::token::STRINGLIT, std::string, "\001\002\003");
CHECKSYM(RezParser::token::STRINGLIT, std::string, "\x42\x43");
CHECKSYM(RezParser::token::STRINGLIT, std::string, "Blah \x5F");
CHECKSYM_(0);
}
BOOST_AUTO_TEST_SUITE_END()
@@ -103,59 +103,59 @@ BOOST_AUTO_TEST_SUITE(BinarySuite)
BOOST_AUTO_TEST_CASE(bytes)
{
BinaryOutput out;
out.write(8, 'a');
out.write(8, 'b');
out.write(8, 'c');
BOOST_CHECK_EQUAL(out.resourceData(), "abc");
BinaryOutput out;
out.write(8, 'a');
out.write(8, 'b');
out.write(8, 'c');
BOOST_CHECK_EQUAL(out.resourceData(), "abc");
}
BOOST_AUTO_TEST_CASE(multibyte)
{
BinaryOutput out;
out.write(32, 'abcd');
BOOST_CHECK_EQUAL(out.resourceData(), "abcd");
BinaryOutput out;
out.write(32, 'abcd');
BOOST_CHECK_EQUAL(out.resourceData(), "abcd");
}
BOOST_AUTO_TEST_CASE(subbyte)
{
BinaryOutput out;
out.write(4, 6);
out.write(4, 1);
BinaryOutput out;
out.write(4, 6);
out.write(4, 1);
out.write(2, 1);
out.write(2, 2);
out.write(4, 2);
out.write(2, 1);
out.write(2, 2);
out.write(4, 2);
out.write(3, 3);
out.write(2, 0);
out.write(3, 3);
BOOST_CHECK_EQUAL(out.resourceData(), "abc");
out.write(3, 3);
out.write(2, 0);
out.write(3, 3);
BOOST_CHECK_EQUAL(out.resourceData(), "abc");
}
BOOST_AUTO_TEST_CASE(peek)
{
BinaryOutput out;
for(char c : "Hello, world.")
if(c != 0)
out.write(8, c);
BinaryOutput out;
for(char c : "Hello, world.")
if(c != 0)
out.write(8, c);
BOOST_CHECK_EQUAL(out.resourceData(), "Hello, world.");
BOOST_CHECK_EQUAL(out.resourceData(), "Hello, world.");
BOOST_CHECK_EQUAL(out.peek(0,8), 'H');
BOOST_CHECK_EQUAL(out.peek(32,8), 'o');
BOOST_CHECK_EQUAL(out.peek(0,8), 'H');
BOOST_CHECK_EQUAL(out.peek(32,8), 'o');
BOOST_CHECK_EQUAL(out.peek(0,32), 'Hell');
BOOST_CHECK_EQUAL(out.peek(40,32), ', wo');
BOOST_CHECK_EQUAL(out.peek(0,32), 'Hell');
BOOST_CHECK_EQUAL(out.peek(40,32), ', wo');
BOOST_CHECK_EQUAL(out.peek(1,8), 'H' * 2);
BOOST_CHECK_EQUAL(out.peek(2,8), 0x21);
BOOST_CHECK_EQUAL(out.peek(1,8), 'H' * 2);
BOOST_CHECK_EQUAL(out.peek(2,8), 0x21);
BOOST_CHECK_EQUAL(out.peek(2,30), 'Hell' & 0x3FFFFFFF);
BOOST_CHECK_EQUAL(out.peek(2,32), ('Hell' & 0x3FFFFFFF) << 2 | ('o' >> 6) );
BOOST_CHECK_EQUAL(out.peek(2,30), 'Hell' & 0x3FFFFFFF);
BOOST_CHECK_EQUAL(out.peek(2,32), ('Hell' & 0x3FFFFFFF) << 2 | ('o' >> 6) );
BOOST_CHECK_EQUAL(out.peek(4,3), 4);
BOOST_CHECK_EQUAL(out.peek(4,3), 4);
}
BOOST_AUTO_TEST_SUITE_END()

View File

@@ -1,19 +1,19 @@
# Copyright 2015 Wolfgang Thaller.
# Copyright 2015 Wolfgang Thaller.
#
# This file is part of Retro68.
# This file is part of Retro68.
#
# Retro68 is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# Retro68 is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Retro68 is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# Retro68 is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Retro68. If not, see <http://www.gnu.org/licenses/>.
# You should have received a copy of the GNU General Public License
# along with Retro68. If not, see <http://www.gnu.org/licenses/>.
# To use this example as a standalone project using CMake:
# mkdir build
@@ -22,16 +22,16 @@
# make
add_application(Dialog
dialog.c
dialog.r
)
dialog.c
dialog.r
)
# Enable -ffunction-sections and -gc-sections to make the app as small as possible
# On 68K, also enable --mac-single to build it as a single-segment app (so that this code path doesn't rot)
set_target_properties(Dialog PROPERTIES COMPILE_OPTIONS -ffunction-sections)
if(CMAKE_SYSTEM_NAME MATCHES Retro68)
set_target_properties(Dialog PROPERTIES LINK_FLAGS "-Wl,-gc-sections -Wl,--mac-single")
set_target_properties(Dialog PROPERTIES LINK_FLAGS "-Wl,-gc-sections -Wl,--mac-single")
else()
set_target_properties(Dialog PROPERTIES LINK_FLAGS "-Wl,-gc-sections")
set_target_properties(Dialog PROPERTIES LINK_FLAGS "-Wl,-gc-sections")
endif()

View File

@@ -22,10 +22,10 @@
#include <Fonts.h>
#ifndef TARGET_API_MAC_CARBON
/* NOTE: this is checking whether the Dialogs.h we use *knows* about Carbon,
not whether we are actually compiling for Cabon.
If Dialogs.h is older, we add a define to be able to use the new name
for NewUserItemUPP, which used to be NewUserItemProc. */
/* NOTE: this is checking whether the Dialogs.h we use *knows* about Carbon,
not whether we are actually compiling for Cabon.
If Dialogs.h is older, we add a define to be able to use the new name
for NewUserItemUPP, which used to be NewUserItemProc. */
#define NewUserItemUPP NewUserItemProc
#endif
@@ -33,7 +33,7 @@
pascal void ButtonFrameProc(DialogRef dlg, DialogItemIndex itemNo)
{
DialogItemType type;
Handle itemH;
Handle itemH;
Rect box;
GetDialogItem(dlg, 1, &type, &itemH, &box);
@@ -49,8 +49,8 @@ int main()
InitFonts();
InitWindows();
InitMenus();
TEInit();
InitDialogs(NULL);
TEInit();
InitDialogs(NULL);
#endif
DialogPtr dlg = GetNewDialog(128,0,(WindowPtr)-1);
InitCursor();
@@ -61,7 +61,7 @@ int main()
Rect box;
GetDialogItem(dlg, 2, &type, &itemH, &box);
SetDialogItem(dlg, 2, type, (Handle) NewUserItemUPP(&ButtonFrameProc), &box);
SetDialogItem(dlg, 2, type, (Handle) NewUserItemUPP(&ButtonFrameProc), &box);
ControlHandle cb, radio1, radio2;
GetDialogItem(dlg, 5, &type, &itemH, &box);
@@ -89,5 +89,5 @@ int main()
} while(item != 1);
FlushEvents(everyEvent, -1);
return 0;
return 0;
}

View File

@@ -5,17 +5,17 @@
# make
add_application(HelloWorld
hello.c
CONSOLE
hello.c
CONSOLE
)
# make the result as small as possible
# by removing unused code (gc-sections)
# and by removing macsbug function names on 68K
# (don't do this when debugging...)
# by removing unused code (gc-sections)
# and by removing macsbug function names on 68K
# (don't do this when debugging...)
set_target_properties(HelloWorld PROPERTIES COMPILE_OPTIONS -ffunction-sections)
if(CMAKE_SYSTEM_NAME MATCHES Retro68)
set_target_properties(HelloWorld PROPERTIES LINK_FLAGS "-Wl,-gc-sections -Wl,--mac-strip-macsbug")
set_target_properties(HelloWorld PROPERTIES LINK_FLAGS "-Wl,-gc-sections -Wl,--mac-strip-macsbug")
else()
set_target_properties(HelloWorld PROPERTIES LINK_FLAGS "-Wl,-gc-sections")
set_target_properties(HelloWorld PROPERTIES LINK_FLAGS "-Wl,-gc-sections")
endif()

Some files were not shown because too many files have changed in this diff Show More