/* Z88TRAN Z88 file transfer and support program This program facilitates the transfer of data to and from a Z88 computer using the built in import/export program. The code is written in what is hoped to be a general enough form to be used with a number of differing systems with only minor modifications. As the program stands, it is not an operational program for any given system, but is intended as a nearly operational program which can be implemented easily by others. This program is released into the public domain, with the only request that if machine specific versions of the program are created, they be made available to others at no charge. This is a rather simple program in all, but if direct connections are available serves the Z88 rather well (no error checking is done). There are a number of constants and routines which must be defined, mainly single character unfiltered I/O to the Z88, which is assumed to be the operational terminal. The program has (among others) the following drawbacks: No error checking done. Remote print simply captures to the file z88print.prn No triming or adjusting of file names is done The following constants must be defined: BUFLEN - Character buffer length (maximum length of text file line) MAXLEN - Maximum length of file/path names TFILBW - Mode string for fopen() for binary file write TFILBR - Mode string for fopen() for binary file read TFILTW - Mode string for fopen() for text file write TFILTR - Mode string for fopen() for text file read The following routines need to be defined: getch() - Get a single character from standard input trinit() - Initialize line parameters/config (if needed) trfini() - Restore line parameters/config (if needed) sleep(n) - Suspend program for n seconds zgetc() - Get a character from the Z88 zputc() - Put a character to the Z88 ========================================================================== Users Guide (brief) Z88TRAN is a simple program, providing basic file exchange capabilities using the Z88 import/export feature. Each of the options is described briefly below: Z88 -> Host Text Z88 -> Host Binary Transfer a file from the Z88 to the host system, after selecting this option, go to import/export and send a single file. The file will either be saved as a text file (CR converted to CR/LF), or as a binary file (exact copy). Binary file format varies with the system. Host -> Z88 Text Host -> Z88 Binary Transfer a file from the host system to the Z88, after selecting this option and entering the name for the file to transfer, go into import/export and set to receive batch. The file name will be the same as the name of the file on the host system. Z88 -> Host & Print Puts the program into a mode where all serial line input is simply trapped to a binary file until two ESC characters are detected in sequence. This can be used to create a file (by chosing this option and then printing normally on the Z88) for routing to a printer on the Host system. Z88 -> Host Batch Send a batch file from the Z88 to the Host, used primarily to back up the Z88, the file will be saved exactly as transfered from the Z88, sending the file back to the Z88 will recreate all of the files. The contents of the batch file can be listed using the Catalog Batch File option. After selecting the name for the batch file on the Host, go into import/export and send the file(s) (:*//* for all the files in the Z88). At the end of the transfer, go back to terminal mode by hitting []V, then type ESC, followed by an uppercase Z. The ESC Z indicates the end of the batch transfer. Host -> Z88 Batch Get a batch file from the Host (see above). Simply enter the file name of the saved batch file on the Host, then go into import/export and set batch receive. Catalog Batch File Generate a listing of all of the files in a batch file (with checksums and sizes). Hit any key to continue at the end of the listing. Set options Set options, either 7 bit or 8 bit mode can be selected, if 7 bit is used (the default), all characters above ASCII 128 will be send as 7 bit codes using the import/export encoding scheme. Exit Program Exit the program. ========================================================================== */ #include #include "z88tran.h" /* Include file with local system changes */ #define ERRMSG 1 /* If defined, full error msg text else just numbers */ #ifdef ERRMSG #define NERMSG 17 static int iermsg[] = { 100,101,102,103,200,201,300,301,400,401,402, 500,501,502,600,601,602 }; static char *ermsgt[] = { "Unable to open batch save file", "Error writing to batch save file", "Error attempting to close batch file", "Error opening batch file", "Unable to process batch file - bad file structure", "Bad file name terminator in batch file", "Unable to open batch file for input", "Error writing batch file to Z88", "Error opening output file", "Error opening input file", "Error closing input file", "Error synchronizing with Z88", "Bad file name header", "Bad start of file header", "Unable to open printer output file", "End of file from Z88 while reading printer data", "Unable to close printer output file" }; #endif static int ibt7; static char name[MAXLEN], path[MAXLEN], fname[MAXLEN]; static char cbuff[BUFLEN]; static unsigned int chk, lchk; static double len, llen; main() { int iexit, ichar; char fname1[MAXLEN]; FILE *fp, *fopen(); trinit(); /* Initialize I/O routines if need be */ iexit = 1; ibt7 = 1; while ( iexit != 0 ) { mmenu(); ichar = toupper(getch()); switch (ichar) { case 'A' : /* Receive text file */ rcfil(0); break; case 'B' : /* Send text file */ sndfil(0); break; case 'C' : /* Receive binary file */ rcfil(1); break; case 'D' : /* Send binary file */ sndfil(1); break; case 'E' : /* Get a file, and then spool for printer */ psfile(); break; case 'F' : /* Receive batch file */ gbatch(); break; case 'G' : /* Send a batch file */ sbatch(); break; case 'H' : /* Display a catalog of a batch file */ clrscr(); printf("Batch File to Catalog : "); scanf("%s",fname1); fp = fopen(fname1,TFILBR); if (fp == NULL) prterr(103); else catfil(fp,0); break; case 'J' : /* Set options */ setopt(); break; case 'X' : iexit = 0; break; default : break; } } clrscr(); trfini(); /* Restore I/O routines if need be */ exit(0); } /* Display a catalog listing of the batch receive file iop controls what is listed, if 0, just a file listing is generated. */ catfil(fp,iop) int iop; FILE *fp; { int iend, ic, nfile; unsigned int chkl; double lenl; clrscr(); if (iop == 0) printf("File name Chksm Length\n"); chkl = 0; lenl = 0.; nfile = 0; iend = 1; while (iend != 0) { while ((ic = getc(fp)) != 27) { if (ic == EOF) { prterr(200); return(0); } } ic = getc(fp); /* Get command byte */ switch (ic) { case 'N' : gname(fp); ic = getc(fp); if (ic != 'F') { prterr(201); return(0); } gfile(fp); nfile++; chkl = chkl + chk; lenl = lenl + len; if (iop == 0) printf("%-62s %6u %8.0f\n",name,chk,len); else printf("|CD%s\n",path); ic = 27; break; case 'Z' : printf("Total of %8d files %6u %8.0f\n",nfile,chkl,lenl); getch(); return(0); break; } } } /* Clear the screen Since the general form of the program is with the Z88 running this program on a host machine, the Z88 clear screen command is used, (simply a FF). If the host/z88 link does not support transparent passage of FF, simply change this routine to output 8 LFs. */ clrscr() { putc(12,stdout); return(0); } /* Get a batch file */ gbatch() { int ir, ic, iend; FILE *fp; clrscr(); printf("Batch Save File : "); scanf("%s",fname); fp = fopen(fname,TFILBW); if (fp == NULL) { prterr(100); return(0); } clrscr(); printf("Initiate transfer from Z88 now ...\n\n"); iend = 0; do { ic = zgetc(); ir = putc(ic,fp); if (ir == EOF) { prterr(101); return(0); } if (ic == 27) { ic = zgetc(); ir = putc(ic,fp); if (ir == EOF) { prterr(101); return(0); } if (ic == 90) iend = 1; } } while (iend == 0); ir = fclose(fp); if (ir == EOF) prterr(102); return(0); } /* Get a byte from the file fp, standard ESC processing, -1 is returned for the end of the file, -2 for the end of the block transfer, -3 for an error, otherwise the ascii value is returned. */ gbyte(fp) FILE *fp; { int ic, i1, i2; ic = getc(fp); switch (ic) { case 27: ic = getc(fp); switch (ic) { case 'E': /* End of this file */ return(-1); case 'Z': /* End of entire block */ return(-2); case 'B' : /* Byte in hexadecimal notation */ i1 = getc(fp) - 48; if (i1 > 9) i1 = i1 - 7; i2 = getc(fp) - 48; if (i2 > 9) i2 = i2 - 7; ic = i1 * 16 + i2; return(ic); default : /* Unknown byte */ prterr(200); return(-3); } default: /* Anything else just return */ return(ic); } } /* Get a byte from the Z88, standard ESC processing, -1 is returned for the end of the file, -2 for the end of the block transfer, -3 for an error, otherwise the ascii value is returned. */ gbytez() { int ic, i1, i2; ic = zgetc(); switch (ic) { case 27: ic = zgetc(); switch (ic) { case 'E': /* End of this file */ return(-1); case 'Z': /* End of entire block */ return(-2); case 'B' : /* Byte in hexadecimal notation */ i1 = zgetc() - 48; if (i1 > 9) i1 = i1 - 7; i2 = zgetc() - 48; if (i2 > 9) i2 = i2 - 7; ic = i1 * 16 + i2; return(ic); default : /* Unknown byte */ prterr(200); return(-3); } default: /* Anything else just return */ return(ic); } } /* Get a file, length and checksum are returned. */ gfile(fp) FILE *fp; { int ic; chk = 0; len = 0.0; while ((ic=gbyte(fp)) >= 0) { chk = chk + ic; len = len + 1.0; } return(ic); } /* Get the name from the file header (file) */ gname(fp) FILE *fp; { int ic; char *n1; n1 = name; while ((ic=getc(fp)) != 27) { *n1 = ic; n1++; } *n1 = 0; strcpy(path,name); n1 = strrchr(path,'/') + 1; *n1 = 0; n1 = strrchr(name,'/') + 1; strcpy(fname,n1); return(0); } /* Get the name from the file header (z88) */ gnamez() { int ic; char *n1; n1 = name; while ((ic=zgetc()) != 27) { *n1 = ic; n1++; } *n1 = 0; strcpy(path,name); n1 = strrchr(path,'/') + 1; *n1 = 0; n1 = strrchr(name,'/') + 1; strcpy(fname,n1); return(0); } /* put out the character ic as an escape sequence to the Z88. */ hputc(ic) int ic; { int i1, i2, ir; ir = zputc(27); if (ir == EOF) return(ir); ir = zputc(66); if (ir == EOF) return(ir); i1 = ic / 16; i2 = ic - i1 * 16 + 48; i1 = i1 + 48; if (i1 > 57) i1 = i1 + 7; if (i2 > 57) i2 = i2 + 7; ir = zputc(i1); if (ir == EOF) return(ir); ir = zputc(i2); if (ir == EOF) return(ir); return(0); } /* Print out the main menu */ mmenu() { clrscr(); printf("Z88 Import/Export Support Program\n\n"); printf("A) Z88 -> Host Text "); printf("F) Z88 -> Host Batch \n"); printf("B) Host -> Z88 Text "); printf("G) Host -> Z88 Batch \n"); printf("C) Z88 -> Host Binary "); printf("H) Catalog Batch File\n"); printf("D) Host -> Z88 Binary "); printf("I) \n"); printf("E) Z88 -> Host & Print "); printf("J) Set options "); printf("X) Exit Program\n"); return(0); } /* Print an error message to the screen, and wait for the user to hit a key. */ prterr(msg) int msg; { int i; clrscr(); printf("Z88TRAN - Error number %d\n",msg); #ifdef ERRMSG for (i=0;i\n"); getch(); return(0); } /* Capture all data from the Z88 to a file (till terminated with the escape sequence), then spool the file to the printer. Escape sequence is by default two in series. */ psfile() { int ic1, ic2, ir, iend; FILE *fp; fp = fopen("z88print.prn",TFILBW); if (fp == NULL) { prterr(600); return(-1); } clrscr(); printf("\nZ88 Remote Print"); printf("\n\nSend to exit\n"); do { ic1 = zgetc(); if (ic1 == EOF) { prterr(601); ir = fclose(fp); if (ir == EOF) prterr(602); return(-1); } iend = 0; switch (ic1) { case 27 : ic2 = zgetc(); if (ic2 == EOF) { prterr(601); ir = fclose(fp); if (ir == EOF) prterr(602); return(-1); } if (ic2 == 27) iend = 1; else { putc(ic1,fp); putc(ic2,fp); } break; default : putc(ic1,fp); break; } } while (iend == 0); ir = fclose(fp); if (ir == EOF) { prterr(602); return(-1); } return(0); } /* Receive a file from the terminal, iop sets the output file mode, 0 for text, 1 for binary. */ rcfil(iop) int iop; { int ic; FILE *fp1; clrscr(); if (iop == 0) printf("\nZ88 -> Host text file transfer"); else printf("\nZ88 -> Host binary file transfer"); printf("\n\nGo into Import/Export and send file (single)\n"); ic = synchz(); if (ic != 0) return(-1); gnamez(name,path,fname); ic = zgetc(); /* Get start of file byte */ if (ic != 70) { prterr(502); return(-1); } if (iop == 0) fp1 = fopen(fname,TFILTW); else fp1 = fopen(fname,TFILBW); if (iop == 0) /* Text file, convert CR to LF */ while ( (ic=gbytez()) >= 0) { if (ic == 13) ic = 10; putc(ic,fp1); } else while ( (ic=gbytez()) >= 0) putc(ic,fp1); fclose(fp1); return(ic); } /* Send a batch file, if the 7bit flag is set (ibt7) then convert all 8 bit references to escaped ones. */ sbatch() { int ir, ic, iesc, iend; FILE *fp; clrscr(); printf("Batch File to send: "); scanf("%s",fname); fp = fopen(fname,TFILBR); if (fp == NULL) { prterr(300); return(0); } clrscr(); printf("Set for import batch receive...\n\n"); sleep(5); iend = 0; do { ic = getc(fp); if ((ic > 127) & (ibt7 != 0)) /* if 7 bit, escape over 127 */ ir = hputc(ic); else ir = zputc(ic); if (ir == EOF) { prterr(301); return(0); } if ((iesc!=0) & (ic=90)) /* End of file */ iend = 1; if (ic == 27) iesc = 1; else iesc = 0; } while (iend == 0); return(0); } /* Set options for file transfer and other defaults */ setopt() { int ic, iend; iend = 0; do { clrscr(); printf("Options set menu\n\n"); printf(" A) 7 Bit transfers "); if (ibt7 == 1) printf("*\n"); else printf("\n"); printf(" B) 8 Bit transfers "); if (ibt7 == 0) printf("*\n"); else printf("\n"); printf("\n Q) Quit to previous menu\n"); ic = toupper(getch()); switch (ic) { case 'A' : /* Set for 7 bit download */ ibt7 = 1; break; case 'B' : /* Set for 8 bit download */ ibt7 = 0; break; case 'Q' : /* Quit to previous */ iend = 1; break; default : break; } } while (iend == 0); return(0); } /* Send a file from the host system to the Z88 */ sndfil(iop) int iop; { int i, ic, ir, l; FILE *fp; clrscr(); if (iop == 0) /* Text file transfer */ printf("\nHost -> Z88 text file transfer"); else /* Binary file transfer */ printf("\nHost -> Z88 binary file transfer"); printf("\n\nHost file to transfer : "); scanf("%s",fname); strcpy(path,fname); if (iop == 0) /* Text file transfer */ fp = fopen(fname,TFILTR); else /* Binary file transfer */ fp = fopen(fname,TFILBR); if (fp == NULL) { prterr(401); return(-1); } sleep(10) ; /* Delay to allow for Z88 setup */ zputc(27); zputc(78); l = strlen(path); for (i=0;i 127) & (ibt7 != 0)) hputc(ic); else zputc(ic); } zputc(13); /* Put CR at end of line as per Z88 */ } } else /* Binary file transfer */ { while ((ic=getc(fp)) != EOF) { if (((ic>127) & (ibt7!=0)) | (ic<32)) hputc(ic); else zputc(ic); } } zputc(27); zputc(90); ir = fclose(fp); if (ir == EOF) { prterr(402); return(-1); } return(0); } /* Read till start of file block, used to drop out all of the startup characters in file transfers. 0 returned on no error, -1 for read error from Z88 line */ synchz() { int ic; while ((ic = zgetc()) != 27) { if (ic == EOF) { prterr(500); return(0); } } ic = zgetc(); /* Get command byte */ switch (ic) { case 'N' : /* Valid header */ return(0); default : /* Anything else is an error */ prterr(501); return(-1); } }