/*
Includes a main function that reads the name of an LC-3 object file
from the command line, then parses the file and passes the instructions
in the file to the disassemble function for disassembly.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
static const int MAX_FILE_NAME_LEN = 250;
/*Exit Conditions*/
enum {
EXIT_SUCCEED = 0,
EXIT_FAIL = 1,
EXIT_BAD_ARGS = 2,
EXIT_PANIC = 3
};
/*
The arguments to main are taken from the command line.
The second paramater, argv, is an array of strings, with each string
corresponding to one of the space-separated "words" on the command
line. The first element of this array is the command's name,
and the others are the arguments. The first argument, argc, is
a count of the number of elements in the argv array.
*/
int main (int argc, char** argv)
{
int len; /* length of given file name */
char filename[MAX_FILE_NAME_LEN + 5]; /* private copy of file name */
struct stat obj_stats; /* object file statistics */
int num_words; /* number of instructions */
unsigned short* inst; /* pointer to instructions */
FILE* obj_file; /* the object file */
unsigned char buf[4]; /* a buffer for reading */
int begin_addr; /* the code's starting address */
int inst_count; /* count of instructions read */
/* Check command line syntax. */
if (argc != 2) {
fprintf (stderr, "syntax: %s <object file>\n", argv[0]);
return EXIT_BAD_ARGS;
}
/* Check length of object file name. */
len = strlen (argv[1]);
if (len < 1 || len > MAX_FILE_NAME_LEN) {
fputs ("object file name too short or long\n", stderr);
return EXIT_BAD_ARGS;
}
/* Make a copy of the object file name in the filename variable.
If no extension appears in the file name, add .obj. */
strcpy (filename, argv[1]);
if (strrchr (filename, '.') == NULL)
strcpy (filename + len, ".obj");
/* Check how many instructions are in the object file. The first
word is the starting address, which we handle separately. */
if (stat (filename, &obj_stats) == -1) {
/* Type in the name of a non-existent file to see the
error message generated by this library routine. */
perror ("Could not determine object file length");
return EXIT_BAD_ARGS;
}
num_words = (obj_stats.st_size / sizeof (*inst)) - 1;
if ((obj_stats.st_size % sizeof (*inst) != 0) ||
num_words < 1 || num_words > 65536) {
fprintf (stderr, "%s does not seem to be an LC-3 object file.\n",
filename);
return EXIT_BAD_ARGS;
}
/* Dynamically allocate an array of unsigned short integers to hold
the instructions. If we don't have enough memory, give up. */
inst = malloc (num_words * sizeof (*inst));
if (inst == NULL) {
perror ("Dynamic allocation failed");
return EXIT_PANIC;
}
/* Open the object file. */
obj_file = fopen (filename, "r");
if (obj_file == NULL) {
perror ("Open object file");
return EXIT_BAD_ARGS;
}
if (fread (buf, sizeof (*inst), 1, obj_file) != 1) {
fputs ("Could not read all instructions.\n", stderr);
return EXIT_PANIC;
}
begin_addr = (buf[0] << 8) | buf[1];
/* Finally, read the instructions and close the file. */
for (inst_count = 0; inst_count < num_words; inst_count++) {
if (fread (buf, sizeof (*inst), 1, obj_file) != 1) {
fputs ("Could not read all instructions.\n", stderr);
return EXIT_PANIC;
}
inst[inst_count] = (buf[0] << 8) | buf[1];
}
fclose (obj_file);
/* Disassemble the instructions.
This function calls on the second source file which disassembles the
code*/
disassemble (begin_addr, num_words, inst);
/* We're done. */
return EXIT_SUCCEED;
}