// ibm1130_fmt.c : interpret tabs in 1130 Assembler or Fortran source | |
// Bob Flanders | |
// ------------------------------------------------------------------------------------------- | |
// | |
// These routines are used by ibm1130_cr.c when the user has indicated | |
// that the input text is formatted with tabs. Input lines are edited | |
// into the appropriate column format. Three edit modes are recognized: | |
// | |
// Assembler mode: | |
// Input lines of the form | |
// | |
// [label]<whitespace>[opcode]<tab>[tag][L]<tab>[argument] | |
// | |
// are rearranged so that the input fields are placed in the appropriate columns | |
// | |
// The label must start on the first character of the line. If there is no label, | |
// the first character(s) before the opcode must be whitespace. Following the opcode, there | |
// MUST be a tab character, followed by the format and tag. Following the format and tag | |
// may be exactly one whitespace character, and then starts the argument. | |
// | |
// Input lines with * in column 1 and blank lines are turned into Assembler comments, | |
// with the * in the Opcode field. | |
// | |
// Assembler directive lines at the beginning of the deck must be preceded by | |
// ! to indicate that they are not comments. For example, | |
// | |
// !*LIST | |
// * This is a comment | |
// | |
// Fortran mode: | |
// Input lines of the form | |
// | |
// [label]<tab>statement | |
// | |
// or | |
// | |
// [label]<tab>Xcontinuation | |
// | |
// where X is a non alphabetic contination character are rearranged in the | |
// appropriate manner: | |
// | |
// 1 2 | |
// 12345678901234567890... | |
// ------------------------ | |
// label statement | |
// labelXcontinuation | |
// | |
// However, you must take care that you don't end up with statement text after column 72. | |
// | |
// Input lines with * or C in column 1 are left alone (comments and directives) | |
// | |
// (The ! escape is not used before Fortran directives as before Assembler directives) | |
// | |
// Tab mode: | |
// Tabs are replaced with spaces. Tab settings are assumed to be eight characters wide, | |
// as is standard for vi, notepad, etc. | |
// ------------------------------------------------------------------------------------------- | |
#include <stdio.h> | |
#include <string.h> | |
#include <stdlib.h> | |
#include <memory.h> | |
#include <ctype.h> | |
#include "ibm1130_fmt.h" | |
#define MAXLINE 81 // maximum output line size | |
#define WORKSZ 256 // size for tab work area | |
#define TAGOFFSET 12 // offset for tag field | |
#define FMTOFFSET 11 // offset for format field | |
#define MIN(a,b) ((a < b) ? a : b) | |
#define AMSG " with Assembler Reformat" | |
#define FMSG " with FORTRAN Reformat" | |
#define AFORMAT "%20.20s%-60.60s"," " | |
#define ACOMMENTFMT "%20.20s%-60.60s"," " | |
#define ABLANKLINE "%20.20s*"," " | |
#define FFORMAT "%-5.5s %-74.74s" | |
#define FCONTFMT "%-5.5s%-75.75s" | |
char gszLabel[6]; // work area for label | |
char gszArg[MAXLINE]; // .. argument | |
char gszOutput[MAXLINE]; // .. output | |
short gaiAsmTabs[] = {7,12,15,20,25,30,35,40,45,52,0};// tab stops for assembler | |
short gaiPlainTabs[] = {9, 17, 25, 33, 41, 49, 57, 65, 73, 0};// tab stops for just plain tabs | |
// /////////////// | |
// helper routines | |
/////////////////////////////////////////////////// | |
// ExpandTabs: Expand tabs to spaces | |
char* ExpandTabs(char* p_szInbuf, // expand tabs .. input buffer | |
char* p_szOutbuf, // .. output buffer | |
short* p_aiTabs) // .. array of tab stops (1 based) -- 0 end of array | |
{ | |
short iI, // input position | |
iO, // output position | |
iT; // next tab stop | |
char cX; // character to test | |
iI = 0; // init input position | |
iO = 0; // init output position | |
iT = 0; // init tab stop | |
while (cX = *(p_szInbuf + iI)) // while there are characters | |
{ | |
if (cX == '\t') // q. tab character? | |
{ // a. yes .. | |
while ((p_aiTabs[iT] <= iO + 1) // search for next valid stop .. | |
&& (p_aiTabs[iT] != 0)) // .. or end of table | |
iT++; // .. go to next tab | |
if (p_aiTabs[iT] != 0) // q. end of tab array? | |
{ // a. no .. | |
while (iO < (p_aiTabs[iT] - 1)) // fill to tab with blanks | |
*(p_szOutbuf + iO++) = ' '; // .. put in a blank | |
} | |
else // Otherwise ... | |
*(p_szOutbuf + iO++) = ' '; // .. Translate to blank | |
} | |
else // Otherwise .. not tab | |
*(p_szOutbuf + iO++) = cX; // .. save the input char | |
iI++; // next input character | |
} | |
*(p_szOutbuf + iO) = 0; // end the string.. | |
return p_szOutbuf; // .. return output area addr | |
} | |
///////////////////////////////////// | |
// extract next token, modify pointer | |
char* GetToken(char* p_szOut, // output location | |
int p_iLen, // max output length | |
char**p_pszToken) // pointer to input token | |
{ | |
int iI; // work integer | |
char* pszX; // work pointer | |
pszX = *p_pszToken; // get pointer to token | |
for (iI = 0; *(pszX + iI) && (!isspace(*(pszX + iI)));) // while not whitespace & not end | |
iI++; // .. count token length | |
memset(p_szOut, 0, p_iLen); // zero out output area | |
if (iI > 0) // q. any chars? | |
strncpy(p_szOut, *p_pszToken, MIN(iI, p_iLen-1)); // a. yes.. copy max of p_iLen-1 | |
*p_pszToken += iI; // point beyond token | |
return p_szOut; // .. return token pointer | |
} | |
///////////////////////////////////////////////////////// | |
// EditToAsm - convert tab-formatted text line to 1130 Assembler format | |
char *EditToAsm (char* p_pszEdit) // convert line to 1130 assembler | |
{ | |
char pszLine[MAXLINE]; // source line | |
char pszWork[WORKSZ]; // work buffer | |
char acTFWrk[2]; // tag/format work area | |
size_t iI; // work integer | |
if (p_pszEdit == NULL) // q. null request? | |
return AMSG; // a. yes .. return display message | |
if (*p_pszEdit == '!') // leave lines starting with ! alone | |
return EditToWhitespace(p_pszEdit+1); | |
if (*p_pszEdit == '*') // q. comment line? | |
{ // a. yes.. | |
strncpy(pszWork, EditToWhitespace(p_pszEdit), MAXLINE); // .. convert any tabs | |
sprintf(gszOutput, ACOMMENTFMT, pszWork); // .. put the comment out there in the opcode column | |
return gszOutput; // .. and return it | |
} | |
strncpy(pszLine, p_pszEdit, MAXLINE-1); // copy the line local | |
ExpandTabs(pszLine, pszWork, gaiAsmTabs); // expand the tabs | |
strncpy(pszLine, pszWork, MAXLINE-1); // copy the line back | |
for (iI = strlen(pszLine); iI--;) // trim trailing whitespace | |
{ | |
if (*(pszLine + iI) <= ' ') // q. space or less? | |
*(pszLine + iI) = 0; // a. yes .. remove it | |
else // otherwise | |
break; // .. done. Leave loop. | |
} | |
if (strlen(pszLine) == 0) // q. blank line? | |
{ // a. yes .. Assembler abhors these so | |
sprintf(gszOutput, ABLANKLINE); // format as comment statement | |
return gszOutput; // .. and return it | |
} | |
// TODO: Add code to process a strip switch | |
// comment? | |
if (strlen(pszLine) > (TAGOFFSET + 1)) // q. line long enough? | |
{ // a. yes.. reorder tag/format | |
memcpy(acTFWrk, pszLine + FMTOFFSET, 2); // get tag/format | |
memset((pszLine + FMTOFFSET), ' ', 2); // .. blank 'em out | |
for (iI = 0; iI < 2; iI ++) | |
if (isalpha(acTFWrk[iI])) // q. alpha char? | |
*(pszLine + FMTOFFSET) = acTFWrk[iI]; // a. yes .. make it format | |
else if (isdigit(acTFWrk[iI])) // q. digit? | |
*(pszLine + TAGOFFSET) = acTFWrk[iI]; // a. yes .. make it the tag | |
} | |
sprintf(gszOutput, AFORMAT, pszLine); // format the line | |
return gszOutput; // return formatted line | |
} | |
///////////////////////////////////////////////////////// | |
// EditToFortran - convert tab-formatted input text line to FORTRAN format | |
// (a la DEC Fortran) | |
char *EditToFortran(char* p_pszEdit) // convert line to 1130 assembler | |
{ | |
char pszLine[MAXLINE]; // source line | |
char* pszWork; // work pointer | |
size_t iI; // work integer | |
char bContinue; // true if continue | |
if (p_pszEdit == NULL) // q. null request? | |
return FMSG; // a. yes .. return display message | |
if (strchr(p_pszEdit, '\t') == NULL) // q. no tab in the line? | |
return p_pszEdit; // a. nope, return line as is, assume it's formatted correctly | |
if (*p_pszEdit == 'C' || *p_pszEdit == '*' || *p_pszEdit == '\0') // q. comment or directive or blank line? | |
{ // a. yes.. don't restructure | |
return EditToWhitespace(p_pszEdit); | |
} | |
strncpy(pszLine, p_pszEdit, MAXLINE-1); // copy the line local | |
for (iI = strlen(pszLine); iI--;) // trim trailing whitespace | |
{ | |
if (*(pszLine + iI) <= ' ') // q. space or less? | |
*(pszLine + iI) = 0; // a. yes .. remove it | |
else // otherwise | |
break; // .. done. Leave loop. | |
} | |
// TODO: Add code to process a strip switch | |
// comment? | |
pszWork = (char*) pszLine; // set pointer to line | |
GetToken(gszLabel, 6, &pszWork); // get the line, if any. | |
pszWork++; // skip tab/whitespace | |
// continuation... | |
bContinue = ((isdigit(*pszWork) && (*pszWork != '0')) // if first char non-zero digit | |
|| (!isspace(*pszWork) && !isalpha(*pszWork))); // .. or non-alpha non-blank | |
memset(gszArg, 0, MAXLINE); // .. and arguments | |
strncpy(gszArg, pszWork, 75); // copy rest to argument | |
sprintf(gszOutput, (bContinue) ? FCONTFMT : FFORMAT, // format the line | |
gszLabel, // .. statement # | |
gszArg); // .. code | |
return gszOutput; // return formatted line | |
} | |
///////////////////////////////////////////////////////// | |
// EditToWhitespace - expand tabs at 8 space intervals. | |
char* EditToWhitespace(char *p_pszEdit) | |
{ | |
int iI; /* work integer */ | |
char pszLine[MAXLINE]; // source line | |
char pszWork[WORKSZ]; // work buffer | |
if (p_pszEdit == NULL) // q. null request? | |
return AMSG; // a. yes .. return display message | |
strncpy(pszLine, p_pszEdit, MAXLINE-1); // copy the line local | |
ExpandTabs(pszLine, pszWork, gaiPlainTabs); // expand the tabs | |
strncpy(gszOutput, pszWork, MAXLINE-1); // copy the line back | |
for (iI = strlen(gszOutput); iI--;) // look at each character | |
{ | |
if (*(gszOutput + iI) <= ' ') // q. space or less? | |
*(gszOutput + iI) = 0; // a. yes .. remove it | |
else // otherwise | |
break; // .. done. Leave loop. | |
} | |
return gszOutput; /* ... return buffer */ | |
} |