SUBR SONNE,SUN
SUBR BLUME,BLU
+ SUBR ABCDEF,AFFE
REL
ORG '1000
ICA
ICA
BLU LDA 0
SUN LDA 1
+AFFE CRA
END
\ No newline at end of file
\item The program shall run on any computer running GNU/Linux.
\item It has no graphical user interface but a help option and command line error reporting.
\item The program shall support and check all block types according to \cite{ser16:progref:bformats}.
-\item The Program must be able to list a tape image's contents.
+\item The program must be able to list a tape image's contents.
\item The program shall be capable of splitting tape images into single object files.
\item The program's structure must be modular and easily extendable.
\end{itemize}
\begin{itemize}
\item Possibility to split a tape image into single data block files.
\item Software handshake paper tape reader control:\\
-A paper paper tape reader connected to the computer's serial port could be motion-controlled
+A paper tape reader connected to the computer's serial port could be motion-controlled
by use of XON and XOFF characters. This is useful when error breaks for tape inspection are
enabled and the paper tape device does not support RTS/CTS hardware handshake.
\item Full POSIX.1, 2004 edition, compliance.\\
an end of tape mark is an appropriate end block.
}
-\rd{chk005}{Interactive checksum error handling}{
- The program shall be configurable to pause block processing on
- detection of a checksum error (\req{chk002}) and resume processing after
- user intervention.\\
- This feature is incompatible with data input from standard input.
-}
%*******************************************************************************
\subsection{Additional features}
of all blocks contained in the input data.\\
The output line format shall be unified for all block types.
}
+\vspace{0.5em}
+\par
+Here is an example output for the object \verb|O$PB|: \begin{verbatim}
+O$PB (0-0) Subprogram Name
+O$PS (0-0) " "
+O$PLDR (0-0) " "
+ (0-24) Switch to relocatable mode
+ (0-4) Data
+ (0-4) Data
+O$PB (0-50) Subprogram Entry Point Definition
+ (0-4) Data
+ (0-4) Data
+ (0-4) Data
+O$PLDR (0-50) Subprogram Entry Point Definition
+ (0-4) Data
+ (0-4) Data
+ (0-14) End
+\end{verbatim}
\rd{da002}{List exported symbols}{
Output a list of all exported symbols.
a zero-padded three digit number and EOT blocks are not suppressed.
}
+\rd{dp003}{Split into numbered blocks}{
+ The whole tape is split into one named and numbered file for each block.
+}
+
%*******************************************************************************
\newpage
}
\rd{err001}{Error types}{
+ The program shall react to several error conditions. Some error
+ conditions can be turned into warnings by program configuration,
+ see \req{cfg003} and \req{cfg004} for details.\\
The following distinguished error types shall exist:
\begin{itemize}
\item Input/output error:\\
- Error occuring during reading from the input file descriptor
- or during writing to an output file.\\
+ Error occuring during read from the input file descriptor
+ or during write to an output file.\\
+ No recovery from this error is possible.
\enosup
\item Block integrity error:\\
Caused by failed check according to \req{chk001}.\\
}
\rd{err002}{Program exit codes}{
- \begin{table}[H]
+ The application shall return several different exir codes to the
+ execution environment (i.e. the shell). On occurrence of any error,
+ the program shall terminate with the appropriate exit code.\\
+ Program runs with warnings shall return a special exit code.
+ \begin{table}[H]
\begin{center}
\begin{tabular}{|r|c|}
\hline
Unknown block type error & 5\\
Object integrity error & 6\\
Usage error & 7\\
+ Success with warnings & 99 \\
Internal program error & 100 \\
\hline
\end{tabular}
}
\rd{err003}{Error and warning messages}{
+ Every warning or error case shall cause an appropriate error respective
+ warning message.\\
Error messages shall consinst of ''Error:'' and the error reason.\\
Warning messages shall consist of ''Warning:'' and a descriptive
text.\\
(\req{dp001}).\\
split\_objects\_numbered & S & Split into numbered object files
(\req{dp002}).\\
+ split\_blocks & B & Split tape into named and numbered block
+ files (\req{dp003}).\\
ignore\_block\_errors & b & Ignore block integrity errors
(\req{err001},\req{chk001}).\\
ignore\_checksum\_errors & k & Ignore Checksum errors
(\req{err001}\req{chk002}).\\
- pause\_on\_checksum\_error & p & Wait for user input on checksum error
- (\req{chk005}).\\
+% pause\_on\_checksum\_error & p & Wait for user input on checksum error
+% (\req{chk005}).\\
ignore\_unknown\_block\_errors & n & Ignore errors causes by
datablocks of unknown type
(\req{err001}\req{chk003}).\\
\rd{cfg005}{Configuration file syntax}{
The configuration file must comply two the following grammar, given in EBNF:
}
+
+% | "pause_on_checksum_error"
+
\begin{verbatim}
ConfigurationFile = { ConfigurationLine "<EOL>" } ;
ConfigurationLine = SwitchLine | StringLine | CommentLine ;
CommentLine = WSpace [ "#" String ] ;
WSpace = { " " } ;
SwLong = "output_info" | "ouput_called" | "output_exported"
- | "output_unsatisfied" | "split_objects" [ _"numbered" ]
+ | "output_unsatisfied" | "split_objects" [ "_numbered" ]
+ | "split_blocks"
| "ignore_block_errors" | "ignore_checksum_errors
- | "pause_on_checksum_error"
| "ignore_unknown_block_errors"
| "ignore_object_integrity"
| "quiet" ;
BoolValue = TrueStr | FalseStr ;
String = { ? Every character except newline ?} ;
TrueStr = "yes" | "1" | "true" ;
- FalseStr = | "no" | "0" | "false" ;
+ FalseStr = "no" | "0" | "false" ;
\end{verbatim}
\rd{cfg006}{Command Line syntax}{
LongSwitch = "--" SwLong [ "=" BoolValue ] ;
ShortParam = "-" StrShort String ;
LongParam = "--" StrLong "=" String ;
- SwShort = "h" | "a" | "c" | "e" | "u" | "s" | "S"
+ SwShort = "h" | "a" | "c" | "e" | "u" | "s" | "S" | "B"
| "b" | "k" | "p" | "n" | "g" | "q";
SwLong = "help"
| "output_info" | "ouput_called" | "output_exported"
- | "output_unsatisfied" | "split_objects" [ _"numbered" ]
+ | "output_unsatisfied" | "split_objects" [ "_numbered" ]
| "ignore_block_errors" | "ignore_checksum_errors"
- | "pause_on_checksum_error"
| "ignore_unknown_block_errors"
| "ignore_object_integrity"
| "quiet" ;
StrShort = "o" ;
StrLong = "out_file" ;
\end{verbatim}
+ Some command line examples:\\
+ \verb|ldc2 -ve --output-file=out.dat in.dat|\\
+ \verb|ldc2 -kb test.obj|\\
+
+% | "pause_on_checksum_error"
\newpage
\rd{cfg007}{Configuration implications}{
\begin{itemize}
- \item \emph{pause\_on\_checksum\_errors} implies \emph{ignore\_checksum\_errors}.
- \item \emph{pause\_on\_checksum\_errors} is completely ignored when input
- is read from standard input.
- \item \emph{output\_*} and \emph{split\_*} inhibit
+% \item \emph{pause\_on\_checksum\_error} implies \emph{ignore\_checksum\_errors}.
+% \item \emph{pause\_on\_checksum\_error} is completely ignored when input
+% is read from standard input.
+ \item \emph{output\_*} inhibit
tape information output (\req{da001}).
\item \emph{help} inhibits all other actions.
\end{itemize}
int cfg_output_unsatisfied=0;
int cfg_split_objects=0;
int cfg_split_objects_numbered=0;
+int cfg_split_blocks=0;
int cfg_ignore_block_errors=0;
int cfg_ignore_checksum_errors=0;
-int cfg_pause_on_checksum_error=0;
+//int cfg_pause_on_checksum_error=0;
int cfg_ignore_unknown_block_errors=0;
int cfg_ignore_object_integrity_errors=0;
int cfg_list_contents=1;
int cfg_version=0;
int in_fd=0; //! File descriptor for data input
-int out_fd=2; //! File descriptor for text output
+int out_fd=1; //! File descriptor for text output
void do_config(int argc, char ** args){
"List all unsatisfied symbols.",
&cfg_output_unsatisfied,true,true);
- ar.add_option_switch("S","split_objects_numbered",
- "Split input data into distinct numbered files",
- &cfg_split_objects_numbered,true,true);
-
ar.add_option_switch("s","split_objects",
"Split input data into distinct object files.",
&cfg_split_objects,true,true);
+ ar.add_option_switch("S","split_objects_numbered",
+ "Split input data into distinct numbered files",
+ &cfg_split_objects_numbered,true,true);
+
+ ar.add_option_switch("B","split_blocks",
+ "Split tape into named and numbered block files",
+ &cfg_split_blocks,true,true);
+
ar.add_option_switch("b","ignore_block_errors",
"Ignore block integrity errors. This will output broken blocks,too",
&cfg_ignore_block_errors,true,true);
"Ignore block checksum errors. Errors will be converted to warnings.",
&cfg_ignore_checksum_errors,true,true);
- ar.add_option_switch("p","pause_on_checksum_error",
- "Wait for user input on checksum error.",
- &cfg_pause_on_checksum_error,true,true);
+// ar.add_option_switch("p","pause_on_checksum_error",
+// "Wait for user input on checksum error.",
+// &cfg_pause_on_checksum_error,true,true);
ar.add_option_switch("n","ignore_unknown_block_errors",
"Ignore errors caused by unknown block types. Errors will be converted to warnings.",
if (cfg_verbose)cfg_quiet=0;
// The configuration implications according to /cfg007/
- if (in_fd==0) cfg_pause_on_checksum_error=0;
- if (cfg_pause_on_checksum_error==1) cfg_ignore_checksum_errors=1;
+ // if (in_fd==0) cfg_pause_on_checksum_error=0;
+ // if (cfg_pause_on_checksum_error==1) cfg_ignore_checksum_errors=1;
if (cfg_output_info||cfg_output_called||cfg_output_exported||
- cfg_output_unsatisfied||
- cfg_split_objects||cfg_split_objects_numbered)
- cfg_list_contents=0;
+ cfg_output_unsatisfied) cfg_list_contents=0;
}
extern int cfg_output_unsatisfied;
extern int cfg_split_objects;
extern int cfg_split_objects_numbered;
+extern int cfg_split_blocks;
extern int cfg_ignore_block_errors;
extern int cfg_ignore_checksum_errors;
extern int cfg_pause_on_checksum_error;
vector<string> data_block_0_0::get_exported_symbols(){
return get_labels();
}
-
return result;
}
+/***************************************************************/
+/*!
+ *\brief Determine if the block marks the end of an object
+ *\return true because this block is an end block.
+ */
+bool data_block_0_3::is_endblock(){
+ return true;
+}
+
void(*)(void*),void*);
public:
vector<string> get_description();
+ bool is_endblock();
protected:
data_block_0_3(data_block_0&);
vector<string> data_block_0_label_extractor::get_labels(){
int l_count=word_size/3-1;
vector<string> result;
- for (int l_no=0; l_no<l_count;l_no++)
- result.insert(result.end(),extract_label(4+6*l_no));
+ for (int l_no=0; l_no<l_count;l_no++){
+ string r1=extract_label(4+6*l_no);
+ if (r1!=" ") result.insert(result.end(),r1);
+ }
return result;
}
return result;
}
-/***************************************************************/
-/*!
- *\brief Determine if the block marks the end of an object
- *\return true because this block is an end block.
- */
-bool data_block_3::is_endblock(){
- return true;
-}
-
public:
vector<string> get_description();
- bool is_endblock();
};
#endif
return result;
}
-/***************************************************************/
-/*!
- *\brief Determine if the block marks the end of an object
- *\return true because this block is an end block.
- */
-bool data_block_4::is_endblock(){
- return true;
-}
-
public:
vector<string> get_description();
- bool is_endblock();
};
#endif
*/
vector<string> data_block_6::get_exported_symbols(){
vector<string> result;
- result.insert(result.end(),extract_label(3));
+ string rs=extract_label(3);
+ if (rs!=" ") result.insert(result.end(),rs);
return result;
}
+$Header: /var/lib/cvs/h316/pc-tools/ldc2/src/data_block_7.cpp,v 1.6 2007/03/26 00:45:12 hachti Exp $
+
#include "data_block_7.hh"
/*!
/* ldc2 preliminary main program */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
#include <vector>
#include <string>
if (error) fprintf(stderr,message.c_str());
if (warning) fprintf(stdwarn,message.c_str());
-
- if(cfg_list_contents){
+
+ if(error||warning){
dump_vector(block->get_description());
- if (!error&&!warning) spaced=false;
+ } else {
+ if(cfg_list_contents){
+ FILE * tmp_fp=fdopen(out_fd,"w");
+ dump_vector_fp(block->get_description(),tmp_fp);
+ if (!error&&!warning) spaced=false;
+ }
}
if (error||warning||cfg_verbose){
}
} // read_tape()
+
/******************************************************************************/
+void process_tape(){
+ if (cfg_verbose) fprintf(stdwarn,"Processing Tape.\n");
+
+ bool in_object=false;
+ char filename[100];
+ char filename_numbered[100];
+ string objname;
+ int unknown_count=-1;
+ int fd=-1, fd_numbered=-1;
+ int obj_no=0;
+ int obj_start_block;
+
+ for (unsigned int i=0; i<tape.size();i++){
+ tape_block * block=tape[i];
+
+ if (block->get_type()==tape_block::TBT_EOT){
+ objname="EOT";
+ if (in_object){
+ if (cfg_ignore_object_integrity_errors){
+ fprintf(stdwarn,"Warning: Object integrity error!\n");
+ warnings++;
+ } else {
+ fprintf(stderr,"Error: Object integrity error!\
+ (Object no %i, Block %i unexpected)\n",obj_no,i);
+ errors++;
+ errcode=6;
+ return;
+ }
+ }
+ }
+
+ if (!in_object){ // object begin
+ obj_no++;
+ obj_start_block=i;
+
+ objname="UNKNOWN";
+ unknown_count++;
+
+ vector<string>names=block->get_exported_symbols();
+ for (unsigned int a=0; a<names.size();a++){
+ objname=names[0];
+ if (objname!=" "){
+ objname=objname.substr(0,objname.find_last_not_of(" ")+1);
+ unknown_count--;
+ break;
+
+ }
+ }
+
+ if (block->get_type()==tape_block::TBT_EOT){
+ objname="EOT";
+ }
+
+ // Open file for split objects
+ if (cfg_split_objects && (block->get_type()!=tape_block::TBT_EOT)){
+ if (objname=="UNKNOWN")snprintf(filename,99,"UNKNOWN%02i.obj",unknown_count);
+ else snprintf(filename,99,"%s.obj",objname.c_str());
+ if (fd>-1) close (fd);
+ fd=open(filename,O_WRONLY|O_CREAT|O_TRUNC,0666);
+ printf("opening \"%s\"\n",filename);
+ if (fd<0){
+ fprintf(stderr,"Error: could not open file \"%s\" for writing!\n",
+ filename);
+ exit (1);
+ }
+ }
+
+ // Open file for split objects numbered
+ snprintf(filename_numbered,99,"%03i0-%s.obj",obj_no,objname.c_str());
+ if (cfg_split_objects_numbered){
+ if (fd_numbered>-1) close (fd_numbered);
+ fd_numbered=open(filename_numbered,O_WRONLY|O_CREAT|O_TRUNC,0666);
+ if (fd_numbered<0){
+ fprintf(stderr,"Error: could not open file \"%s\" for writing!\n",
+ filename_numbered);
+ exit (1);
+ }
+ }
+ in_object=true;
+ } // object begin
+
+ // Output block data
+ if (cfg_split_objects){
+ try{
+ if (block->get_type()!=tape_block::TBT_EOT) // Don't want EOT here
+ block->dump_to_fd(fd);
+ }
+ catch (tape_block::io_error_exception e){
+ fprintf(stderr,"Error: could write to file \"%s\"!\n",
+ filename);
+ exit (1);
+ }
+ } // if (cfg_split_objects)
+
+ // Output block data
+ if (cfg_split_objects_numbered){
+ try{
+ block->dump_to_fd(fd_numbered);
+ }
+ catch (tape_block::io_error_exception e){
+ fprintf(stderr,"Error: could write to file \"%s\"!\n",
+ filename_numbered);
+ exit (1);
+ }
+ } // if (cfg_split_objects_numbered)
+
+ // Output individual block file if desired
+ if (cfg_split_blocks){
+ char fname[100];
+ snprintf(fname,99,"%03i0-%s-%03i.block",obj_no,objname.c_str(),i-obj_start_block);
+ int fd_block=open(fname,O_WRONLY|O_TRUNC|O_CREAT,0666);
+ if (fd_block<0){
+ fprintf(stderr,"Error: could not open file \"%s\" for writing!\n",
+ fname);
+ exit (1);
+ }
+ try{
+ block->dump_to_fd(fd_block);
+ }
+ catch (tape_block::io_error_exception e){
+ fprintf(stderr,"Error: could write to file \"%s\"!\n",
+ fname);
+ exit (1);
+ }
+ close(fd_block);
+ }
+
+ if (block->is_endblock()||(block->get_type()==tape_block::TBT_EOT)) {
+ in_object=false;
+ if (fd!=-1) close(fd);
+ if (fd_numbered!=-1) close(fd_numbered);
+ }
+ } // for (...)
+
+ if (in_object){
+ if (cfg_ignore_object_integrity_errors){
+ fprintf(stdwarn,"Warning: Object integrity error!\n");
+ warnings++;
+ } else {
+ fprintf(stdwarn,"Error: Object integrity error!\n");
+ errors++;
+ errcode=6;
+ return;
+ }
+ }
+
-void type_check(){
- bool warning=false;
- bool error=false;
+} // process_tape()
+void process_called_imports(){
+ vector<string>exported;
+ vector<string>called;
+ vector <string>unsatisfied;
+
for (unsigned int i=0; i<tape.size();i++){
- bool spaced=false;
- if (!tape[i]->has_known_type()){
- FILE * fp;
- if (cfg_ignore_unknown_block_errors){
- fp=stdwarn;
- warning=true;
- } else {
- fp=stderr;
- error=true;
- }
- if (!spaced) {
- spaced=false;fprintf(fp,"\n");
- fprintf(fp,"Warning: Unknown Block type! Block No.%i\n",i);
- dump_vector_fp(tape[i]->get_description(),fp);
- fprintf(fp,"\n");
- spaced=true;
- }
- if (!cfg_ignore_unknown_block_errors){
- int errcode=5;
- fprintf(stdwarn,"Failed. (%i)\n",errcode);
- exit(errcode);
+ merge_vector_unique(exported,tape[i]->get_exported_symbols());
+ merge_vector_unique(called,tape[i]->get_called_symbols());
+ }
+
+ for (unsigned int icalled=0;icalled<called.size();icalled++){
+ bool found=false;
+ for (unsigned int iexported=0;iexported<exported.size();iexported++){
+ if (exported[iexported].compare(called[icalled])==0){
+ found=true;
+ break;
}
}
+ if (!found) {
+ bool present=false;
+ for (unsigned int i=0;i<unsatisfied.size();i++){
+ if (unsatisfied[i].compare(called[icalled])==0){
+ present=true;
+ break;
+ }
+ }
+ if (!present) unsatisfied.insert(unsatisfied.end(),called[icalled]);
+ }
}
-} // type_check()
+
+ FILE * outp=fdopen(out_fd,"w");
+
+ if (cfg_output_called){
+ dump_vector_fp(called,outp);
+ }
+
+ if (cfg_output_exported){
+ dump_vector_fp(exported,outp);
+ }
+
+ if (cfg_output_unsatisfied){
+ dump_vector_fp(unsatisfied,outp);
+ }
+
+}
/******************************************************************************/
/*!
*/
int main(int argc, char ** args){
-
// Do all the configuration stuff
do_config(argc,args);
read_tape(); // Process input to completion.
exit_on_error();
+ process_tape();
+ exit_on_error();
+
+ process_called_imports();
+ exit_on_error();
- if (cfg_split_objects){
- for (unsigned int i=0; i<tape.size();i++){
- tape[i]->dump_to_fd(out_fd);
- }
+ if (warnings>0){
+ fprintf(stdwarn,"Warnings:%i\n",warnings);
+ return 99;
}
-
-
+ if (cfg_verbose) fprintf(stdwarn,"Success.\n");
return 0;
} // main()
case 001: n_data_block_0_x=new data_block_0_1(*n_data_block_0); break;
case 002: n_data_block_0_x=new data_block_0_2(*n_data_block_0); break;
case 003: n_data_block_0_x=new data_block_0_3(*n_data_block_0); break;
- // case 004: n_data_block_0_x=new data_block_0_4(*n_data_block_0); break;
+ case 004: n_data_block_0_x=new data_block_0_4(*n_data_block_0); break;
case 010: n_data_block_0_x=new data_block_0_10(*n_data_block_0); break;
case 014: n_data_block_0_x=new data_block_0_14(*n_data_block_0); break;
case 024: n_data_block_0_x=new data_block_0_24(*n_data_block_0); break;
using namespace std;
-/*!
- *\brief Output a vector of strings to out_fd.
- *\arg strings A vector containing text.
- *\retval 0 The vector was empty.
- *\retval 1 The vector contained text.
- */
-int dump_vector(vector<string> strings){
- int res=0;
- for (vector<string>::iterator iter=strings.begin();iter<strings.end();iter++){
- char buffer[50000];
- snprintf(buffer,50000,"%s\n",(*iter).c_str());
- write (out_fd,buffer,strlen(buffer));
- res=1;
- }
- return res;
-}
/*!
*\brief Output a vector of strings.
int dump_vector_fp(vector<string> strings, FILE * fp){
int res=0;
for (vector<string>::iterator iter=strings.begin();iter<strings.end();iter++){
- fprintf(fp,"%s\n",(*iter).c_str());
+ fprintf(fp,"%s\n",
+ iter->substr(0,iter->find_last_not_of(" ")+1).c_str());
res=1;
}
return res;
}
/*!
- *\brief add contents of one vector to another vector uniquely.
- *\param target Reference to the target vector.
- *\param source Reference to the vector whose contents are to be added
- * to target.
+ *\brief Output a vector of strings to out_fd.
+ *\arg strings A vector containing text.
+ *\retval 0 The vector was empty.
+ *\retval 1 The vector contained text.
*/
-template<typename T>
-void merge_vector_unique(vector<T> &target, const vector<T> & source){
- for (unsigned int isource=0; isource<source.size();isource++){
- bool already_present=false;
- for (int itarget=0;itarget<target.size();itarget++)
- if (target[itarget]==source[isource]){
- already_present=true;
- break;
- }
- if (!already_present) target.insert(target.end().source[isource]);
- }
+int dump_vector(vector<string> strings){
+ FILE * fp=fdopen(out_fd,"w");
+ return dump_vector_fp(strings,fp);
}
extern int dump_vector(vector<string> strings);
extern int dump_vector_fp(vector<string> strings, FILE * fp);
-template<typename T>
-extern void merge_vector_unique(vector<T> &target, const vector<T> & source);
+/*!
+ *\brief add contents of one vector to another vector uniquely.
+ *\param target Reference to the target vector.
+ *\param source Reference to the vector whose contents are to be added
+ * to target.
+ */
+template<typename T>
+void merge_vector_unique(vector<T> &target, const vector<T> & source){
+ for (unsigned int isource=0; isource<source.size();isource++){
+ bool already_present=false;
+ for (unsigned int itarget=0;itarget<target.size();itarget++)
+ if (target[itarget]==source[isource]){
+ already_present=true;
+ break;
+ }
+ if (!already_present) target.insert(target.end(),source[isource]);
+ }
+}
#endif