FORMAT ђђ(¤?А ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееOTHELLO C S PPONG C 8 RALLY C PRALLY MAPSTDLIB1 C B !"#$%&'(STDLIB2 C Ђ)*+,-./012345678STDLIB2 C  9:TELNET C Ђ;<=>?@ABCDEFGHIJTELNET C #KLMNOTABIFY C PQееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее /* OTHELLO -- The Game of Dramatic Reversals written by Bert Halstead modified for BDS C by Leor Zolman This program is a good example of: a) structured, heirarchical function organization b) arrays as formal parameters c) use of the "qsort" library function Object of the game is for two players to alternate placing their marker someplace on an 8 by 8 grid, so that at least one of the opponent's pieces becomes surrounded by the moving player's peices -- causing the flanked pirow and second representing column. For example: if playing '*', your first move might be '46', meaning 4th row down, 6th position across. As an alternative to entering a move, one of the following commands may be typed: g causes computer to play both sides until game is over a causes computer to print out an analysis of each of your possible moves. A letter from A to Z will appear at each of your legal move positions, where A is the machine's opinion of an excellant move and*/ int h[4][2]; /* handicap position table */ char mine, his; /* who has black (*) and white (@) in current game */ char mefirst; /* true if computer goes first in current game */ main(argc,argv) int argc; char **argv; { char b[8][8]; int i; h[0][0] = h[0][1] = h[2][0] = h[3][1] = 0; h[1][0] = h[1][1] = h[2][1] = h[3][0] = 7; printf("\nWelcome to the BDS C OTHELLO program!\n"); printf("\nNote: `*' always goes first...Good luck!!!\n\n"); srand1("Do you want to go first? "); if (ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееeces to flip 'color' and belong to the moving player. After 60 moves have been played (or if no player has a legal move left), the player with the most of his own pieces on the board wins. The playing pieces are '*' and '@'. You may choose to play either '*' or '@' for the first game; thereafter, you and the computer will alternate going first for each game. Whoever goes first always plays `*'. You enter a move as a two digit number, each digit being from 1 to 8, first digit representing Z is a real loser. hn sets handicap. n is 1,2,3, or 4. If n is positive, gives n free pieces to the computer. If n is negative, gives YOU the free peices. f forfeit the current move. This happens automatically if you have no legal moves. q quit the current game. b prints out board again. s prints out the score, and tells who is winning. */ #define BLACK '*' #define WHITE '@' #define EMPTY '-' int handicap; char selfplay; /* true if computer playing with itself toupper(getchar()) == 'Y') mefirst = 0; else mefirst = 1; printf("\n\n"); do { clrbrd(b); prtbrd(b); i = game(b,4); mefirst = !mefirst; if (i==4) break; if (i=='Q') continue; printf("\n"); i = prtscr(b); if (i>0) printf(" You won by %d\n",i); else if (i<0) printf(" You lost by %d\n",-i); else printf(" A draw\n"); } while (ask("Another game? ")=='Y'); } game(b,n) char b[8][8]; int n; { char c; int ff; int i,j; handicap = 0; selfplay = ' '; ff=0; if (mefirst) { mine = BLACK; his = WHITE; printf("\nI go first:\n\n"); } else { mine = WHITE; his = BLACK; printf("\nYou go first:\n\n"); } while(1) { if (cntbrd(b,EMPTY)==0) return 'D'; if (cntbrd(b,EMPTY)==60 && mine == BLACK) goto Istart; if (chkmvs(b,his)==0) { printf(!mefirst ? "Forfeit" : " ...Forfeit\n"); ff |= 1; } else switch (c = getmov(&i,&j)) { case 'B': prtbrd(b); continue; case 'S': i= prtscr(b); if (i>0) printf(" You're winmefirst ? "%1d-%1d" : " ...%1d-%1d\n", i+1,j+1); putmov(b,his,i,j); } else { printf("Illegal!\n"); continue; } break; case 'F': if (n>abs(handicap)+4) { printf ("Illegal!\n"); continue; } else printf(!mefirst ? "Forfeit" : " ...Forfeit\n"); } Istart: if (cntbrd(b,EMPTY) == 0) return 'D'; if (chkmvs(b,mine)==0) { printf(!mefirst ? "...Forfeit\n": "Forfeit...\n"); ff |=2; } else { my_mov(b,mine,his,EMPTY,&i,&j); tch (c=skipbl()) { case '\n': printf("Move? "); continue; case 'G': if ((c = skipbl()) != '\n') goto flush; selfplay='G'; return 'G'; case 'B': case 'S': case 'Q': case 'F': case 'A': a=c; if (( c = skipbl()) != '\n') goto flush; return a; case 'H': if ((a=c=skipbl()) == EMPTY) c=getchar(); if (c<'1' || c>'4' || skipbl() !='\n') goto flush; *i = a==EMPTY? -(c-'0') : (c-'0'); return 'H'; case 4: return c; default: if (c<'1' || c>'8') got]; char p; { int i,j,k; k=0; for (i=0; i<8; i++) for (j=0; j<8; j++) k += chkmov(b,p,i,j); return k; } chkmov(b,p,x,y) char b[8][8],p; int x,y; { if (b[x][y] != EMPTY) return 0; return chkmv1(b,p,x,y,0,1) + chkmv1(b,p,x,y,1,0) + chkmv1(b,p,x,y,0,-1)+ chkmv1(b,p,x,y,-1,0)+ chkmv1(b,p,x,y,1,1) + chkmv1(b,p,x,y,1,-1)+ chkmv1(b,p,x,y,-1,1)+ chkmv1(b,p,x,y,-1,-1); } chkmv1(b,p,x,y,m,n) char b[8][8],p; int x,y,m,n; { int k; k=0; while ((x += m) >= 0 && x < 8 && (yturn !(c1==o && c2==e || c1==e && c2==o); } notak2(b,p,o,e,x,y,m,n) char b[8][8],p,o,e; int x,y,m,n; { x += m; y +=n; if (x>=0 && x<=7 && y>=0 && y<=7) while(b[x][y] == 0) { x += m; y+=n; if (x<0 || x>7 || y<0 || y>7 || b[x][y]==e) return o; } while (x>=0 && x<=7 && y>=0 && y<=7 && b[x][y]==p) { x +=m; y+=n; } if (x<0 || x>7 || y<0 || y>7) return p; return b[x][y]; } putmov(b,p,x,y) char b[8][8]; char p; int x,y; { int i,j; b[x][y] = p; for (i= -1; ining\n"); else if (i<0)printf(" You're losing!\n"); else putchar('\n'); continue; case 'Q': case 4: return c; case 'H': if (n>abs(handicap)+4) printf("Illegal!\n"); else for (j=0; i!=0; j++) { b[h[j][0]][h[j][1]]= i>0?BLACK:WHITE; handicap += i>0 ? 1 : -1; ++n; i += i>0 ? -1 : 1; } prtbrd(b); continue; case 'A': analyze(b,his,mine,EMPTY); continue; case 'G': my_mov(b,his,mine,EMPTY,&i,&j); case 'M': if (chkmov(b,his,i,j)>0) { printf(! printf(!mefirst ? "...%1d-%1d\n" : "%1d-%1d...\n", i+1,j+1); putmov(b,mine,i,j); ++n; } if (ff==3 || n>64) return 'D'; if (!(ff & 1)) prtbrd(b); ff = 0; } } prtscr(b) char *b; { int i,j; printf("%1d-%1d",i = cntbrd(b,his), j=cntbrd(b,mine)); return i-j; } char getmov(i,j) int *i, *j; { char a,c; int n; char *p; char skipbl(); if (selfplay == 'G') { if (!kbhit()) return 'G'; selfplay = ' '; getchar(); } printf("Move: "); while(1) swio flush; *i = c-'1'; c = skipbl(); if (c<'1' || c>'8') goto flush; *j = c- '1'; if ((c=skipbl()) == '\n') return 'M'; flush: while (c != '\n' && c != 4) c=getchar(); if (c==4) return c; printf ("Huh?? "); } } char ask(s) char *s; { char a,c; printf ("%s ",s); a=skipbl(); while (c != '\n' && c != 4) c= getchar(); return a; } char skipbl() { char c; while ((c = toupper(getchar())) == ' ' || c=='\t'); return c; } chkmvs(b,p) char b[8][8 += n) >= 0 && y<8) { if (b[x][y]==EMPTY) return 0; if (b[x][y]== p ) return k; if (x==0 || x==7 || y==0 || y==7) k += 10; else k++; } return 0; } notake(b,p,o,e,x,y) char b[8][8]; char p,o,e; int x,y; { return notak1(b,p,o,e,x,y,0,1)&& notak1(b,p,o,e,x,y,1,1)&& notak1(b,p,o,e,x,y,1,0)&& notak1(b,p,o,e,x,y,1,-1); } notak1(b,p,o,e,x,y,m,n) char b[8][8],p,o,e; int x,y,m,n; { int c1,c2; c1 = notak2(b,p,o,e,x,y,m,n); c2 = notak2(b,p,o,e,x,y,-m,-n); re<=1; i++) for (j= -1; j<=1; j++) { if ((i != 0 || j!=0)&&chkmv1(b,p,x,y,i,j)>0) putmv1(b,p,x,y,i,j); } } putmv1(b,p,x,y,m,n) char b[8][8]; char p; int x,y,m,n; { while ((x += m) >= 0 && x<8 && (y += n)>=0 && y<8) { if (b[x][y] == EMPTY || b[x][y] == p) return; b[x][y] = p; } } struct mt { int x; int y; int c; int s; }; my_mov(b,p,o,e,m,n) char b[8][8],p; int *m, *n; { struct mt t[64]; int i,k; int cmpmov(); k = fillmt(b,p,o,e,t); if (!k) return 0; qsort (&t, k, 8, &cmpmov); for (i=1; i=10) { s -= 4; oside |= 8; } } if (s< -oside) s= -oside; if (side>0) return s+side-7+10*ok; if (i==1 || i==6) {s--; side++;} if (j==1 || j==6) {s--; side++;} if (side>0) return s; if (i==2 || i==5) s++; if (j==2 || j==5) s++; retur) { putchar(' '); putchar(b[i][j]); } putchar('\n'); } putchar('\n'); } cpybrd(a,b) char *a, *b; { int i; i=64; while (i--) *a++ = *b++; } cntbrd(b,p) char *b, p; { int i,j; i= 64; j=0; while (i--) if (*b++ == p) ++j; return (j); } har b[8][8]; { int i,j; printf(" 1 2 3 4 5 6 7 8\n"); for (i=0; i<8; i++) { printf("%2d",i+1); for (j=0; j<8; j++/* Polish Pong game for H19/H89, RHH (Robert H. Halstead) August 1980: Object is to guide the little ball around the screen by setting up and removing blockade sections. All control is via the keypad; "4" and "6" cause blockades to be formed at the current position of the roving ball, while pressing "5" at the exact moment the ball hits a blockade should make that blockade disappear. Oh yes, and the POINT of all this is to make the ball hit the little square target--once tdefine ISPEED 400 /* initial ball speed */ #define SPEEDINC 100 /* increments/decrements in ball speed */ #define TIMX 50 /* locations of status strings */ #define TIMY 23 #define TARGX 30 #define TARGY 23 #define SPEEDX 10 #define SPEEDY 23 #define BESTX 70 #define BESTY 23 #define CONINF 1 /* console input FDOS function */ #define MSPS 960 /* "millisecs" per second */ #define QUITCH 3 /* ^C quits the program */ #define DELETE 0177 /* DELETE restarts the game */ #define XOFF i<8; i++) for(j=0; j<8; j++) if (t[k].c = chkmov(b,p,i,j)) { t[k].x =i; t[k].y =j; t[k].s = s_move(b,p,o,e,i,j); ++k; } return k; } s_move(b,p,o,e,i,j) char b[8][8], p, o, e; int i,j; { char a[8][8]; int ok,s,k,l,side,oside; int c,dkl; cpybrd(a,b); putmov(a,p,i,j); side = 0; if (i==0 || i==7) side++; if (j==0 || j==7) side++; s = 0; ok = 0; if (side==2 || notake(b,p,o,e,i,j)) ok++; oside = 0; for (k=0; k<8; k++) for(l=0; l<8; l++) { c=chkn s; } cmpmov(a,b) struct mt *a, *b; { if ((*a).s > (*b).s) return -1; if ((*a).s < (*b).s) return 1; if ((*a).c > (*b).c) return -1; if ((*a).c < (*b).c) return 1; return 0; } clrbrd(b) char b[8][8]; { int i,j; for (i=0; i<8; i++) for (j=0; j<8; j++) b[i][j]= EMPTY; b[3][3] = b[4][4] = BLACK; b[3][4] = b[4][3] = WHITE; } prtbrd(b) char b[8][8]; { int i,j; printf(" 1 2 3 4 5 6 7 8\n"); for (i=0; i<8; i++) { printf("%2d",i+1); for (j=0; j<8; j++ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееhis is done, the square will disappear and reappear somewhere else, to be hit again. Go for hitting the target the specified number of times AS QUICKLY AS POSSIBLE. Your score is how many seconds you took; the lower the better. Keys "8" and "2" speed up and slow down the ball; as you get better, try it at a faster speed! */ #include "bdscio.h" #define MAXX 78 /* horizontal size of board */ #define MAXY 23 /* vertical size */ #define MAXTARG 20 /* # of targets per game */ #('S'&037) /* flow control chars */ #define XON ('Q'&037) #define EGRAPH "\033F" /* H19 escape sequences */ #define XGRAPH "\033G" #define REGKPM "\033u\033>" #define VBAR '`' /* H19 alternate graphic chars */ #define HBAR 'a' #define SLASH 'x' #define BSLASH 'y' #define BALL '^' #define TARGET 'i' char board[MAXX][MAXY]; /* board with current layout */ int ballx,bally,ballxv,ballyv; /* state of ball */ int Speed,Dist; /* speed of ball */ int TargLeft; /* number of targets left */ int MSecs,Secs; /* bookkeeping for time elapsed */ int NewTime; /* nonzero if time has changed */ int Best; /* best score so far */ int InChar; /* character read from input */ putchx(c) int c; { if (++MSecs >= MSPS) { MSecs = 0; Secs++; NewTime = 1; } Dist += Speed; if (bios(2)) { InChar = bios(3) & 0177; if (InChar == QUITCH) { InChar = -1; outs(0,MAXY-1,XGRAPH); prints(CURSORON); exit(0); } if (InChar == XOFF) { whil int ch,x,y; { putchx(ESC); putchx('Y'); putchx(y+32); putchx(x+32); putchx(ch); } outs(x,y,s) /* put string at position (x,y) */ int x,y; char *s; { putchx(ESC); putchx('Y'); putchx(y+32); putchx(x+32); prints(s); } puttarg() { char buff[100]; sprintf(buff,"\033p%2d\033q",TargLeft); outs(TARGX,TARGY,buff); } puttime() { char buff[100]; sprintf(buff,"\033p%3d\033q",Secs); outs(TIMX,TIMY,buff); } putspeed() { char buff[100]; sprintf(buff,"\033p%3ent char */ i = board[ballx][bally]; if (i == SLASH || i == BSLASH) board[ballx][bally] = ' '; else putchx(7); break; case '8': /* go faster */ if (Speed < 1000) { Speed += SPEEDINC; putspeed(); } break; case '2': /* go slower */ if (Speed > SPEEDINC+50) { Speed -= SPEEDINC; putspeed(); } break; case DELETE: /* start a new game */ return(0); default: putchx(7); break; } } switch (board[ballx][bally nx = ballx + ballxv; ny = bally + ballyv; ouch(BALL,nx,ny); ouch(board[ballx][bally],ballx,bally); if (NewTime) { puttime(); NewTime = 0; } ballx = nx; bally = ny; while (Dist < (ballyv?22000:10000)) putchx(1); /* further delay to slow ball down */ return(1); } main() { puts("Welcome to Polish Pong!\n"); sleep(10); Best = 32767; Speed = ISPEED; /* governs how fast ball moves */ while (playgame()); } int playgame() { int i,j; char buff[100]; /* temp */ InChaboard[i][0] = board[i][MAXY-1] = HBAR; for (i = 0; i < MAXY; i++) board[0][i] = board[MAXX-1][i] = VBAR; board[0][0] = 'f'; /* special corner pieces */ board[0][MAXY-1] = 'e'; board[MAXX-1][0] = 'c'; board[MAXX-1][MAXY-1] = 'd'; board[rand()%(MAXX-2)+1][rand()%(MAXY-2)+1] = TARGET; /* place initial target */ TargLeft = MAXTARG; /* start with full complement of targets */ prints(REGKPM); prints(CLEARS); prints(EGRAPH); prints(CURSOROFF); for (j = 0; j < MAXY; j++) { for (i = 0; ie (InChar != XON) { while (!bios(2)); InChar = bios(3) & 0177; } InChar = -1; } } bios(4,c); if (c == '\n') putchx('\r'); } /* int getch() /* get a char from console, no echo */ { int c; c = inp(CDATA); return(c); } */ prints(s) /* put out a string */ char *s; { int c; while (c = *s++) putchx(c); } puts(s) /* same as prints, but "srand1" needs it */ char *s; { prints(s); } ouch(ch,x,y) /* put character at position */d\033q",Speed/10); outs(SPEEDX,SPEEDY,buff); } int moveball() { int i,nx,ny; Dist = 0; i = InChar; if (i > 0) { InChar = -1; switch (i) { case '4': /* lay down backslash */ if (board[ballx][bally] == ' ') board[ballx][bally] = BSLASH; else putchx(7); break; case '6': /* lay down slash */ if (board[ballx][bally] == ' ') board[ballx][bally] = SLASH; else putchx(7); break; case '5': /* delete curr]) { case ' ': break; case VBAR: ballxv = -ballxv; break; case HBAR: ballyv = -ballyv; break; case BSLASH: i = ballxv; ballxv = ballyv; ballyv = i; break; case SLASH: i = ballxv; ballxv = -ballyv; ballyv = -i; break; case TARGET: if (--TargLeft <= 0) return(0); puttarg(); board[ballx][bally] = ' '; do { nx = rand()%(MAXX-2) + 1; ny = rand()%(MAXY-2) + 1; } while (board[nx][ny] != ' '); board[nx][ny] = TARGET; ouch(TARGET,nx,ny); break; } r = -1; /* initially, no char typed in */ srand1("\033H\033GType any key to start game: \033K"); if (bdos(1) == QUITCH) /* clear the input character */ exit(); /* and quit on control-C */ InChar = -1; /* clear space out of input buffer */ ballx = rand()%(MAXX-2) + 1; bally = rand()%(MAXY-2) + 1; ballxv = ballyv = 0; i = (rand()&2) - 1; if (rand()&1) ballxv = i; else ballyv = i; for (i = 0; i < MAXX; i++) for (j = 0; j < MAXY; j++) board[i][j] = ' '; for (i = 0; i < MAXX; i++) < MAXX; i++) putchx(board[i][j]); putchx('\n'); } outs(TIMX-11,TIMY,"\033G\033pTime Used: "); outs(TARGX-14,TARGY,"Targets Left: "); if (Best < 32767) { sprintf(buff,"Best Time: %3d",Best); outs(BESTX-11,BESTY,buff); } outs(SPEEDX-7,SPEEDY,"Speed: \033F\033q"); putspeed(); puttarg(); MSecs = Secs = 0; puttime(); ouch(BALL,ballx,bally); while (moveball()); if (TargLeft == 0 && Secs < Best) Best = Secs; return(1); } /* H19 RALLY Game, 5/80 Steve Ward Works ONLY on Heathkit/Zenith H19/Z19 terminal (or H89 computer) Command format: A>rally [-rn] [-b] [mapname] where: "n" is an optional seed for the random number generator (results in exactly the same minor track deviations each time it is given with a particular track); If "n" is omitted, then track deviations are totally random for each session (but same for each run in any single session.) "-b"CRTFrz, CRTChr; int Miles; char Pavement, Freeze, BFlag; char CurX, CurY, SignY; int CarX, CarDX; char RevFlg, AltFlg; int Speed, Tenths; char Image[CARY*80+80]; char *ImPtr, *ImEnd; int Seed; int Ranno; char InBuf[BUFSIZ], SavChr; int SpTime[MAXSPD+1]; struct Road { struct Node *Next; char active; char Token; int Windy; int Curvy; int Age; int ToGo; char Holes; char X; char dx; char width; } Road1, Road2; struct Sign { struct Node *Next; char key; char text[0];) { char stat, ch; for(;;) { if ((CIMASK & (stat = inp(CSTAT))) == (CAHI ? CIMASK : 0)) switch(ch = (0177 & inp(CDATA))) { case 'S'-64: CRTFrz=1; break; case 'Q'-64: CRTFrz=0; break; case 'C'-64: puts("\033z"); exit(); default: CRTChr=ch; } if (CRTFrz) continue; if ((stat & COMASK) == (CAHI ? COMASK : 0)) { if (c) outp(CDATA,c); return; } } } char *new(size) { char *rr; rr = Freep; Freep += size; return rr; } struct Dist *NRoad(widx, curv, windx, dist) ff->Next = 0; ff->Branch = 0; return ff; } PrNode(nn) struct Node *nn; { printf("Node %x: %c -> %x \r\n", nn, nn->key, nn->Next); } char rdc() { char ch; if (ch = SavChr) { SavChr=0; return ch; }; return (getc(InBuf)); } char pkc() { return (SavChr = rdc()); } int rdn() { int ans, ch; ans = 0; while (isdigit(pkc())) ans = ans*10 + (rdc() - '0'); return ans; } struct Dist *LRoad() { int w, c, iwid, dd; char ch; dd = rdn(); w = -1; c = -1; iwid = 20; while (pkdc()) != ('Z'-64)) { last = it; switch(ch) { case '=': Tag[rdc(InBuf)] = Freep; break; case '|': while (rdc() != '\n'); break; case '"': cc = buf; while (((ch = rdc()) != '"') && (ch != '\n')) *cc++ = ch; *cc = 0; it->Next = NSign(buf); it = it->Next; break; case '#': it->Next = LRoad(); it = it->Next; break; case ':': it->Next = rdc(); case '.': it = &Ignore; break; case '>': it->Next = NFork('R'); it = it->Next; it->Branch = rdc(); is a debugging option doing Steve-knows-what. "mapname" specifies the map file to use for the track (defaults to "rally.map"). */ #include "bdscio.h" /* Get std console parameters */ #define CARY 16 /* Y position of car. */ #define IBAD 0 #define LSPEED 7 /* Line 25 label posns */ #define LMILES 20 #define MAXSPD 9 #define SPDSCL 128 #define TENTHS 10 /* Number of lines per mile. */ #define TICMIN 1920 /* Number of tics per minute. */ char Free[10000], *Freep; char }; struct Fork { struct Node *Next; char key; char *Branch; }; struct Dist { struct Node *Next; char key; char wid, curve, wind; int miles; }; union Node { struct Dist; struct Fork; struct Sign; } *Tag[128]; /* Write a character to the terminal, handling X-ON/X-OFF protocol and not going into a busy loop if the terminal isn't ready to send a character, but rather just returning in that case to let the caller do more crunching and try again later. */ putchar(c { struct Dist *rr; rr = new(sizeof *rr); rr->key = 'D'; rr->Next = 0; rr->miles = dist; rr->wid = widx; rr->curve = curv; rr->wind = windx; return rr; } struct Sign *NSign(txt) char *txt; { int leng; char *cc, *dd; struct Sign *ss; leng = sizeof *ss; leng++; for (cc=txt; *cc++; leng++); ss = new(leng); ss->key = 'S'; ss->Next = 0; dd = &(ss->text); for (cc=txt; *dd++ = *cc++;); return ss; } struct Fork *NFork(kk) { struct Fork *ff; ff = new(sizeof *ff); ff->key = kk;c() != '\n') switch(rdc()) { case '~': c++; continue; case 'W': iwid = rdn(); continue; case '!': w++; continue; default: continue; } return NRoad(iwid, c, w, dd); } struct Dist *Load(name) char *name; { char ch, buf[100], *cc; struct Sign First, Ignore; struct Node *it, *last; puts("\033z"); SavChr = 0; it = &First; First.key = '?'; if (fopen(name, InBuf) == -1) { printf("Can't read %s\r\n", name); exit(); } while ((ch = rdc()) != 014) putchar(ch); while ((ch = r break; case '<': it->Next = NFork('L'); it = it->Next; it->Branch = rdc(); break; case ' ': case '\n': case '\r': case '\t': case '\f': break; default: puts("Illegal syntax: "); putchar(ch); while ((ch = rdc(InBuf)) != '\n') putchar(ch); puts("\n\r"); break; }} NSign("Unbound label"); srand1("\033x1\033x5\033Y8 (type a character to start)"); if (!Seed) Seed = rand(); /* Do this only if "-r" option given without any argument. */ bdos(1); return First.Next; } Exec(rr) struct Road *rr; { int x, dir, tt, right, left; union Node *nn; nn = rr->Next; rr->Next = nn->Next; x = rr->X; dir = -1; switch (nn->key) { case 'S': right = x+(rr->width); left = 78-right; x = x>left? 0:right+2; printf("\033Y%c%c\033G %s \033F", SignY++, x+32, &(nn->text)); return; case 'D': rr->Age = 0; if (nn->wind != 255) rr->Windy = ~(-1 << nn->wind); if (nn->curve != 255) rr->Curvy = nn->curve; rr->ToGo = nn->miles; if (nn->wid CurX=0; CurY=0; if ((ImPtr += 80) == ImEnd) ImPtr = Image; Pavement = ImPtr[CarX]; setmem(ImPtr, 80, IBAD); } road(x, width, rdno) { char i, *cc; puts("\033Y "); putchar(32+x); if (!RevFlg) { puts("\033p"); RevFlg=1; } if (!AltFlg) { puts("\033F"); AltFlg=1; } cc = &(ImPtr[x]); for (i=width; i--;) { putchar('i'); *cc++ |= rdno; }} /* Update a Road; returns 1 if finish line. */ UpRd(rr) struct Road *rr; { int ddx, left, right, curve, act, rough; unsigned i; if (!(act = rrr->X; right = left+(rr->width); if (left < 1) ddx = rough; else if (right > 79) ddx = -rough; else if ((!Freeze) && (!((rr->Windy) & Ranno))) { curve = rr->Curvy; if (Ranno & 64) ddx += 1; if (Ranno & 1024) ddx -= 1; if ((ddx > curve) || (ddx < (-curve))) ddx = rr->dx; } rr->dx = ddx; rr->X += ddx; road(rr->X, rr->width, rr->Token); return 0; } /* returns 2 iff end, 0 iff crash, 1 else. */ int Update() { int Eor; SignY=32; roll(); Eor = UpRd(&Road1) | UpRd(&Road }}}} fork(where, dir) struct Node *where; { struct Road *r1, *r2, newx; r1 = &Road1; r2 = &Road2; if (!(r1->active)) { r1 = &Road2; r2 = &Road1; } r1->dx = dir; r2->dx = -dir; r2->X = r1->X; r2->active = 1; r2->Age = 0; r2->Windy = r1->Windy; r2->Curvy = r1->Curvy; r2->width = r1->width; r2->Next = where; r2->ToGo = -1; Freeze = 1; } main(argc, argv) char **argv; { int i, j, Mins, Hours, Tics; char *arg, *MapNam; struct Node *First; Seed = 12345; j = SPDSCL*MAXSpeed 00 Miles 0 "); puts("\033Y8X Rally 1.2 Steve Ward "); setmem(Image,CARY*80,255); ImPtr = Image; ImEnd = &(Image[CARY*80]); Road1.Token=1; Road2.Token=2; Road1.active = 1; Road1.Age = 0; Road1.ToGo = 0; Road1.X = 20; Road1.dx = 0; Road2.active = 0; CarDX = 0; RevFlg = 0; AltFlg = 0; Road1.ToGo = 0; Road1.Next= First; CarX = Road1.X + (Road1.width >> 1); Speed=3; Update(); for (i=0; iwidth = nn->wid; return; case 'L': dir = 1; case 'R': if (!Freeze) fork(nn->Branch, dir); return; } } MoveTo(x, y) { puts("\033Y"); putchar(y+32); putchar(x+32); } SpeedL() { MoveTo(LSPEED, 24); putchar(Speed + '0'); } label(val, posn) { printf("\033Y8%c%d ", posn+32, val); } getchar() { char ch; while (!(ch = CRTChr)) putchar(0); CRTChr = 0; return ch; } car(x) { puts("\033Y"); putchar(CARY+31); putchar(x+32); puts(" "); } roll() { puts("\033H\033L"); ->active)) return 0; (rr->ToGo)--; while ((rr->ToGo) <= 0) { if (i = (rr->Next)) { if (i == '.') return 1; if (i == '*') { rr->active = 0; return 0; } if (i < 128) { rr->Next = Tag[i]; if (BFlag) { puts("\033H\033G"); putchar(i); puts("\033F"); }} Exec(rr); } else { rr->active = 0; return 0; }} if (Freeze) rough=0; else rough=1; if (++(rr->Age) > 24) if (!(Pavement & (rr->Token))) { rr->active = 0; Freeze = 0; return 0; } ddx = rr->dx; left = r2); if (Eor) return 2; Delay(SpTime[Speed]); if ((CarX += CarDX) < 0) { CarX=0; CarDX=0; } else if (CarX > 79) { CarX=79; CarDX=0; } car(CarX); if (Pavement == IBAD) return 0; return 1; } Delay(n) { char ch; n |= 1; while (n--) { putchar(0); if (CRTChr) { ch = getchar(); switch(ch) { case '4': CarDX--; break; case '6': CarDX++; break; case '5': case '2': if (Speed>1) Speed--; Speed--; case '8': if (++Speed > MAXSPD) Speed=MAXSPD; SpeedL(); PD; for (i=1; i<= MAXSPD; i++) SpTime[i] = j/i - SPDSCL; SpTime[MAXSPD] = 0; BFlag = 0; MapNam = "RALLY.MAP"; for (i=1; i= TICMIN) { Tics -= TICMIN; Mins++; }; while (Mins >= 60) { Mins -= 60; Hours++; }; if (!(i = Update())) { puts("\033H CRASHED AFTER "); done: printf("\033G %d Hours, %d Minutes\007!!! !!! !!! ", Hours, Mins); delay(10000); goto top; } else if (i == 2) { puts("\033H YOU MADE IT IN "); goto done; } if (++Tenths >= 10) { label(++Miles, LMILES); Tenths=0; } goto loop; } p q p Rally Game Version 1.1 q p q p Usage: q F^G Left/Right keypad arrows control steering F^G Up/Down keypad arrows control speed F^G See how fast you can make it to the finish line! F^G Explore some turnoffs; you might find a short cut. p Steve Ward 5/80 q =S "Starting Line: 80 Miles to go" #50 ~~! W20 "Field -- Next Left" #25 ~~! W20 "Finish Line -- ! "End of track - Congratulations!" #18 ~!!!!!!!!!!!!! :. =F #40 !~~ W20 #40 !!!!!!~ W79 #1 !!!!!!~ W74 >G #40 !!!!!!~ W39 #10 !!!!!!~ W30 #30 !~ W20 :4 =G #40 !!!!!!~ W39 #10 !!!!!!~ W30 #40 !~~~ W20 "Narrow Bridge" #10 !~~~ W20 #2 !~ W4 #20 !~~~ W20 "Straightaway ahead" #200 !~ W6 "Chicane" #20 !!~~~ W6 :H | Narrow path, et al. =P #30 ~!!!!!!!! W4 #30 ~~!!! W4 "Too easy, huh?" #30 ~~~~! W7 #30 W6 =Y #30 W5 #30 W4 #30 W3 #5 W5 _nleft = 0; return iobuf -> _fd; } int getc(iobuf) struct _buf *iobuf; { int nsecs; if (iobuf == 0) return getchar(); if (iobuf == 3) return bdos(3); if (iobuf -> _nleft--) return *iobuf -> _nextp++; if ((nsecs = read(iobuf -> _fd, iobuf -> _buff, NSECTS)) <= 0) return ERROR; iobuf -> _nleft = (NSECTS * SECSIZ - 1); iobuf -> _nextp = iobuf -> _buff; return *iobuf->_nextp++; } /* Buffered "unget" a character routine. Only ONE byte may be "ungotten"eat(name)) < 0 ) return ERROR; iobuf -> _nextp = iobuf -> _buff; iobuf -> _nleft = (NSECTS * SECSIZ); return iobuf -> _fd; } int putc(c,iobuf) char c; struct _buf *iobuf; { if (iobuf == 1) return putchar(c); if (iobuf == 2) return (bdos(5,c)); if (iobuf == 3) return (bdos(4,c)); if (iobuf -> _nleft--) return *iobuf -> _nextp++ = c; if ((write(iobuf -> _fd, iobuf -> _buff, NSECTS)) != NSECTS) return ERROR; iobuf -> _nleft = (NSECTS * SECSIZ - 1); iobuf -> _nextp = iobuf -> _bBear right" #5 ~~! W20 W #80 ~~~~~ "30 Miles to Finish" =X #30 "Road Narrows" #10 #2 W18 !!~~ #2 W16 !!~~ #2 W14 !!~~ #2 W12 !!~~ #2 W10 !!~~ =Z #2 W8 !!~~ #110 W8 =H "Road Widens" #10 W8 #2 W10 #2 W12 #2 W14 #2 W16 #2 W18 #20 W20 "10 Miles Left" #90 ~~~~~~~ !! "Approaching FINISH LINE" #10 ~!!!!!!!!!!!! #5 W12 #5 W14 #5 W17 :Z | Twisty Maze: =W #30 ~~~! W8 =a >f =g #30 ~~~! W8 >g =b #30 ~~~! W8 j :h =j #30 ~~!!! W8 "Leaving TWISTY MAZE" "Visit us again soon" #30 ~~~!!! W10 "Bear right for" " OMEGA DRIVE " >o :X =o #30 W14 ~~~! " OMEGA DRIVE " :o =f h #30 ~!!!!!!!!!!!! W8 _fd = open(filename,0))<0) ret between consecutive "getc" calls. */ int ungetc(c, iobuf) struct _buf *iobuf; char c; { if (iobuf == 0) return ungetch(c); if (iobuf -> _nleft == (NSECTS * SECSIZ)) return ERROR; *--iobuf -> _nextp = c; iobuf -> _nleft++; return OK; } int getw(iobuf) struct _buf *iobuf; { int a,b; if (((a=getc(iobuf)) >= 0) && ((b= getc(iobuf)) >=0)) return 256*b+a; return ERROR; } int fcreat(name,iobuf) char *name; struct _buf *iobuf; { unlink(name); if ((iobuf -> _fd = cruff; return *iobuf -> _nextp++ = c; } int putw(w,iobuf) unsigned w; struct _buf *iobuf; { if ((putc(w%256,iobuf) >=0 ) && (putc(w / 256,iobuf) >= 0)) return w; return ERROR; } int fflush(iobuf) struct _buf *iobuf; { int i; if (iobuf < 4) return OK; if (iobuf -> _nleft == (NSECTS * SECSIZ)) return OK; i = NSECTS - iobuf->_nleft / SECSIZ; if (write(iobuf -> _fd, iobuf -> _buff, i) != i) return ERROR; i = (i-1) * SECSIZ; if (iobuf -> _nleft) { movmem(iobuf->_buff + i, iobuf->_buff, SECSIZ); iobuf -> _nleft += i; iobuf -> _nextp -= i; return seek(iobuf->_fd, -1, 1); } iobuf -> _nleft = (NSECTS * SECSIZ); iobuf -> _nextp = iobuf -> _buff; return OK; } int fclose(iobuf) struct _buf *iobuf; { return close(iobuf -> _fd); } /* Some string functions */ int atoi(n) char *n; { int val; char c; int sign; val=0; sign=1; while ((c = *n) == '\t' || c== ' ') ++n; if (c== '-') {sign = -1; n++;} while ( isdigit(c+) len++; return len; } /* Some character diddling functions */ int isalpha(c) char c; { return isupper(c) || islower(c); } int isupper(c) char c; { return c>='A' && c<='Z'; } int islower(c) char c; { return c>='a' && c<='z'; } int isdigit(c) char c; { return c>='0' && c<='9'; } int isspace(c) char c; { return c==' ' || c=='\t' || c=='\n'; } char toupper(c) char c; { return islower(c) ? c-32 : c; } char tolower(c) char c; { returnves it could find...) */ qsort(base, nel, width, compar) char *base; int (*compar)(); { int gap,ngap, i, j; int jd, t1, t2; t1 = nel * width; for (ngap = nel / 2; ngap > 0; ngap /= 2) { gap = ngap * width; t2 = gap + width; jd = base + gap; for (i = t2; i <= t1; i += width) for (j = i - t2; j >= 0; j -= gap) { if ((*compar)(base+j, jd+j) <=0) break; _swp(width, base+j, jd+j); } } } _swp(w,a,b) char *a,*b; int w; { char tmp; while(w--) from chapter 8 of K&R, but simplified to ignore the storage allignment problem and not bother with the "morecore" hack (a call to "sbrk" under CP/M is a relatively CHEAP operation, and can be done on every call to "alloc" without degrading efficiency.) Note that compilation of "alloc" and "free" is disabled until the "#define ALLOC_ON 1" statement is un-commented in the header file ("BDSCIO.H"). This is done so that the external storage required by alloc and free isn't declared unless the= q -> _ptr; ; q = p, p = p -> _ptr) { if (p -> _size >= nunits) { if (p -> _size == nunits) q -> _ptr = p -> _ptr; else { p -> _size -= nunits; p += p -> _size; p -> _size = nunits; } _allocp = q; return p + 1; } if (p == _allocp) { if ((cp = sbrk(nunits * sizeof (_base))) == ERROR) return NULL; cp -> _size = nunits; free(cp+1); /* remember: pointer arithmetic! */ p = _allocp; } } } free(ap) struct _header *ap; { struc = *n++)) val = val * 10 + c - '0'; return sign*val; } char *strcat(s1,s2) char *s1, *s2; { char *temp; temp=s1; while(*s1) s1++; do *s1++ = *s2; while (*s2++); return temp; } int strcmp(s,t) char s[], t[]; { int i; i = 0; while (s[i] == t[i]) if (s[i++] == '\0') return 0; return s[i] - t[i]; } char *strcpy(s1,s2) char *s1, *s2; { char *temp; temp=s1; while (*s1++ = *s2++); return temp; } int strlen(s) char *s; { int len; len=0; while (*s+ isupper(c) ? c+32 : c; } /* Other stuff... */ /* This is the new qsort routine, utilizing the shell sort technique given in the Software Tools book (by Kernighan & Plauger.) NOTE: this "qsort" function is different from the "qsort" given in some old releases (pre 1.32) -- here, the items are sorted in ASCENDING order. The old "qsort" sorted stuff in DESCENDING order, and was in part responsible for the atrocious play of the "Othello" program (it always made the WORST mo{tmp=*a; *a++=*b; *b++=tmp;} } /* Initialization functions */ initw(var,string) int *var; char *string; { int n; while ((n = getval(&string)) != -32760) *var++ = n; } initb(var,string) char *var, *string; { int n; while ((n = getval(&string)) != -32760) *var++ = n; } int getval(strptr) char **strptr; { int n; if (!**strptr) return -32760; n = atoi(*strptr); while (**strptr && *(*strptr)++ != ','); return n; } /* Storage allocation routines, taken user actually needs the alloc and free functions. As soon as BDS C gets static variables, this kludge will go away. */ #ifdef ALLOC_ON /* Compilation of alloc and free is enabled only when the ALLOC_ON symbol is #defined in BDSCIO.H */ char *alloc(nbytes) unsigned nbytes; { struct _header *p, *q, *cp; int nunits; nunits = 1 + (nbytes + (sizeof (_base) - 1)) / sizeof (_base); if ((q = _allocp) == NULL) { _base._ptr = _allocp = q = &_base; _base._size = 0; } for (p t _header *p, *q; p = ap - 1; /* No need for the cast when "ap" is a struct ptr */ for (q = _allocp; !(p > q && p < q -> _ptr); q = q -> _ptr) if (q >= q -> _ptr && (p > q || p < q -> _ptr)) break; if (p + p -> _size == q -> _ptr) { p -> _size += q -> _ptr -> _size; p -> _ptr = q -> _ptr -> _ptr; } else p -> _ptr = q -> _ptr; if (q + q -> _size == p) { q -> _size += p -> _size; q -> _ptr = p -> _ptr; } else q -> _ptr = p; _allocp = q; } #endif /* Now some really hairy functions to wrap things up: */ int abs(n) { return (n<0) ? -n : n; } int max(a,b) { return (a > b) ? a : b; } int min(a,b) { return (a <= b) ? a : b; } > _size += q -> _ptr -> _size; p -> _ptr = q -> _ptr -> _ptr; } else p -> _ptr = q -> _ptr; if (q + q -> _size == p) { q -> _size += p -> _size; q -> _ptr = p -> _ptr; } else q -> _ptr = p; _allocp = q; } #endif /* N/* STDLIB2.C -- for BDS C v1.42 -- 11/22/80 This file contains the source for the following library functions: printf fprintf sprintf _spr scanf fscanf sscanf _scn fgets puts fputs swapin Note that all the upper-level formatted I/O functions ("printf", "fprintf", "scanf", and "fscanf") now use "_spr" and "_scn" for doing conversions. While this leads to very modularized source code, it also means that calls to "scanf" and "fscanf" must process ALL the information onne-dimensional character array. The length limit on this array is presently set to 132 by the #define MAXLINE statement; if you intend to create longer lines through printf, fprintf, scanf, or fscanf calls, be SURE to raise this limit by changing the #define statement. Some misc. comments on hacking text files with CP/M: The conventional CP/M text format calls for each line to be terminated by a CR-LF combination. In the world of C programming, though, we like to just use a single LF ( maintaining compat- ibility with the CP/M text format for disk files (so that, for example, a text file can be "type"d under the CCP.) To confuse matters further, the "gets" function (which simply buffers up a line of console input) terminates a line with '\0' (a zero byte) instead of CR or LF. Thus, if you want to read in lines of input from the console and write them to a file, you'll have to manually put out the CR and LF at the end of every line ("gets" was designed this was to bef file: CPMEOF ( 0x1a, or control-Z), ERROR (-1, or 255 if you assign it to a char variable) should the CPMEOF (0x1a) be missing. */ #include "bdscio.h" char toupper(), isdigit(); /* printf usage: printf(format, arg1, arg2, ...); Note that since the "_spr" function is used to form the output string, and then "puts" is used to actually print it out, care must be taken to avoid generating null (zero) bytes in the output, since such a byte will terminate printing of the sееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее a line of text; if the format string runs out and there is still text left in the line being processed, the text will be lost (i.e., the NEXT scanf or fscanf call will NOT find it.) An alternate version of "_spr" is given in the file FLOAT.C for use with floating point numbers; see FLOAT.C for details. Since "_spr" is used by "printf", this really amounts to an alternate version of "printf." Also note that temporary work space is declared within each of the high-level functions as a oalso called a newline) to terminate lines. AND SO, the functions which deal with reading and writing text lines from disk files to memory and vice-versa ("fgets", "fputs") take special pains to convert CR-LF combinations into single '\n' characters when reading from disk ("fgets"), and convert '\n' characters to CR-LF combinations when writing TO disk ("fputs"). This allows the C programmer to do things in style, dealing only with a single line terminator while the text is in memory, while compatible with the UNIX version). Remember to put out a 0x1a (control-Z, CPMEOF) at the end of text files being written out to disk. Also, watch out when reading in text files using "getc". While a text file is USUALLY terminated with a control-Z, it MAY NOT BE if the file ends on an even sector boundary (although respectable editors will now usually make sure the control-Z is always there.) This means that there are two possible return values from "getc" which can signal an End-otring by puts. Thus, a statment such as: printf("%c foo",'\0'); would print nothing at all. This is my latest version of the "printf" standard library routine. This time, folks, it REALLY IS standard. I've tried to make it EXACTLY the same as the version presented in Kernighan & Ritchie: right-justification of fields is now the default instead of left-justification (you can have left-justification by using a dash in the conversion, as specified in the book); the "%s" conversion can take a precision now as well as a field width; the "e" and "f" conversions, for floating point numbers, are supported in a special version of "_spr" given in source form in the FLOAT.C file. If you do a lot of number crunching and wish to have that version be the default (it eats up a K or two more than this version), just replace the version of "_spr" in DEFF.CRL with the one in FLOAT.C, using the CLIB program, or else be stuck with always typing in "float" on the clink command line... */ le each time scanf is called, any unprocessed text left over from the last call is lost forever. This is a difference between BDS scanf and UNIX scanf. Another is that the field width specification is not supported here. */ int scanf(format) char *format; { char line[MAXLINE]; gets(line); /* get a line of input from user */ return _scn(line,&format); /* and scan it with "_scn" */ } /* fprintf: Like printf, except that the first argument is a pointer to a buffered I/O buffe, ptr1, ptr2, ...); Returns number of items matched (zero on EOF.) Note that any unprocessed text is lost forever. Each time scanf is called, a new line of input is gotten from the file, and any information left over from the last call is wiped out. Thus, the text in the file must be arranged such that a single call to fscanf will always get all the required data on a line. This is not compatible with the way UNIX does things, but it eliminates the need for separate scanning functions foreturn 0; return _scn(text,&format); } /* sprintf: Like fprintf, except a string pointer is specified instead of a buffer pointer. The text is written directly into memory where the string pointer points. Usage: sprintf(string,format,arg1, arg2, ...); */ sprintf(buffer,format) char *buffer, *format; { _spr(buffer,&format); /* call _spr to do all the work */ } /* sscanf: Reads a line of text in from the console and scans it for variable values specified in the foruent list of (optional) values. Having arguments passed on the stack works out a heck of a lot neater than it did before when the args were passed via an absolute vector in low memory! */ _spr(line,fmt) char *line, **fmt; { char _uspr(), c, base, *sptr, *format; char wbuf[MAXLINE], *wptr, pf, ljflag; int width, precision, *args; format = *fmt++; /* fmt first points to the format string */ args = fmt; /* now fmt points to the first arg value */ while (c = *format++) printf(format) char *format; { char line[MAXLINE]; _spr(line,&format); /* use "_spr" to form the output */ puts(line); /* and print out the line */ } /* scanf: This one accepts a line of input text from the console, and converts the text to the required binary or alphanumeric form (see Kernighan & Ritchie for a more thorough description): Usage: scanf(format, ptr1, ptr2, ...); Returns number of items matched. Since a new line of text must be entered from the consor, and the text is written to the file described by the buffer: ERROR (-1) returned on error. usage: fprintf(iobuf, format, arg1, arg2, ...); */ int fprintf(iobuf,format) char *format; struct _buf *iobuf; { char text[MAXLINE]; _spr(text,&format); return fputs(text,iobuf); } /* fscanf: Like scanf, except that the first argument is a pointer to a buffered input file buffer, and the text is taken from the file instead of from the console. Usage: fscanf(iobuf, formatr files, strings, and console input; it is more economical to let both "fscanf" and "scanf" use "sscanf". If you want to be able to scan a partial line with fscanf and have the rest still be there on the next fscanf call, you'll have to rewrite fscanf to be self contained (not use sscanf) and use "ungetc" to push back characters. Returns number of items succesfully matched. */ int fscanf(iobuf,format) char *format; struct _buf *iobuf; { char text[MAXLINE]; if (!fgets(text,iobuf)) mat string. Uses "_scn" for actual conversions; see the comments below in the _scn function for more details. Usage: scanf(format,&arg1,&arg2,...); */ int sscanf(line,format) char *line, *format; { return _scn(line,&format); /* let _scn do all the work */ } /* General formatted output conversion routine, used by fprintf and sprintf..."line" is where the output is written, and "fmt" is a pointer to an argument list which must consist of a format string pointer and subseqif (c == '%') { wptr = wbuf; precision = 6; ljflag = pf = 0; if (*format == '-') { format++; ljflag++; } width = (isdigit(*format)) ? _gv2(&format) : 1; if ((c = *format++) == '.') { precision = _gv2(&format); pf++; c = *format++; } switch(toupper(c)) { case 'D': if (*args < 0) { *wptr++ = '-'; *args = -*args; width--; } case 'U': base = 10; goto val; case 'X': base = 16; goto val; case 'O': base = 8; /* note that arbitrary bases can be added easily before this line */ val: width -= _uspr(&wptr,*args++,base); goto pad; case 'C': *wptr++ = *args++; width--; goto pad; case 'S': if (!pf) precision = 200; sptr = *args++; while (*sptr && precision) { *wptr++ = *sptr++; precision--; width--; } pad: *wptr = '\0'; pad2: wptr = wbuf; if (!ljflag) whiernal function which converts n into an ASCII base `base' representation and places the text at the location pointed to by the pointer pointed to by `string'. Yes, you read that correctly. */ char _uspr(string, n, base) char **string; unsigned n; { char length; if (n b-1) return ERROR; else return c; } /* puts: Write out the given string to the console. Ale (width-- > 0) *line++ = ' '; while (*line = *wptr++) line++; if (ljflag) while (width-- > 0) *line++ = ' '; break; default: *line++ = c; } } else *line++ = c; *line = '\0'; } /* Internal routine used by "_spr" to perform ascii- to-decimal conversion and update an associated pointer: */ int _gv2(sptr) char **sptr; { int n; n = 0; while (isdigit(**sptr)) n = 10 * n + *(*sptr)++ - '0'; return n; } /* Int points to a string containing ascii text to be converted, and "fmt" points to an argument list consisting of first a format string and then a list of pointers to the destination objects. Appropriate data is picked up from the text string and stored where the pointer arguments point according to the format string. See K&R for more info. The field width specification is not supported by this version. NOTE: the "%s" termination character has been changed from "any white space" to the chags = fmt; /* now it points to the arg list */ n = 0; while (c = *format++) { if (!*line) return n; /* if end of input string, return */ if (isspace(c)) continue; /* skip white space in format string */ if (c != '%') { /* if not %, must match text */ if (c != _igs(&line)) return n; else line++; } else { /* process conversion */ sign = 1; base = 10; sf = 0; if ((c = *format++) == '*') { sf++; /* if "*" given, supress assignment */ c = *format++; == *format) { format++; break; } if (!sf) *sptr++ = c; } if (!sf) { n++; *sptr = '\0'; args++; } continue; case 'C': if (!sf) { poke(*args++, *line); n++; } line++; continue; default: return n; } if (!sf) { **args++ = val * sign; n++; } }} return n; } /* Internal function to position the character pointer argument to the next non white-space c newline is NOT automatically appended: */ puts(s) char *s; { while (*s) putchar(*s++); } /* fgets: This next function is like "gets", except that a) the line is taken from a buffered input file instead of from the console, and b) the newline is INCLUDED in the string and followed by a null byte. This one is a little tricky due to the CP/M convention of having a carriage-return AND a linefeed character at the end of every text line. In order to make text easier to deal with from C programs, this function (fgets) automatically strips off the CR from any CR-LF combinations that come in from the file. Any CR characters not im- mediately followed by LF are left intact. The LF is included as part of the string, and is followed by a null byte. (Note that LF equals "newline".) There is no limit to how long a line can be here; care should be taken to make sure the string pointer passed to fgets points to an area large enough to accept any possible line length (achar *cptr; count = MAXLINE; cptr = s; if ( (c = getc(iobuf)) == CPMEOF || c == EOF) return NULL; do { if ((*cptr++ = c) == '\n') { if (cptr>s+1 && *(cptr-2) == '\r') *(--cptr - 1) = '\n'; break; } } while (count-- && (c=getc(iobuf)) != EOF && c != CPMEOF); if (c == CPMEOF) ungetc(c,iobuf); /* push back control-Z */ *cptr = '\0'; return s; } /* fputs: This function writes a string out to a buffered output file. The '\n' character is expanded into a CR to swap in a code segment in the area of memory between the end of the root segment and the start of the external data area. See the document "SWAPPING.DOC" for detailed info on the swapping scheme. Returns ERROR (-1) on error, OK (0) if segment loaded in OK. This version does not check to make sure that the code yanked in doesn't overlap into the extenal data area (in the interests of keeping the function short.) But, if you'd like swapin to check for such problems, note that memory rror on %s\n",name); close(fd); return ERROR; } close(fd); return OK; } usual.) By rewriting swapin to read in one sector at a time and check the addresses, accidental overlap into the data area can be avoided. */ swapin(name,addr) char *name; /* the file to swap in */ { int fd; if (( fd = open(name,0)) == ERROR) { printf("Swapin: cannot open %s\n",name); return ERROR; } if ((read(fd,addr,9999)) < 0) { printf("Swapin: read e #define TITLE "BDS Telnet version 2.3 (July 1980)" /* Written by Leor Zolman and Leo Kenen December 1979, March 1980, May 1980, July 1980 This version has been modified to obtain all hardware- dependent information from bdscio.h, which must contain the correct hardware specifications for your modem port. It is also no longer necessary to alter #define statements in this file to reflect CP/M system size; the "topofmem()" function is now used to determine the amount of memory av line must be terminated by a newline (LF, or '\n') character before it is considered complete.) The value NULL (defined to be 0 here) is returned on EOF, whether it be a physical EOF (attempting to read past last sector of the file) OR a logical EOF (encountered a control-Z.) The 1.3 version didn't recognize logical EOFs, because I did't realize how SIMPLE it was to implement a buffered I/O "ungetc" function. */ char *fgets(s,iobuf) char *s; struct _buf *iobuf; { int count, c; -LF combination, in keeping with the CP/M convention. If a null ('\0') byte is encountered before a newline is encountered, then there will be NO automatic termination character appended to the line. ERROR (-1) returned on error. */ fputs(s,iobuf) char *s; struct _buf *iobuf; { char c; while (c = *s++) { if (c == '\n') putc('\r',iobuf); if (putc(c,iobuf) == ERROR) return ERROR; } return OK; } /* swapin: This is the swapping routine, to be used by the root segment locations ram+115h and ram+116h contain the 16-bit address of the base of the external data area (low order byte first, as usual.) By rewriting swapin to read in one sector at a time and check the addresses, accidental overlap into the data area can be avoided. */ swapin(name,addr) char *name; /* the file to swap in */ { int fd; if (( fd = open(name,0)) == ERROR) { printf("Swapin: cannot open %s\n",name); return ERROR; } if ((read(fd,addr,9999)) < 0) { printf("Swapin: read eееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееailable for the text collection buffer. If you intend to use this program for high speed (i.e, greater than 300 baud) data transfers, such as maybe over RS232 lines between two machines directly, then the speed of transfer will be limited by the processors involved instead of the baud rate; UNDER SUCH CIRCUMSTANCES, A TRANSFER WILL ONLY WORK IF THESE TWO CONDITIONS ARE MET: 1) The transfer must always performd in BINARY mode, never in TEXT mode, and 2) The receiving processor must be as fast or FASTER than the transmitting processor. That is, a 2 MHz machine may transmit to a 4 MHz machine at, say, 9600 baud, BUT NOT VICE- VERSA. See the write up by Leo for more details than are presented here. ****************************************** * Telnet assumes that your CP/M console * * I/O device is much faster than your * * modem. On a 2MHz 8080, the modem can * * be receiving at up to 300 baud as long * * as your console whips along (at ering the appropriate command letter. Incoming data may be buffered up in RAM memory and dumped to disk whenever you desire (via the "o", "d", "c" and "k" commands), data may be transmitted from disk to modem (via "t" and "a"), or files can be formally transferred in an alternate "checksum" mode which handles handshaking and buffering automatically when interacting with the same program on the other end of the line. During file transfers, you may temporarily pause and later resume the transmboth parties must make sure that their modems are operating in FULL-DUPLEX. When you are in full duplex, then what you type will NOT come right back at you from the modem; the only input you see from the modem is the data transmitted by the machine on the OTHER end of the line. This program considers "half duplex" to be any situation in which the data you transmit comes right back at you; whether it is your modem that is performing the ehoing or a computer system far away doesn't really matter. In one originating and the other answering, then telnet will both display what each types to the console and send it to the modem. If a file then needs to be transferred, then one user would give the "t" command (to transmit) and the other would give the "o" command (to open an output file.) If both users indicate checksum mode (rather than only one specifing checksum mode which will abort almost immediatly), then telnet will take it from there and perform the transfer. If the sender (transmitter) wape to signal a Telnet command (should be obscure...I use a "control-shift-uparrow") */ /* The following #defines need not be changed: */ #define ACK 0x06 /* Ascii ACK for handshaking */ #define NAK 0x15 #define EOT 0x04 /* End of transmission */ #define ETX 0x03 /* Abort Transmission */ /* External variable declarations: */ char rflag; /* receiving file open flag */ char tflag; /* transmitting file open flag */ char chflag; /* checksumming enabled flag *the * * very least) at about 1200. 4 MHz mach- * * ines might be able to get away with * * slower terminals, but not much slower. * ****************************************** "Telnet" is a program which interacts with a modem to turn your microcomputer into a very versatile terminal. Special commands are entered to the program by typing the character you designate as "SPECIAL", i.e, some character (such as the null or ^A ) which you wouldn't be likely to need transmitted, and then entission (via the "p" and "r" commands.) There are also various options you can control (see "n", "7", "h" and "l") to adapt operation toward the type of file you wish to transfer. The "q" command closes the output file (if open) and quits to CP/M. The "s" command displays the status of the program. "z" clears the console screen. Any other command letter (such as, for example, "?") causes a list of legal commands to be displayed. In order to transmit or receive files in the checksum mode, any case, checksumming and handshaking is not allowed under half- duplex operation, since erroneous characters would be received. When you run telnet, it will ask you whether or not you are in half-duplex, and perform accordingly. If you switch from half to full or vice-versa while running the program, use the "h" option to inform telnet of the fact. To perform checksummed file transfer, a connection must first be established between the two parties. If both parties are operating in full duplex,nts to suspend the transfer temporarily and continue later, he can use the "p" command. When the receiver sees that transmission has been suspended (when no data has been sent for a long time), then HE gives the "p" command also, and both users may type to each other. When ready to resume, the "r" command must be given by the RECEIVER first, and then the sender, to prevent data from being lost. */ #include "bdscio.h" /* System, h'ware constants */ #define SPECIAL 0x1e /* The character you ty/ char cflag; /* text-collection enabled flag */ char pflag; /* pausing flag */ char spflag; /* stripping parity bit flag */ char lflag; /* list device enabled flag */ char nflag; /* recognizing nulls flag */ char fflag; /* true if changing CR-LF's into just CR when transmitting */ char lastc; /* last char xmitted */ char dodflag; /* true if displaying outging data */ char didflag; /* true if displaying incoming data */ char hdflag; /* true if effectively working in half-duplex */ char abortf; /* true when file I/O aborted */ char rbuf[BUFSIZ]; /* file I/O buffer for incoming data file */ char tbuf[SECSIZ]; /* sector buffer for file being transmitted */ char rname[20]; /* name of receiving file */ char tname[20]; /* name of transmitting file */ int rfd, tfd; /* file descriptors */ char *cptr; /* pointer to free space in buf */ unsigned free; /* number of bytes free in buf */ int bcount; /* counts bytes in current char toupper(); /* This makes for better code than if we let it default to "int" */ /* Routine to return true if input is present on the modem: */ miready() { return (inp(MSTAT) & MIMASK) == (MAHI ? MIMASK : 0); } /* Routine to return true if modem is ready to output a byte: */ moready() { return (inp(MSTAT) & MOMASK) == (MAHI ? MOMASK : 0); } main() { char c, c2; int n; init(); loop: if (abortf) { if (rflag) rclose(); if (tflag) se { *cptr++ = c; free--; } if (chflag) { checksum += c2; bcount++; if (bcount == SECSIZ) { bcount = 0; outmod(checksum >> 8); outmod(checksum); checksum = 0; c = getmod(); if (c == EOT) { rdump(0); rclose(); printf("\n%s recieved OK\n",rname); } else if (c == ACK) { if (cptr > buf+1000) rdump(0); if (!didflag) printf("Good sector <%d>\n",++scount); outmod(0xFD); } else { cptr -= SECSIZ; free += SECSIZ; "); switch (toupper(c)) { case '\n': return; case SPECIAL: outmod(SPECIAL); printf("Special char sent\n"); break; case '7': spflag = ask("Strip parity"); break; case 'N': nflag = ask("Recognize incoming nulls"); break; case 'F': fflag = ask("Transmit CR-LF pairs as CR only"); break; case 'H': if (rflag || tflag) { printf( "Must abort transfer first\n"); break; } printf("\nAre you either at half"); "transmission" : "collection"); } goto lf; case 'R': if (!pflag) printf("Not pausing"); else { pflag = 0; dodflag = dod_sav; didflag = did_sav; printf("%s now enabled again.", tflag ? "transmission" : "collection"); } goto lf; case 'K': printf("Text buffer !ZAPPED!"); free = bufspace; cptr = buf; goto lf; case 'V': if (rflag) { putchar('\n'); i = buf; while (i < cptr) putchar block when checksumming */ int scount; /* Number of sectors sent/received */ int checksum; /* the checksum value itself */ char timoutf; /* true if time-out happens while waiting for modem data */ char *i; /* odd-job char pointer */ int dod_sav, did_sav; /* scratch variables */ unsigned bufspace; /* # of bytes available for text collection buffer in ram */ char *buf; /* text collection pointer; will point to the location just after itself */ tabort(); abortf = 0; } if (tflag && xmit()) { printf("\nTransmission complete.\n"); close(tfd); reset(); } if (abortf) goto loop; if (miready()) { c = c2 = getmod(); if (spflag) c &= 0x7f; if (tflag && (c == ETX)) { printf("Reciever has aborted;\n"); abortf = 1; goto loop; } if (didflag && (c || nflag) && (c != CPMEOF)) display(c); if (cflag && !pflag) { if (c || nflag) if (!free) printf("**BUFFER FULL**\007\007"); el printf("\nChecksum error. Retrying <%d>\n",scount+1); outmod(0xFD); timoutf = 0; } } } } } if (kbready()) { c = getch(); if (c != SPECIAL) { if (pflag || (!tflag && !(rflag && chflag))) { outmod(c); if (dodflag) display(c); } } else special(); } goto loop; } /* Handle special Telnet command: */ special() { char c; int n; printf("\nSpecial: "); if ( (c = getchar()) != '\n') printf(" printf("-duplex or getting an "); hdflag = ask ("echo"); reset(); break; case 'L': lflag = ask("List incoming data"); break; case 'Z': printf(CLEARS); break; case 'P': if (pflag) printf("Already pausing"); else if (!(tflag || rflag)) printf("Not transmitting or receiving"); else { pflag = 1; dod_sav = dodflag; did_sav = didflag; dodflag = !hdflag; didflag = 1; printf("Ok, pausing from %s", tflag ? (*i++); printf("\n%u bytes free",free); } else printf("No recieving file open"); goto lf; case 'O': if (rflag) rclose(); if (tflag) tabort(); printf("\nOutput filename? "); gets(rname); rflag = 1; if (!askstuff()) { rflag = 0; return; } printf("Creating %s...",rname); rfd = fcreat(rname,rbuf); if (rfd == ERROR) { printf("Cannot create %s\n",rname); reset(); break; } putchar('\n'); cptr = buf; free = bufspace; rflag = cflag = 1; pflag = checksum = bcount = 0; if (chflag) { printf("Trying to link..."); do { c = getmod(); if (abortf) { printf("aborting...\n"); unlink(rname); reset(); return; } timoutf = 0; } while (c & 0x7f); printf("linked.\n"); outmod(0); } break; case 'D': if (rflag) rdump(1); else printf("No output file"); if (!askstuff()) { tflag = 0; return; } tfd = open(tname,0); if (tfd == ERROR) { printf("Cannot open %s\n",tname); reset(); goto lf; } pflag = checksum = bcount = 0; if (read(tfd,tbuf,1) <=0) { printf("Read error from %s\n", tname); abortf = 1; return; } if (chflag) { printf("Trying to link..."); while (1) { outmod(0); for (n=0; n<5000; n++) if (miready( printf("p: Pause (suspend collection or transmission)\n"); printf("r: Resume after pausing\n"); printf("d: Dump (append) text buffer to output file\n"); printf("c: Close output file (after dumping buffer)\n"); printf("v: View contents of text buffer\n"); printf("k: Kill (erase) contents of text buffer\n"); printf("t: Transmit a file to modem\n"); printf("a: Abort transfer of file\n"); printf("n: accept or ignore Nulls\n"); printf("7: select policy regarding Parity bits\n"); printf("f: suf + 500 - topofmem(); /* compute space available */ bufspace = -bufspace; /* for text collection buf */ printf("\n\nAnswer `y' if either your modem is set to half-duplex,\n"); printf("or you expect an echo from the system on the"); printf(" other end\n"); printf("of the line; else answer `n':\n"); hdflag = ask("Do you expect an echo"); reset(); printf("OK; you're on line...\n\n"); } /* Get all the info pertinent to a file transfer; i.e, whether or not the file is text (and" : "not ", rflag ? "incoming" : "outgoing"); } else { spflag = didflag = dodflag = 0; nflag = 1; printf("%s all data verbatim, and not\n", rflag ? "Recieving" : "Sending"); printf("displaying it on the console.\n"); } putchar('\n'); printf("Handshaking & checksumming can only happen\n"); printf("if the other computer has this same program\n"); printf("running. Do you want handshaking & checksumming"); chflag = ask(""); if (chflag && hdflag) { printf("Can't do it goto lf; case 'C': if (rflag) rclose(); else printf("No output file"); goto lf; case 'Q': if (tflag) tabort(); if (rflag) rclose(); exit(); case 'A': if (tflag || rflag) { if (chflag) outmod(ETX); abortf = 1; break; } printf("No transfer to abort.\n"); goto lf; case 'T': if (tflag) tabort(); if (rflag) rclose(); printf("\nFile to transmit? "); gets(tname); tflag = 1; )) { if( !(getmod() & 0x7f)) { printf("linked.\n"); return; } } else if (kbabort()) { printf("aborting.\n"); return; } } } break; case 'S': dostat(); goto lf; default: prcoms(); lf: putchar('\n'); } } /* Print out legal Telnet commands: */ prcoms() { printf("\nBDS Telnet commands are:\n"); printf("Double SPECIAL: send SPECIAL\n"); printf("o: Open output file, start collection\n"); elect whether to transmit CR-LF as just CR\n"); printf("h: set Half/full duplex mode\n"); printf("l: control CP/M List device\n"); printf("z: clear console terminal screen\n"); printf("s: display Status of Telnet\n"); printf("q: dump & close output file (if open) and Quit to CP/M"); } /* Print opening message and initialize program: */ init() { printf(TITLE); timoutf = cflag = nflag = lflag = pflag = abortf = fflag = 0; spflag = 1; lastc = 0; buf = &buf + 1; bufspace = b needs parity stripped, nulls ignored, echoing to console, etc.), whether or not checksumming and handshaking are required (they always go together), and make sure the user is in full duplex mode. */ askstuff() { printf("\n%s ",rflag ? "recieving" : "transmitting"); if (ask("text (y) or binary data (n) ")) { nflag = 0; spflag = didflag = 1; dodflag = !hdflag; printf("Stripping parity, ignoring nulls,\n"); printf(" %sdisplaying %s data.\n", (rflag ? didflag : dodflag) ? " unless you can eliminate"); printf(" the echo! Aborting.\n"); return 0; } scount = 0; return ask("OK...type y to begin, n to abort:"); } /* Routine to print out a string and return true if the user responds positively */ int ask(s) char *s; { char c; while (1) { printf("%s ",s); printf("(y/n)? "); c = toupper(getchar()); if (c == 'Y') { printf("es\n"); return 1; } else if (c == 'N') { printf("o\n"); return 0; } else putchar('\n'); } } /* Print out state of Telnet program: */ dostat() { putchar('\n'); if (rflag) { printf("Output file = %s\n",rname); printf("Text buffer has %u bytes free", free); printf("\nText collection: "); if (cflag) if (pflag) printf("on, but pausing\n"); else printf("on\n"); else printf("off\n"); } else printf("No output file\n"); if (tflag) { printf("Transmitting: %s ", tname); if (pflag) printf("(but pausing)"); pu this is here only to make up for a strange "feature" of Lifeboat's Northstar CBIOS where disk polling happens during console output, potentially causing bytes to be missed from the modem.) */ rdump(n) { for (i=buf; i\n",++scount); outmod(ACK); } else { outmod(EOT); return 1; } checksum = 0; if (getmod() != 0xFD) { printf("\nPhase error; aborting..."); abortf = 1; } return 0; } /* Read a sector of the transmission file: */ read1() { int i; i = read(tfd, tbufееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее /* Tabify.c written by Leor Zolman This filter takes sequences of spaces in a file and turns them, whenever possible, into tabs. Usage: A>tabify oldfile newfile Quoted strings are not processed, but there should NOT be any `lone' double quotes within the file being tabified. */ #include "bdscio.h" main(argc,argv) char **argv; { int scount, column, ifd, ofd, i; int c; char ibuf[BUFSIZ], obuf[BUFSIZ]; if (argc != 3) { printf("usage: tabify oldfile newfile\n"); putc1('\t',obuf); else putc1(' ',obuf); scount = 0; } break; case '\t': scount = 0; column += (8-column%8); putc1('\t',obuf); break; case '"': putc1('"',obuf); do { c = getc(ibuf); if (c == ERROR) { printf("Quote error.\n"); exit(); } putc1(c,obuf); } while (c != '"'); do { c = getc(ibuf); putc1(c,obuf); } while (c != '\n'); column = scount = 0; break; ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее exit(); } ifd = fopen(argv[1],ibuf); ofd = fcreat(argv[2],obuf); if (ifd == ERROR || ofd == ERROR) { printf("Can't open file(s)\n"); exit(); } scount = column = 0; do { c = getc(ibuf); if (c == ERROR) { putc(CPMEOF,obuf); break; } switch(c) { case '\r': putc1(c,obuf); scount = column = 0; break; case '\n': putc1(c,obuf); scount = 0; break; case ' ': column++; scount++; if (!(column%8)) { if (scount > 1) case 0x1a: putc(CPMEOF,obuf); break; default: for (i=0; i