Skip to content

Commit 2d8c938

Browse files
committed
Allow shebang line in overlays.
1 parent 45c74e0 commit 2d8c938

File tree

7 files changed

+73
-22
lines changed

7 files changed

+73
-22
lines changed

disk.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@
3535
//
3636
// Open binary image as disk.
3737
//
38-
Disk::Disk(Word id, Memory &m, const std::string &p, bool wp)
39-
: volume_id(id), memory(m), path(p), write_permit(wp)
38+
Disk::Disk(Word id, Memory &m, const std::string &p, bool wp, unsigned offset)
39+
: volume_id(id), memory(m), path(p), write_permit(wp), file_offset(offset)
4040
{
4141
// Open file.
4242
int open_flag = write_permit ? O_RDWR : O_RDONLY;
@@ -155,7 +155,8 @@ void Disk::simh_to_memory(unsigned zone, unsigned sector, unsigned addr, unsigne
155155
8 + // skip OS info
156156
(256 * sector); // sector offset
157157

158-
if (lseek(file_descriptor, offset_nwords * sizeof(Word), SEEK_SET) < 0)
158+
unsigned offset_bytes = offset_nwords * sizeof(Word) + file_offset;
159+
if (lseek(file_descriptor, offset_bytes, SEEK_SET) < 0)
159160
throw std::runtime_error("Disk seek error");
160161

161162
Word *destination = memory.get_ptr(addr);
@@ -186,7 +187,8 @@ void Disk::memory_to_simh(unsigned zone, unsigned sector, unsigned addr, unsigne
186187
8 + // skip OS info
187188
(256 * sector); // sector offset
188189

189-
if (lseek(file_descriptor, offset_nwords * sizeof(Word), SEEK_SET) < 0)
190+
unsigned offset_bytes = offset_nwords * sizeof(Word) + file_offset;
191+
if (lseek(file_descriptor, offset_bytes, SEEK_SET) < 0)
190192
throw std::runtime_error("Disk seek error");
191193

192194
Word *source = memory.get_ptr(addr);
@@ -203,7 +205,7 @@ void Disk::file_to_memory(unsigned zone, unsigned sector, unsigned addr, unsigne
203205
if (zone >= num_zones)
204206
throw std::runtime_error("Zone number exceeds file size");
205207

206-
unsigned offset_bytes = (4 * zone + sector) * PAGE_NBYTES / 4;
208+
unsigned offset_bytes = (4 * zone + sector) * PAGE_NBYTES / 4 + file_offset;
207209
if (lseek(file_descriptor, offset_bytes, SEEK_SET) < 0)
208210
throw std::runtime_error("File seek error");
209211

@@ -235,7 +237,7 @@ void Disk::memory_to_file(unsigned zone, unsigned sector, unsigned addr, unsigne
235237
if (zone >= num_zones)
236238
throw std::runtime_error("Zone number exceeds file size");
237239

238-
unsigned offset_bytes = (4 * zone + sector) * PAGE_NBYTES / 4;
240+
unsigned offset_bytes = (4 * zone + sector) * PAGE_NBYTES / 4 + file_offset;
239241
if (lseek(file_descriptor, offset_bytes, SEEK_SET) < 0)
240242
throw std::runtime_error("File seek error");
241243

disk.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,12 @@ class Disk {
4141
int file_descriptor;
4242
unsigned num_zones;
4343

44+
// Skip so many bytes at the beginning of the file.
45+
unsigned file_offset{};
46+
4447
public:
4548
// Constructor throws exception if the file cannot be opened.
46-
Disk(Word id, Memory &memory, const std::string &path, bool write_permit);
49+
Disk(Word id, Memory &memory, const std::string &path, bool write_permit, unsigned offset = 0);
4750
Disk(Word id, Memory &memory, const std::string &pattern, unsigned num_zones);
4851

4952
// Clone the disk.

machine.cpp

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -465,7 +465,7 @@ unsigned Machine::file_search(Word disc_id, Word file_name, bool write_mode)
465465
// Return error code.
466466
// In case of success return zero.
467467
//
468-
unsigned Machine::file_mount(unsigned disk_unit, unsigned file_index, bool write_mode)
468+
unsigned Machine::file_mount(unsigned disk_unit, unsigned file_index, bool write_mode, unsigned file_offset)
469469
{
470470
if (disk_unit < 030 || disk_unit >= 070)
471471
throw std::runtime_error("Invalid disk unit " + to_octal(disk_unit) + " in file_mount()");
@@ -492,7 +492,7 @@ unsigned Machine::file_mount(unsigned disk_unit, unsigned file_index, bool write
492492
return E57_NO_ACCESS;
493493
}
494494
}
495-
disks[disk_unit - 030] = std::make_unique<Disk>(0, memory, path, write_mode);
495+
disks[disk_unit - 030] = std::make_unique<Disk>(0, memory, path, write_mode, file_offset);
496496
if (bin_created && !write_mode) {
497497
// Remove binary image of the disk when finished.
498498
disks[disk_unit - 030]->remove_when_finished();
@@ -768,8 +768,9 @@ void Machine::boot_ms_dubna(const std::string &path)
768768

769769
//
770770
// Check for binary program (overlay).
771+
// Return file offset for shebang.
771772
//
772-
bool Machine::is_overlay(const std::string &filename)
773+
bool Machine::is_overlay(const std::string &filename, unsigned *file_offset_ptr)
773774
{
774775
// Open binary file.
775776
std::ifstream file(filename, std::ios_base::binary);
@@ -778,17 +779,33 @@ bool Machine::is_overlay(const std::string &filename)
778779
return false;
779780
}
780781

782+
// Check for shebang line.
783+
std::string line(512, '\0');
784+
if (!file.read(&line[0], line.size())) {
785+
return false;
786+
}
787+
*file_offset_ptr = 0;
788+
if (line[0] == '#' && line[1] == '!') {
789+
// Shebang found: determine offset to actual overlay binary.
790+
auto newline = line.find('\n');
791+
if (newline == std::string::npos) {
792+
// Too long line.
793+
return false;
794+
}
795+
*file_offset_ptr = newline + 1;
796+
}
797+
781798
// Check file size.
782799
file.seekg(0, std::ios_base::end);
783-
auto nbytes = file.tellg();
800+
auto nbytes = file.tellg() - (off_t)*file_offset_ptr;
784801
if (nbytes / PAGE_NBYTES < 2 || nbytes % PAGE_NBYTES != 0) {
785802
// Must be a multiple of the page size.
786803
return false;
787804
}
788805

789806
// Check magic word OVERLA at fixed offset.
790807
std::string word(6, '\0');
791-
file.seekg(01762 * 6, std::ios_base::beg);
808+
file.seekg(01762 * 6 + *file_offset_ptr, std::ios_base::beg);
792809
if (!file.read(&word[0], word.size())) {
793810
return false;
794811
}
@@ -798,7 +815,7 @@ bool Machine::is_overlay(const std::string &filename)
798815
}
799816

800817
// Check base address of the binary.
801-
file.seekg(6, std::ios_base::beg);
818+
file.seekg(6 + *file_offset_ptr, std::ios_base::beg);
802819
if (!file.read(&word[0], word.size())) {
803820
return false;
804821
}
@@ -812,7 +829,7 @@ bool Machine::is_overlay(const std::string &filename)
812829
//
813830
// Load binary program (overlay).
814831
//
815-
void Machine::boot_overlay(const std::string &filename, const std::string &path)
832+
void Machine::boot_overlay(const std::string &filename, unsigned file_offset, const std::string &path)
816833
{
817834
// Mount tape 9/monsys as disk 30, read only.
818835
disk_search_path = path;
@@ -823,7 +840,7 @@ void Machine::boot_overlay(const std::string &filename, const std::string &path)
823840

824841
// Open overlay as disk 60, read only.
825842
file_paths.push_back(filename);
826-
file_mount(060, file_paths.size(), false);
843+
file_mount(060, file_paths.size(), false, file_offset);
827844

828845
// clang-format off
829846
memory.store(02000, besm6_asm("*70 3000, utc")); // читаем таблицу резидентных программ для загрузчика

machine.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ class Machine {
192192
unsigned disk_find(Word tape_id);
193193
void scratch_mount(unsigned disk_unit, unsigned num_zones);
194194
unsigned file_search(Word disc_id, Word file_name, bool write_mode);
195-
unsigned file_mount(unsigned disk_unit, unsigned file_index, bool write_mode);
195+
unsigned file_mount(unsigned disk_unit, unsigned file_index, bool write_mode, unsigned file_offset = 0);
196196

197197
// Drum i/o.
198198
void drum_io(char op, unsigned drum_unit, unsigned zone, unsigned sector, unsigned addr,
@@ -213,10 +213,11 @@ class Machine {
213213
void print_iso_string(std::ostream &out, unsigned addr);
214214

215215
// Check for binary program (overlay).
216-
bool is_overlay(const std::string &filename);
216+
// Return file offset for shebang.
217+
bool is_overlay(const std::string &filename, unsigned *file_offset_ptr);
217218

218219
// Load binary program (overlay).
219-
void boot_overlay(const std::string &filename, const std::string &path = "");
220+
void boot_overlay(const std::string &filename, unsigned file_offset, const std::string &path = "");
220221

221222
//
222223
// Trace methods.

session.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,9 @@ class Session::Hidden {
9191
void run()
9292
{
9393
try {
94-
if (machine.is_overlay(job_file)) {
95-
run_overlay();
94+
unsigned file_offset{};
95+
if (machine.is_overlay(job_file, &file_offset)) {
96+
run_overlay(file_offset);
9697
} else {
9798
run_script();
9899
}
@@ -152,10 +153,10 @@ class Session::Hidden {
152153
//
153154
// Run simulation session with given parameters.
154155
//
155-
void run_overlay()
156+
void run_overlay(unsigned file_offset)
156157
{
157158
// Load binary program.
158-
machine.boot_overlay(job_file);
159+
machine.boot_overlay(job_file, file_offset);
159160

160161
// Run simulation.
161162
machine.run();

tests/cli_test.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,3 +179,30 @@ TEST(cli, overlay_exe)
179179

180180
EXPECT_EQ(output, " HELLO, ALGOL!\n");
181181
}
182+
183+
//
184+
// Run overlay which has shebang line prepended, like "#!/usr/bin/env dubna".
185+
//
186+
TEST(cli, shebang_exe)
187+
{
188+
std::string command_line = BUILD_DIR "/dubna " TEST_DIR "/shebang.exe";
189+
190+
// Set path to the disk images.
191+
EXPECT_EQ(setenv("BESM6_PATH", TEST_DIR "/../tapes", 1), 0);
192+
193+
// Run simulator via shell.
194+
FILE *pipe = popen(command_line.c_str(), "r");
195+
ASSERT_TRUE(pipe != nullptr);
196+
197+
// Capture the output as vector of strings.
198+
auto output = stream_contents(pipe);
199+
std::cout << output;
200+
201+
// Check exit code.
202+
int exit_status = pclose(pipe);
203+
int exit_code = WEXITSTATUS(exit_status);
204+
ASSERT_NE(exit_status, -1);
205+
ASSERT_EQ(exit_code, 0);
206+
207+
EXPECT_EQ(output, " HELLO, ALGOL!\n");
208+
}

tests/shebang.exe

12 KB
Binary file not shown.

0 commit comments

Comments
 (0)