mirror of
https://github.com/autc04/Retro68.git
synced 2026-04-27 02:18:53 +00:00
Switch tab-indented files to 4-space indent
This commit is contained in:
1 parent
9cb90cb3b0
commit
e5185d23c3
133 files changed
+7879
-7866
No files matched your search
@@ -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
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -2,5 +2,5 @@
|
||||
|
||||
int main()
|
||||
{
|
||||
TEST_LOG_OK();
|
||||
TEST_LOG_OK();
|
||||
}
|
||||
+10
-10
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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.
|
||||
}
|
||||
|
||||
+64
-64
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -2,5 +2,5 @@
|
||||
|
||||
void TestLog(const char *str)
|
||||
{
|
||||
TEST_LOG_SIZED(str, strlen(str));
|
||||
TEST_LOG_SIZED(str, strlen(str));
|
||||
}
|
||||
+62
-62
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
+10
-10
@@ -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)
|
||||
+13
-13
@@ -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;
|
||||
}
|
||||
@@ -293,7 +293,7 @@ std::string Console::ReadLine()
|
||||
char c;
|
||||
|
||||
do
|
||||
{
|
||||
{
|
||||
c = WaitNextChar();
|
||||
if(!c)
|
||||
{
|
||||
|
||||
+44
-44
@@ -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);
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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();
|
||||
};
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
+340
-340
@@ -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;
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
+161
-161
@@ -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;
|
||||
}
|
||||
+12
-12
@@ -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
|
||||
|
||||
+103
-103
@@ -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;
|
||||
}
|
||||
+260
-260
@@ -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, §ionHeaderStringTableIdx);
|
||||
elf_getshdrstrndx(elf, §ionHeaderStringTableIdx);
|
||||
|
||||
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();
|
||||
}
|
||||
+26
-26
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
||||
+36
-36
@@ -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();
|
||||
}
|
||||
+24
-24
@@ -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);
|
||||
|
||||
+159
-159
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
+37
-37
@@ -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);
|
||||
|
||||
};
|
||||
|
||||
|
||||
+88
-88
@@ -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 "";
|
||||
}
|
||||
+29
-29
@@ -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
|
||||
+21
-21
@@ -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);
|
||||
}
|
||||
}
|
||||
+21
-21
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
||||
+39
-39
@@ -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;
|
||||
}
|
||||
+22
-22
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
+10
-10
@@ -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));
|
||||
}
|
||||
@@ -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
|
||||
@@ -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(¶ms, 0, sizeof(params));
|
||||
params.flags = kLSLaunchStartClassic
|
||||
| kLSLaunchInClassic
|
||||
| kLSLaunchDontAddToRecents
|
||||
| kLSLaunchNewInstance;
|
||||
params.application = &ref;
|
||||
|
||||
ProcessSerialNumber psn;
|
||||
LSOpenApplication(¶ms, &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(¶ms, 0, sizeof(params));
|
||||
params.flags = kLSLaunchStartClassic
|
||||
| kLSLaunchInClassic
|
||||
| kLSLaunchDontAddToRecents
|
||||
| kLSLaunchNewInstance;
|
||||
params.application = &ref;
|
||||
|
||||
ProcessSerialNumber psn;
|
||||
LSOpenApplication(¶ms, &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
|
||||
@@ -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
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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
|
||||
+191
-191
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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:
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
+86
-86
@@ -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));
|
||||
}
|
||||
@@ -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
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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
|
||||
+149
-149
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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()
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ OpenTptStream::~OpenTptStream()
|
||||
{
|
||||
endpoint->SetNonBlocking();
|
||||
if(connected)
|
||||
endpoint->SndDisconnect(&call);
|
||||
endpoint->SndDisconnect(&call);
|
||||
endpoint->Unbind();
|
||||
OTCloseProvider(endpoint);
|
||||
}
|
||||
|
||||
+283
-283
@@ -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(§ionHeaders[i]);
|
||||
if(sectionHeaders[i].sectionKind == kPEFLoaderSection)
|
||||
loaderHeader = §ionHeaders[i];
|
||||
}
|
||||
PEFSectionHeader *loaderHeader = NULL;
|
||||
UInt16 n = containerHeader->sectionCount;
|
||||
for(UInt16 i=0; i < n; i++)
|
||||
{
|
||||
eswap(§ionHeaders[i]);
|
||||
if(sectionHeaders[i].sectionKind == kPEFLoaderSection)
|
||||
loaderHeader = §ionHeaders[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;
|
||||
}
|
||||
+453
-453
@@ -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;
|
||||
}
|
||||
|
||||
+66
-66
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
+107
-107
@@ -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];
|
||||
|
||||
+18
-18
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
+110
-110
@@ -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;
|
||||
}
|
||||
+31
-31
@@ -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;
|
||||
}
|
||||
|
||||
+14
-14
@@ -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
|
||||
+462
-462
File diff suppressed because it is too large.
Load diff
@@ -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
|
||||
+133
-133
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
+25
-25
@@ -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)
|
||||
+13
-13
@@ -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;
|
||||
}
|
||||
+12
-12
@@ -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&);
|
||||
|
||||
+94
-94
@@ -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);
|
||||
}
|
||||
+65
-65
@@ -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
|
||||
+10
-10
@@ -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
|
||||
+105
-105
@@ -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;
|
||||
}
|
||||
+52
-52
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
||||
+212
-212
@@ -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);
|
||||
}
|
||||
}
|
||||
+73
-73
@@ -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;
|
||||
|
||||
|
||||
+124
-124
@@ -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;
|
||||
}
|
||||
+103
-103
@@ -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;
|
||||
}
|
||||
|
||||
+15
-15
@@ -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
|
||||
+244
-244
@@ -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());
|
||||
}
|
||||
@@ -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
|
||||
+25
-25
@@ -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;
|
||||
}
|
||||
+15
-15
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
||||
+89
-89
@@ -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()
|
||||
@@ -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()
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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()
|
||||
Loaded 100 of 133 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user