home *** CD-ROM | disk | FTP | other *** search
Wrap
#! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # README # socket.c # igc.c # parse.c # ascii.c # board.c # numbers.h # igc.h # Makefile # igc.6 # BUGS # This archive created: Mon Jun 7 19:44:51 1993 export PATH; PATH=/bin:/usr/bin:$PATH if test -f 'README' then echo shar: "will not over-write existing file 'README'" else cat << \SHAR_EOF > 'README' IGS - Ascii Client by Adrian Mariano adrian@u.washington.edu adrian on igs This is an ascii client program for the Internet Go Server. Its purpose is to provide a useable interface to the server with ASCII character drawn Go boards. This program requires UNIX with sockets capability. Read the Makefile for instructions on compiling. SHAR_EOF fi if test -f 'socket.c' then echo shar: "will not over-write existing file 'socket.c'" else cat << \SHAR_EOF > 'socket.c' #include <sys/types.h> #include <sys/time.h> #include <sys/socket.h> #include <netdb.h> #ifndef WINS /* Usually want this... */ #include <netinet/in.h> #else /* ... but need these for WINS. */ #include <sys/in.h> #include <sys/inet.h> #endif #include <fcntl.h> #include <sys/errno.h> #include <stdio.h> #ifndef FD_ZERO #include <sys/select.h> #endif #include "igc.h" /* For some odd systems, which don't put this in errno.h. */ extern int errno; char servename[80]; int serveport; int sock; char inbuf[1000]; int inptr = 0; int doecho = 1; sethost(s) char *s; { strcpy(servename, s); } setport(s) int s; { serveport = s; } void close_connection() { close(sock); } #ifdef DEBUG FILE *blah; #endif setecho(ec) int ec; { doecho = ec; } int open_connection() { struct sockaddr_in server; struct hostent *hp; int ipn; printf("Opening connection to %s %d\n", servename, serveport); #ifdef DEBUG { int d; char n[444]; d = 0; do { sprintf(n, "dump%d.igc", d); blah = fopen(n, "r"); if (!blah) { blah = fopen(n, "w"); if (blah) printf("Creating dump file %s\n", n); break; } close(blah); d++; if (d > 9) { printf("Too many dump files. Delete dump files (dump?.igc)? "); fgets(n, 443, stdin); if (n[0] != 'Y' && n[0] != 'y') exit(1); for (d = 0; d < 10; d++) { sprintf(n, "dump%d.igc", d); unlink(n); } blah = fopen("dump0.igc", "w"); if (!blah) { printf("File open error. Cannot create dump file\n"); exit(1); } break; } } while (1); if (!blah) { printf("File open error. Cannot create dump file.\n"); exit(1); } } #endif if (sscanf(servename, "%d.%d.%d.%d", &ipn, &ipn, &ipn, &ipn) == 4) server.sin_addr.s_addr = inet_addr(servename); else { hp = gethostbyname(servename); if (hp == 0) { puts("Unknown host"); return -1; } bcopy(hp->h_addr, &server.sin_addr, hp->h_length); } server.sin_family = AF_INET; server.sin_port = htons(serveport); sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { perror("socket"); return -1; } if (connect(sock, (struct sockaddr *) & server, sizeof(struct sockaddr_in)) < 0) { perror("connect"); return -1; } return 0; } sendstr(buf) char *buf; { #ifdef DEBUG if (doecho && strlen(buf) && blah && buf[0] != '\377') fprintf(blah, ">%s<\n", buf); #endif write(sock, buf, strlen(buf)); } /* returns 1 if telnet processing ate the character. */ #define IAC '\377' #define DONT '\376' #define DO '\375' #define WONT '\374' #define WILL '\373' #define AYT '\366' #define TELOPT_SGA '\3' #define TELOPT_ECHO '\1' int dotelnet(ch) char ch; { static int telcount = 0; static char telchars[4]; if (ch == IAC || telcount == 1) { telchars[telcount] = ch; telcount++; if (telcount == 2 && telchars[1] == AYT) { telcount = 0; sendstr("igc-yes\n"); return 0; } return 1; } if (telcount == 2) { telcount = 0; telchars[2] = ch; telchars[3] = 0; if (telchars[2] == TELOPT_ECHO) { setecho(telchars[1] == WONT); return 1; } if (telchars[1] == WILL) { if (telchars[2] == TELOPT_SGA) telchars[1] = DO; else telchars[1] = DONT; } else if (telchars[1] == DO) { if (telchars[2] == TELOPT_SGA) telchars[1] = WILL; else telchars[1] = WONT; } sendstr(telchars); return 1; } return 0; } int handlechar(retbuf, in) char *retbuf; char in; { if (in == '\r') return 0; #ifdef DEBUG fputc(in, blah); #endif if (dotelnet(in)) return 0; if (in == '\n') { inbuf[inptr] = 0; strcpy(retbuf, inbuf); inptr = 0; return 1; } else { inbuf[inptr++] = in; if (doneline(inbuf, inptr)) { inbuf[inptr] = 0; strcpy(retbuf, inbuf); inptr = 0; return 1; } } return 0; } int bufdata = 0, bufptr = 0; char thebuf[1000]; int pollserver(retbuf, checkstdin) char *retbuf; int checkstdin; { int sel; fd_set readers; FD_ZERO(&readers); while (1) { while (bufdata) { bufdata--; if (handlechar(retbuf, thebuf[bufptr++])) return 1; } bufptr = 0; if (checkstdin) FD_SET(0, &readers); /* Check stdin */ FD_SET(sock, &readers); sel = select(sock + 1, &readers, NULL, NULL, (struct timeval *) 0); if (sel == -1) { if (errno != EINTR) { /* ^Z will do this */ perror("select"); return -1; } continue; } if (FD_ISSET(sock, &readers)) { bufdata = read(sock, thebuf, 1000); if (!bufdata) return -1; if (bufdata < 0) { perror("read"); return -2; } } else if (FD_ISSET(0, &readers)) return KEY; } } SHAR_EOF fi if test -f 'igc.c' then echo shar: "will not over-write existing file 'igc.c'" else cat << \SHAR_EOF > 'igc.c' #include "igc.h" #include <stdio.h> #include <string.h> #include <signal.h> #include <pwd.h> #include "numbers.h" #define RCNAME "/.igcrc" #define ATRC 1 #define NOTATRC 2 #define BOTH (ATRC | NOTATRC) char login[20] = ""; char password[20] = ""; char friend[MAXFRIENDS][MAXNAME]; /* friends list */ int nfriends = 0; message mesg; /* structure for getting parsed info from * server */ char prefix[21]; /* Text prefix for each outgoing line */ int xcur = -1, ycur = -1; /* Cursor locations on board */ int boardon = 0; /* Is the board being displayed? */ int boardmode = 0; /* Are we on the board? */ int beepcount = 1; /* Number of beeps to send */ int saybeep = 0; /* Beep on say strings? */ int tellbeep = 0; /* Beep on tell strings? */ int friendfilter = 0; /* Filter login messages for friends? */ int displayintro = 1; /* Display intro before log in */ int ingame = -1; /* Game which is displayed, -1 for none */ int observing = 0; /* Are we observing a game? */ int justpeeked = 0; /* Fixup flag for game number after peek */ int needrestore = 0; /* Need to restore board? (After status) */ int bschange = 0; /* boardsize changed? Used with needrestore */ extern int boardsize; char local[1000], *loc; /* Buffer for characters typed by local user */ struct { char white[21], wrank[10], black[21], brank[10]; int hcap; float komi; int bbyo, wbyo, wtime, btime; } curgame; /* Information about current game */ int (*whosort) (); int (*gamessort) (); #define MAXSITES 10 struct { char name[50]; char site[100]; int port; } sitetable[MAXSITES] = { { "hellspark", "hellspark.wharton.upenn.edu", 6969 }, { "pasteur", "ftp.pasteur.fr", 6969 }, { "", "", 6969 }, { "", "", 6969 }, { "", "", 6969 }, { "", "", 6969 }, { "", "", 6969 }, { "", "", 6969 }, { "", "", 6969 }, { "", "", 6969 } }; void myexit(ex) int ex; { if (boardon) endAscii(); exit(ex); } void handleterm() { close_connection(); myexit(0); } char *getpassword(repeat) int repeat; { char trash[20]; if (repeat || !strlen(password)) { printf("Password: "); for (;;) { fgets(password,20,stdin); if (feof(stdin)) handleterm(); if (password[strlen(password)-1]!='\n'){ password[strlen(password)-1]='\n'; do{ fgets(trash,20,stdin); }while (trash[strlen(trash)-1]!='\n'); } if (strstr(password, "helpigc")) printf("You are entering your password for the Internet Go Server. You will be\nprompted twice for your password if you are creating a new account. Enter\nthe same password twice in this case.\nPassword: "); else if (!strlen(password)) printf("Empty password not allowed.\nPassword: "); else break; } } return password; } char *getloginname(repeat) int repeat; { char trash[20]; if (repeat == 1) printf("Login failed.\n"); if (repeat || !strlen(login)) { printf("Login: "); for (;;) { fgets(login,20,stdin); if (feof(stdin)) handleterm(); if (login[strlen(login)-1]!='\n'){ login[strlen(login)-1]='\n'; do{ fgets(trash,20,stdin); }while (trash[strlen(trash)-1]!='\n'); } if (strstr(login, "helpigc")) printf("You are logging into the Internet Go server. Type a login name now.\nLogin: "); else if (!strlen(login)) printf("Blank names not allowed.\nLogin: "); else break; } } else printf("Logging on as %s", login); return login; } putstr(s) char *s; { if (boardon) { addstring(s); addchar('\n'); } else puts(s); } dobeep() { char ch; for (ch = beepcount; ch--;) putchar(7); } readrc() { struct passwd *pw; char rcfilename[1000]; FILE *rcfile; char *var, *val, line[100], saveline[100]; pw = getpwuid(geteuid()); strcpy(rcfilename, pw->pw_dir); strcat(rcfilename, RCNAME); if (rcfile = fopen(rcfilename, "rt")) { while (fgets(line, 99, rcfile)) { if (*line == '#') continue; strcpy(saveline, line); if (!process(line, 0, ATRC)) { if (saveline[strlen(saveline) - 1] == '\n') saveline[strlen(saveline) - 1] = 0; printf("%%Unknown command '%s' in .igcrc file\n", saveline); } } } } void dopassword(first) char *first; { strncpy(password, first, 18); strcat(password, "\n"); password[20]=0; } void dologin(first) char *first; { strncpy(login, first, 18); strcat(login, "\n"); login[20]=0; } void handletstp() { signal(SIGTSTP, handletstp); if (boardon) suspend(); kill(getpid(), SIGSTOP); if (boardon) { unsuspend(); if (boardmode) boardrefresh(); else serverrefresh(); } } int startgame(n) int n; { char str[100], str2[30]; int ret, gotmove; gotmove = 0; sprintf(str, "games %d\n", n); sendstr(str); do { do { ret = getmessage(&mesg, 0); if (ret < 0) handleterm(); } while (!ret); if (mesg.id == MOVE) { if (mesg.movecount) putstr("%Premature move. Restart game."); else gotmove = 1; } } while (mesg.id != GAMES); if (mesg.gamecount != 1 || mesg.gamelist[0].gnum != n) return -1; if (mesg.gamelist[0].bsize > 19) { putstr("%Boardsize too large"); return -1; } strcpy(curgame.white, mesg.gamelist[0].white); strcpy(curgame.black, mesg.gamelist[0].black); strcpy(curgame.brank, mesg.gamelist[0].brank); strcpy(curgame.wrank, mesg.gamelist[0].wrank); curgame.hcap = mesg.gamelist[0].hcap; curgame.komi = mesg.gamelist[0].komi; if (observing) { addstring("Removing observe\n"); sprintf(str, "observe %d\n", ingame); sendstr(str); do { do { ret = getmessage(&mesg, 0); if (ret < 0) handleterm(); } while (!ret); } while (mesg.id != PROMPT); observing = 0; } ingame = n; needrestore = 0; initboard(mesg.gamelist[0].bsize); displaygamenumber(ingame); xcur = ycur = mesg.gamelist[0].bsize / 2; sprintf(str, "%s (%s)", curgame.black, curgame.brank); sprintf(str2, "%s (%s)", curgame.white, curgame.wrank); boardtitle(str, str2); if (gotmove) highlight(0, 0, 0, 0, mesg.btime, mesg.bbyo, mesg.wtime, mesg.wbyo); showkomi(curgame.komi); boardon = 1; return 0; } getmoves(n) int n; { char str[20]; sprintf(str, "moves %d\n", n); sendstr(str); } unobserve() { sendstr("unobserve\n"); /* char str[20]; sprintf(str, "observe %d\n", ingame); sendstr(str); */ } int observegame(n) int n; { int ret; char str[20]; if (n < 0) return 1; if (startgame(n)) return 1; sprintf(str, "observe %d\n", n); sendstr(str); observing = 1; do { do { ret = getmessage(&mesg, 0); if (ret < 0) handleterm(); } while (!ret); if ((mesg.id == INFO) && !strncmp(mesg.text, "Removing", 8)) putstr("%fatal sync error. Restart igc."); } while (mesg.id != MOVE && mesg.id != UNDO); getmoves(n); return 0; } int peekgame(n) int n; { /* if (!observing && ingame != -1) { putstr("Can't peek while playing."); * return 1; } */ if (startgame(n)) return 1; getmoves(n); justpeeked = 1; setgame(-1); return 0; } setgame(newgame) int newgame; { if (newgame != ingame) { ingame = newgame; displaygamenumber(ingame); } } loadgame(name) char *name; { char str[100]; int ret; sprintf(str, "load %s\n", name); sendstr(str); do { ret = getmessage(&mesg, 0); if (ret < 0) handleterm(); } while ((!ret) || (mesg.id != MOVE && mesg.id != ERROR && mesg.id != PROMPT)); if (mesg.id == ERROR) putstr(mesg.text); else if (mesg.id == PROMPT) putstr("%Load error."); else { if (!startgame(mesg.gamenum)) getmoves(mesg.gamenum); } } char *helpmsg = " Server Window\n\ unobserve Stops observing.\n\ peek <n> Looks at the board for game n\n\ restore Restores active game (after look or status)\n\ noboard Goes back to full screen mode\n\ clear Clears the window on the right side of the screen\n\ [no]inverse Switches board to/from inverse \n\ [no]invedge Turns on/off inversed edges\n\ [no]piecemarks Turns on/off piece marks\n\ [no]edgemarks Turns on/off edge marks\n\ sort {none|rank|rating|game|name|idle} Chooses sorting order for who command\n\ gamessort {none|number|obcount} Chooses sorting order for games command\n\ user <name> Checks output from last who for <name>\n\ chars <list> Sets board characters in client\n\ border <char> Sets the border character\n\ beeps <n> Sets number of beeps to use\n\ [no]saybeep Turns on/off beeps when a say is received\n\ [no]tellbeep Turns on/off beeps when a tell is received\n\ goto <n> Goes to a particular move in the current game.\n\ [no]filter Turn filtering of shouts on/off\n\ [un]friend Add or remove a name from the friends list\n\ prefix Sets prefix for all outgoing text you type\n\ Start commands with '!' to avoid using the prefix\n\ \n\ ESC switches between windows ^L refreshes the screen\n\ \n\ Board Window\n\ Use number keys (12346789), emacs keys (^P ^N ^F ^B) or rogue keys\n\ (hjklbnyu) to move the cursor.\n\ Press '0', return, or space to move (send position of cursor)\n\ Press '.' or '>' to move forward through game, ',' or '<' to move backwards.\n\ '.' and ',' move by single moves. '>' and '<' move by sets of ten moves.\n\ Press 's' to go to start of game, 'e' to go to end.\n\ Press 'f' or '/' to find the a particular move in a game by location.\n\ Press 'c' to clear the current move mark."; void help() { if (boardon) bigmess(33, helpmsg); else puts(helpmsg); } doargs(argc, argv) int argc; char *argv[]; { int i; for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "-s")) { int j; for (j = i; j < 3; j++) argv[j] = argv[j + 1]; strcpy(login, ""); strcpy(password, ""); argc--; break; } } if (argc > 3) { printf("Too many command line arguments\n\n"); exit(3); } if (argc > 1) { for (i = 0; i < 10; i++) if (!strcmp(argv[1], sitetable[i].name)) { sethost(sitetable[i].site); setport(sitetable[i].port); if (argc > 2) { printf("Error: port specified with named host. Don't use a port number\n"); printf("when using the shorthand name for a host.\n\n"); exit(3); } return; } sethost(argv[1]); if (argc > 2) { if (atoi(argv[2])) setport(atoi(argv[2])); else { printf("Illegal port specification\n\n"); exit(3); } } } } weave() { char *copy[MAXWHO]; int i, num; num = mesg.whocount / 2 + (mesg.whocount & 1); for (i = 0; i < num * 2; i++) copy[i] = mesg.who[i]; for (i = 0; i < num; i++) { mesg.who[2 * i] = copy[i]; mesg.who[2 * i + 1] = copy[num + i]; } } #define NAMECOL 12 #define IDLECOL 25 #define RANKCOL 32 #define RATECOL 33 #define FLAGCOL 2 #define GAMECOL 10 int namesort(left, right) char *left, *right; { return strncasecmp(*(char **) left + NAMECOL, *(char **) right + NAMECOL, 11); } int gamesort(left, right) char *left, *right; { int i; char *a, *b; a = *(char **) left; b = *(char **) right; if (a[GAMECOL] != '-' && b[GAMECOL] != '-') { i = strncmp(a + GAMECOL - 2, b + GAMECOL - 2, 3); return i ? i : namesort(left, right); } if (a[GAMECOL] != '-') return -1; if (b[GAMECOL] != '-') return 1; if (a[FLAGCOL] != b[FLAGCOL]) { if (a[FLAGCOL] == 'X') return -1; if (b[FLAGCOL] == 'X') return 1; if (a[FLAGCOL] == '!') return 1; if (b[FLAGCOL] == '!') return -1; } return ranksort(left, right); } int ratingsort(left, right) char *left, *right; { char *a, *b; a = *(char **) left; b = *(char **) right; if (a[RATECOL] == b[RATECOL]) return ranksort(left, right); if (a[RATECOL] == '*') return -1; return 1; } int ranksort(left, right) char *left, *right; { int i; char *a, *b; a = *(char **) left; b = *(char **) right; if (a[RANKCOL] == '2') return -1; if (b[RANKCOL] == '2') return 1; if (a[RANKCOL] != b[RANKCOL]) { if (a[RANKCOL] == '?') return 1; if (b[RANKCOL] == '?') return -1; if (a[RANKCOL] == 'R') return 1; if (b[RANKCOL] == 'R') return -1; if (a[RANKCOL] == 'k') return 1; if (b[RANKCOL] == 'k') return -1; if (a[RANKCOL] == 'd') return 1; if (b[RANKCOL] == 'd') return -1; return namesort(a, b); } if (a[RANKCOL] == 'R' || a[RANKCOL] == '?') return namesort(left, right); i = atoi(a + RANKCOL - 2) - atoi(b + RANKCOL - 2); if (a[RANKCOL] == 'k') i = -i; return i ? -i : namesort(left, right); } /******************* * idlesort decides whether a or b has been idle longer *******************/ int idlesort(left, right) char *left, *right; { int i; char *a, *b; a = *(char **) left; b = *(char **) right; /* first check the units letter (h,m,s) assume that we don't need to worry * about d. */ if (a[IDLECOL] != b[IDLECOL]) { if (a[IDLECOL] == 'h') return -1; if (b[IDLECOL] == 'h') return 1; if (a[IDLECOL] == 'm') return -1; if (b[IDLECOL] == 'm') return 1; } i = atoi(b + IDLECOL - 2) - atoi(a + IDLECOL - 2); return i ? i : namesort(left, right); } int gamenumsort(a, b) struct gametype *a; struct gametype *b; { if (a->gnum < b->gnum) return -1; if (a->gnum > b->gnum) return 1; return 0; } int gamesobsort(a, b) struct gametype *a; struct gametype *b; { if (a->obcount > b->obcount) return -1; if (a->obcount < b->obcount) return 1; return 0; } int choosegamessort(first) char *first; { if (!first) return 1; if (!strcmp(first, "number")) { gamessort = gamenumsort; return 0; } if (!strcmp(first, "none")) { gamessort = NULL; return 0; } if (!strcmp(first, "obcount")) { gamessort = gamesobsort; return 0; } return 1; } int choosesort(first) char *first; { if (!first) return 1; if (!strcmp(first, "name")) { whosort = namesort; return 0; } if (!strcmp(first, "rank")) { whosort = ranksort; return 0; } if (!strcmp(first, "game")) { whosort = gamesort; return 0; } if (!strcmp(first, "none")) { whosort = 0; return 0; } if (!strcmp(first, "idle")) { whosort = idlesort; return 0; } if (!strcmp(first, "rating")) { whosort = ratingsort; return 0; } return 1; } restoregame() { char str[30], str2[30]; if (needrestore) { if (bschange) initboard(bschange); restoremaxmoves(); endgame(); needrestore = 0; sprintf(str, "%s (%s)", curgame.black, curgame.brank); sprintf(str2, "%s (%s)", curgame.white, curgame.wrank); boardtitle(str, str2); highlight(0, 0, 0, -1, curgame.btime, curgame.bbyo, curgame.wtime, curgame.wbyo); displaygamenumber(ingame); } } void dofilter(first) int first; { friendfilter = first; } void dofriend(who) char *who; { int i; char buff[60]; if (!who) { putstr("%Current list of friends:\n"); for (i = 0; i < nfriends; i++) putstr(friend[i]); } else { if (nfriends >= MAXFRIENDS) putstr("%Friend list is full."); else if (-1 != find_friend(who)) { sprintf(buff, "%%Player %s already in friend list.", who); putstr(buff); } else { strcpy(friend[nfriends], who); nfriends++; sprintf(buff, "%%Friend %s added.", who); putstr(buff); } } } int isfriend(text) char *text; { int i, length; if (*text != '{') return 1; text++; for (i = 0; i < nfriends; i++) { length = strlen(friend[i]); if (!strncmp(friend[i], text, length) && text[length] == ' ') return 1; } return 0; } void dounfriend(who) char *who; { char i; if (!who) putstr("%unfriend requires 1 parameter."); else if (-1 != (i = find_friend(who))) { for (; i < nfriends; i++) strcpy(friend[i], friend[i + 1]); nfriends--; putstr("%Friend removed."); } else putstr("%Friend not in list."); } int find_friend(fr) char *fr; { char i; for (i = 0; i < nfriends && strcmp(friend[i], fr); i++); return i == nfriends ? -1 : i; } main(argc, argv) int argc; char *argv[]; { char ch; int ret; puts("\tigc - Ascii Client version 0.70 by Adrian Mariano"); puts(" type 'helpigc' to get client help, 'help' for server help\n"); strcpy(prefix, ""); whosort = namesort; gamessort = gamenumsort; readrc(); sethost(sitetable[0].site); setport(sitetable[0].port); doargs(argc, argv); loc = local; signal(SIGINT, handleterm); signal(SIGTERM, handleterm); signal(SIGHUP, handleterm); signal(SIGTSTP, handletstp); if (open_connection()) handleterm(); puts("Connection established."); mesg.whocount = 0; { char *whoptr; for (whoptr = &(mesg.whodata[0][0]), ret = 0; ret < MAXWHO; ret++, whoptr += 40) mesg.who[ret] = whoptr; } initparser(); do { if (boardon) if (boardmode) boardrefresh(); else serverrefresh(); ret = getmessage(&mesg, 1); if (ret < 0 && ret != KEY) { if (boardon) { endAscii(); boardon = 0; } puts("Connection closed by server."); myexit(0); } if (ret > 0) switch (mesg.id) { case TOOMANY: myexit(0); printf("Too many players. Sorry.\n"); break; case QUITMESG: if (boardon) { endAscii(); boardon = 0; } puts(mesg.text); break; case ONSERVER: printf("\nWarning: Client mode is not set on the IGS. Setting client mode now.\n The message of the day was not displayed. Type 'help motd' to see it.\n You have not been informed if you have messages.\n\n"); break; case BEEP: if (mesg.beep) dobeep(); break; case MOVE: if (!boardon) puts("%Error: isolated move received"); else { int i; restoregame(); sethighlight(0); for (i = 0; i < mesg.movecount - 1; i++) makemove(mesg.moves[i].x, mesg.moves[i].y, mesg.moves[i].movenum, mesg.moves[i].color, mesg.btime, mesg.bbyo, mesg.wtime, mesg.wbyo); sethighlight(1); if (mesg.movecount) makemove(mesg.moves[i].x, mesg.moves[i].y, mesg.moves[i].movenum, mesg.moves[i].color, mesg.btime, mesg.bbyo, mesg.wtime, mesg.wbyo); curgame.bbyo = mesg.bbyo; curgame.btime = mesg.btime; curgame.wtime = mesg.wtime; curgame.wbyo = mesg.wbyo; setcursor(xcur, ycur); if (!justpeeked) setgame(mesg.gamenum); justpeeked = 0; } break; case UNDO: restoregame(); if (!boardon) puts("%Error: isolated undo received"); else { setgame(mesg.gamenum); undo(); setcursor(xcur, ycur); } break; case SCOREUNDO: restoregame(); if (endgame()) putstr("%score undo error"); else putstr("Scoring undone."); break; case LOAD: if (!startgame(mesg.gamenum)) getmoves(mesg.gamenum); break; case MATCH: startgame(mesg.gamenum); break; case REMOVE: restoregame(); removeGroup(mesg.x, mesg.y); setcursor(xcur, ycur); break; case SCORE: { char str[50]; sprintf(str, " %s (B): %g\n %s (W): %g", mesg.black, mesg.bscore, mesg.white, mesg.wscore); putstr(str); } break; case STARTSCORE: putstr("Remove dead groups to score."); putstr(mesg.text); break; case STATUS: case LOOK: { int pris[2]; char str[30], str2[30]; if (mesg.boardsize > 19) putstr("%Boardsize too big."); else { needrestore = 1; bschange = 0; savemaxmoves(); if (!boardon || boardsize != mesg.boardsize) { if (!boardon) needrestore = 0; else bschange = boardsize; initboard(mesg.boardsize); xcur = ycur = mesg.boardsize / 2; boardon = 1; } pris[0] = mesg.bcap; pris[1] = mesg.wcap; sprintf(str, "%s (%s)", mesg.black, mesg.brank); sprintf(str2, "%s (%s)", mesg.white, mesg.wrank); boardtitle(str, str2); highlight(0, 0, 0, -1, mesg.btime, mesg.bbyo, mesg.wtime, mesg.wbyo); drawpris(pris); showboard(mesg.board); displaygamenumber(-2); } } break; case KIBITZ: { char s[300]; sprintf(s, "%s: %s", mesg.kibitzer, mesg.kibitz); putstr(s); } break; case WHO: { char out[80 * MAXWHO]; int i; if (whosort) { qsort(mesg.who, mesg.whocount, sizeof(char *), whosort); weave(); } strcpy(out, mesg.whofirst); for (i = 0; i < mesg.whocount; i++) { strcat(out, i & 1 ? " | " : "\n"); strcat(out, mesg.who[i]); } strcat(out, "\n"); strcat(out, mesg.wholast); if (boardon) bigmess(mesg.lines, out); else putstr(out); } break; case GAMES: { char out[80 * MAXGAMES]; int i; if (gamessort) qsort(mesg.gamelist, mesg.gamecount, sizeof(struct gametype), gamessort); strcpy(out, mesg.gamefirst); strcat(out, "\n"); for (i = 0; i < mesg.gamecount; i++) strcat(out, mesg.gamelist[i].gametext); if (boardon) bigmess(mesg.gamecount + 1, out); else putstr(out); } break; case STORED: if (!strlen(mesg.text)) putstr("No stored games"); else putstr(mesg.text); break; case CHKOMI: curgame.komi = mesg.mykomi; showkomi(curgame.komi); case INFO: if (strstr(mesg.text, "Removing")) { observing = 0; setgame(-1); putstr(mesg.text); } else if (mesg.lines > 1 && boardon) bigmess(mesg.lines, mesg.text); else if (strlen(mesg.text)) putstr(mesg.text); break; case PROMPT: if (ingame != -1 && mesg.prompttype == 5) { setgame(-1); observing = 0; } break; case ENDGAMEINFO: if (observing && mesg.gamenum == ingame){ setgame(-1); observing = 0; } putstr(mesg.text); break; case ENDGAME: if (observing && mesg.gamenum == ingame){ setgame(-1); observing = 0; } case SHOUT: if (!friendfilter || isfriend(mesg.text)) putstr(mesg.text); break; case SAY: if (saybeep) dobeep(); putstr(mesg.text); break; case TELL: if (tellbeep) dobeep(); putstr(mesg.text); break; case 0: break; case INTRO: if (!displayintro) break; default: if (mesg.lines > 1 && boardon) bigmess(mesg.lines, mesg.text); else if (strlen(mesg.text)) putstr(mesg.text); break; } if (ret == KEY) { ret = read(fileno(stdin), &ch, 1); if (ch == '\r') ch = '\n'; if (ch == 'L' - 64 && boardon) redraw(); else if (ch == 27 && boardon) switchmode(); else if (boardmode) doboardmode(ch); else doservermode(ch); } } while (1); handleterm(); } switchmode() { boardmode = !boardmode; if (boardmode) setcursor(xcur, ycur); } static char *nomoves = "%no moves recorded"; doboardmode(ch) char ch; { char movestr[10]; switch (ch) { case '^': switchmode(); clearserver(); switchmode(); break; case ',': restoregame(); if (backward(1)) putstr(nomoves); break; case '.': restoregame(); if (forward(1)) putstr(nomoves); break; case '<': restoregame(); if (backward(10)) putstr(nomoves); break; case '>': restoregame(); if (forward(10)) putstr(nomoves); break; case 's': restoregame(); if (beginninggame()) putstr(nomoves); break; case 'e': restoregame(); if (endgame()) putstr(nomoves); break; case 'f': case '/': restoregame(); if (search(xcur, ycur)) putstr("%No move found at that point"); break; case '1': case 'b': if (++ycur == boardsize) ycur = 0; if (!xcur--) xcur = boardsize - 1; break; case '3': case 'n': if (++ycur == boardsize) ycur = 0; if (++xcur == boardsize) xcur = 0; break; case '7': case 'y': if (!xcur--) xcur = boardsize - 1; if (!ycur--) ycur = boardsize - 1; break; case '9': case 'u': if (!ycur--) ycur = boardsize - 1; if (++xcur == boardsize) xcur = 0; break; case 'B' - 64: case '4': case 'h': if (!xcur--) xcur = boardsize - 1; break; case 'P' - 64: case '8': case 'k': if (!ycur--) ycur = boardsize - 1; break; case 'N' - 64: case '2': case 'j': if (++ycur == boardsize) ycur = 0; break; case 'F' - 64: case '6': case 'l': if (++xcur == boardsize) xcur = 0; break; case 'c': unmark(); break; case '\n': case '\r': case ' ': case '0': sprintf(movestr, "%c%d\n", xcur + 'A' + (xcur + 'A' >= 'I' ? 1 : 0), boardsize - ycur); sendstr(movestr); break; } setcursor(xcur, ycur); } void dopeek(first) char *first; { if (first) { if (!observing && ingame != -1) putstr("%Can't observe while playing"); else if (observing && ingame == atoi(first)) unobserve(); else if (peekgame(atoi(first))) putstr("%No such game"); } } void doobserve(first) char *first; { if (first) { if (!observing && ingame != -1) putstr("%Can't observe while playing"); else if (observing && ingame == atoi(first)) unobserve(); else if (observegame(atoi(first))) putstr("%No such game"); } } void dounobserve() { if (observing) unobserve(); else putstr("%Not observing"); } void doload(first) char *first; { if (first) loadgame(first); } void dochars(first) char *first; { if (first) { setchars(first); if (boardon) { reinitboard(boardsize); endgame(); } } } void dorestore(first) char *first; { if (!needrestore) putstr("%no game to restore"); restoregame(); } void dosort(first) char *first; { if (choosesort(first)) putstr("%Unknown sorting method"); } void dogamessort(first) char *first; { if (choosegamessort(first)) putstr("%Unknown games sorting method"); } void doborder(first) char *first; { if (!first) setborder(' '); else setborder(*first); if (boardon) { reinitboard(boardsize); endgame(); } } void dointro(first) int first; { displayintro=first; } void doinverse(first) int first; { setinverse(first); if (boardon) { reinitboard(boardsize); endgame(); } } void doedgemarks(first) int first; { setedgemark(first); if (boardon) { reinitboard(boardsize); endgame(); } } void dopiecemarks(first) int first; { setpiecemark(first); if (boardon) { reinitboard(boardsize); endgame(); } } void doinvedge(first) int first; { setinverseborder(first); if (boardon) { reinitboard(boardsize); endgame(); } } void doprefix(first) char *first; { if (!first) strcpy(prefix, ""); else { strncpy(prefix, first, 19); prefix[20] = 0; } if (boardon) showprefix(prefix); else printf("Prefix '%s'\n", prefix); } void douser(first) char *first; { int i, found; if (!first) putstr("%No user specified"); else { found = 0; for (i = 0; i < mesg.whocount; i++) { if (!strncmp(mesg.who[i] + NAMECOL, first, strlen(first)) && mesg.who[i][NAMECOL + strlen(first)] == ' ') { putstr(mesg.who[i]); found = 1; } } if (!found) putstr("%User not found in last who"); } } void dosaybeep(first) int first; { saybeep = first; } void dotellbeep(first) int first; { tellbeep = first; } void dobeeps(first) char *first; { if (first) beepcount = atoi(first); } void doclear(first) char *first; { if (!boardon) putstr("%Cannot clear."); else clearserver(); } void donoboard(first) char *first; { if (boardon) { if (ingame != -1) { putstr("Board in use. Cannot remove."); } else { boardon = 0; boardmode = 0; endAscii(); } } else putstr("%No board to remove."); } void dogoto(first) char *first; { if (boardon) { first = strtok(NULL, " \t"); if (first) construct(atoi(first)); } else putstr("%no board"); } /* Warning: This function makes calls to strtok which assume that we've * already started parsing the input line. */ void dosite(first) char *first; { int num; char *next; num = atoi(first); if (num < 0 || num >= MAXSITES) { printf("%%invalid site number: %d\n", num); return; } next = strtok(NULL, " \t\n="); if (!next) { printf("%%invalid or missing site name in 'site %d'\n", num); return; } strcpy(sitetable[num].name, next); next = strtok(NULL, " \t\n="); if (!next) { printf("%%invalid or missing host name in 'site %d' command\n", num); return; } strcpy(sitetable[num].site, next); next = strtok(NULL, " \t\n="); if (next && atoi(next)) sitetable[num].port = atoi(next); } int notfirst = 0; doservermode(ch) char ch; { *loc = ch; *(loc + 1) = 0; if (ch < ' ' && ch != ('U' - 64) && ch != '\b' && ch != '\n') return; if (boardon) { if (*loc == '\b' || *loc == '\177') { if (strlen(local) > 1) { deletechar(strlen(local) - 2); loc -= 2; } else loc--; } else if (*loc == 'U' - 64) { loc = local; clrline(); return; } else if (strlen(local) >= linesize()) { if (!notfirst) sendstr(prefix); sendstr(local); loc = local; notfirst = 1; clrline(); putstr(local); return; } else addcharline(strlen(local) - 1, *loc); } if (*loc == '\n') { loc++; *loc = 0; if (boardon) { addstring(local); } if (notfirst) sendstr(local); else if (local[0] == '!') process(local + 1, 0, NOTATRC); else if (strlen(prefix)) { sendstr(prefix); sendstr(local); } else process(local, 1, NOTATRC); if (boardon) clrline(); notfirst = 0; loc = local; } else loc++; } struct commandtype { char *command; void (*action) (); int inrc; int toggle; } comlist[] = { { "border", doborder, BOTH, 0 }, { "chars", dochars, BOTH, 0 }, { "clear", doclear, NOTATRC, 0 }, { "beeps", dobeeps, BOTH, 0 }, { "edgemarks", doedgemarks, BOTH, 1 }, { "filter", dofilter, BOTH, 1}, { "friend", dofriend, BOTH, 0 }, { "gamessort", dogamessort, BOTH, 0 }, { "goto", dogoto, NOTATRC, 0 }, { "helpigc", help, NOTATRC, 0 }, { "intro", dointro, BOTH, 1}, { "invedge", doinvedge, BOTH, 1 }, { "inverse", doinverse, BOTH, 1 }, { "loa", doload, NOTATRC, 0 }, { "load", doload, NOTATRC, 0 }, { "login", dologin, ATRC, 0 }, { "mo", dopeek, NOTATRC, 0 }, { "mov", dopeek, NOTATRC, 0 }, { "move", dopeek, NOTATRC, 0 }, { "moves", dopeek, NOTATRC, 0 }, { "noboard", donoboard, NOTATRC, 0 }, { "ob", doobserve, NOTATRC, 0 }, { "obs", doobserve, NOTATRC, 0 }, { "obse", doobserve, NOTATRC, 0 }, { "obser", doobserve, NOTATRC, 0 }, { "observ", doobserve, NOTATRC, 0 }, { "observe", doobserve, NOTATRC, 0 }, { "password", dopassword, ATRC, 0 }, { "peek", dopeek, NOTATRC, 0 }, { "piecemarks", dopiecemarks, BOTH, 1 }, { "prefix", doprefix, NOTATRC, 0 }, { "restore", dorestore, NOTATRC, 0 }, { "saybeep", dosaybeep, BOTH, 1 }, { "site", dosite, ATRC, 0}, { "sort", dosort, BOTH, 0 }, { "tellbeep", dotellbeep, BOTH, 1 }, { "unfriend", dounfriend, BOTH, 0 }, { "unob", dounobserve, NOTATRC, 0 }, { "unobserve", dounobserve, NOTATRC, 0 }, { "user", douser, NOTATRC, 0 } }; /* Returns 1 if the command was parsed locally. Returns 0 if the command was * passed the the server, or not parsed locally. */ int process(comm, dopre, state) char *comm; int dopre; int state; { char *first, *second; char save[1000]; int i; strcpy(save, comm); first = strtok(comm, " \n\t="); second = strtok(NULL, " \n\t="); if (!first) return 1; for (i = 0; i < sizeof(comlist) / sizeof(struct commandtype); i++) { if ((state & comlist[i].inrc) && !strcmp(first, comlist[i].command)) { if (comlist[i].toggle) comlist[i].action(1); else comlist[i].action(second); return 1; } } if (!strncmp(first, "no", 2)) { first += 2; for (i = 0; i < sizeof(comlist) / sizeof(struct commandtype); i++) { if ((state & comlist[i].inrc) && comlist[i].toggle && !strcmp(first, comlist[i].command)) { comlist[i].action(0); return 1; } } } if (state == NOTATRC) { if (dopre) sendstr(prefix); sendstr(save); } return 0; } SHAR_EOF fi if test -f 'parse.c' then echo shar: "will not over-write existing file 'parse.c'" else cat << \SHAR_EOF > 'parse.c' #include "igc.h" #include <stdio.h> #include <string.h> #include <sys/types.h> #include "numbers.h" extern char *getloginname(); extern char *getpassword(); int loggedon, verbosetog; int repeatpass, repeatlogin; #ifdef STRSTR char *strstr(); #endif #ifdef STRTOL long strtol(); #endif char *Prompts[] = { "Login: ", "Password: ", "Password: ", "Enter Your Password Again: ", "Enter your e-mail address (None): ", "#> ", "#> ", "Enter Dead Group: ", "#> ", "#> ", }; initparser() { loggedon = 0; repeatpass = 0; repeatlogin = 0; verbosetog = 0; } DoState(s) char *s; { if (strncmp(s, Prompts[LOGON], strlen(Prompts[LOGON])) == 0) return LOGON; if (strncmp(s, "1 1", 3) == 0) return PASSWORD; if (strncmp(s, "1 0", 3) == 0) return LOGON; if (strncmp(s, Prompts[PASSWORD], strlen(Prompts[PASSWORD])) == 0) return PASSWORD; if (strncmp(s, Prompts[PASSWD_NEW], strlen(Prompts[PASSWD_NEW])) == 0) return PASSWD_NEW; if (strncmp(s, Prompts[PASSWD_CONFIRM], strlen(Prompts[PASSWD_CONFIRM])) == 0) return PASSWD_CONFIRM; if (strncmp(s, Prompts[WAITING], strlen(Prompts[WAITING])) == 0) return WAITING; if (!strncmp(s, "Too many players, sorry", 23) || !strncmp(s, "Sorry, the server is full", 24)) return TOOMANY; return -1; } static long appending = 0; int getmessage(mess, checkstdin) message *mess; int checkstdin; { char mesg[2000]; int ret; char *textpart; ret = pollserver(mesg, checkstdin); if (ret <= 0) return ret; switch (DoState(mesg)) { case PASSWD_NEW: case PASSWD_CONFIRM: case PASSWORD: sendstr(getpassword(repeatpass++)); break; case WAITING: sendstr("toggle client true\n"); mess->id = ONSERVER; loggedon = 1; return 1; case TOOMANY: mess->id = TOOMANY; return 1; case LOGON: { int needlogin; needlogin = 1; do { if (needlogin == 1) { sendstr(getloginname(repeatlogin++)); needlogin = -1; } ret = pollserver(mesg, 0); if (ret < 0) return ret; if (!strncmp(mesg, "Password:", 9) || (!strncmp(mesg, "1 1", 3))) needlogin = 0; else if (!strncmp(mesg, "Sorry", 5)) { puts(mesg); if (!strncmp(mesg, "Sorry, the server is full", 24)) { mess->id = TOOMANY; return 1; } return 0; } else if (strlen(mesg) > 2 && strncmp(mesg, "Login", 5)) puts(mesg); } while (needlogin); sendstr(getpassword(repeatpass++)); do { ret = pollserver(mesg, 0); if (ret < 0) return ret; if (!strncmp(mesg, "Enter", 5)) sendstr(getpassword(repeatpass++)); if (!strncmp(mesg, "9 File", 6)) needlogin = -1; if (!strncmp(mesg, "To get", 6)) needlogin = 1; if (!strncmp(mesg, "#>", 2)) { sendstr("toggle client true\n"); mess->id = ONSERVER; loggedon = 1; return 1; } if (strstr(mesg, "Invalid") || strstr(mesg, "your name") || strstr(mesg, "Too few") || strstr(mesg, "do not match")) { if (*mesg == '5') puts(mesg + 2); else puts(mesg); needlogin = 1; } } while (!needlogin); if (needlogin > 0) break; } /* intentional fall through occurs here */ loggedon = 1; default: mess->id = strtol(mesg, &textpart, 10); if (!loggedon && !mess->id) { mess->id = INTRO; strcpy(mess->text, mesg); return 1; } textpart++; if (mess->id == 2 && (strstr(textpart, "Game") || strstr(textpart, "min"))) mess->id = TIMEREP; if (appending == -1) { if (mess->id && !strncmp(textpart, "File", 4)) { appending = 0; if (mess->id == INFO && !strncmp(mess->text, "~~~~~~~~~~~~~~~~~~~~~", 21)) mess->id = QUITMESG; return 1; } if (strlen(mess->text)) { strcat(mess->text, "\n"); mess->lines++; } { int len; char *pt; len = strlen(mesg); pt = mesg; while (len > 0) { strncat(mess->text, pt, 79); len -= 79; pt += 79; if (len > 0) { mess->lines++; strcat(mess->text, "\n"); } } } return 0; } if (mess->id == PROMPT) { if (!verbosetog) sendstr("toggle verbose false\n"); if (*textpart == '5' && !loggedon) loggedon = 1; if (appending == MOVE && mess->movecount == 0 && atoi(textpart) == 6 /* TEACHING */ ) { mess->id = MATCH; return 1; } if (appending) { mess->id = appending; appending = 0; return 1; } mess->prompttype = atoi(textpart); } if (!strcmp(textpart, "File")) { appending = -1; strcpy(mess->text, ""); mess->lines = 1; return 0; } if (mess->id == BEEP) { mess->beep = (*textpart == 7); } if (mess->id == KIBITZ) { if (parsekibitz(textpart, mess)) return 0; } if (mess->id == UNDO) if (ret = parseundo(textpart, &(mess->gamenum))) { if (ret < 0) return ret; return 0; } if (mess->id == SCORE) { sscanf(textpart, "%[^ ] (W:%*c):%f to %[^ ] (B:%*c):%f", mess->white, &(mess->wscore), mess->black, &(mess->bscore)); return 1; } if (mess->id == TRANSLATE) { if (appending) { strcat(mess->text, "\n"); strcat(mess->text, textpart); mess->lines++; } else { strcpy(mess->text, textpart); mess->lines = 1; } appending = TRANSLATE; return 0; } if (mess->id == MOVE) { appending = MOVE; parsemove(textpart, mess); return 0; } if (mess->id == WHO) return parsewho(mess, textpart); if (mess->id == GAMES) { appending = GAMES; parsegame(mess, textpart); return 0; } if (mess->id == STATUS) return parsestatus(mess, textpart); strcpy(mess->text, textpart); mess->lines = 1; if (mess->id == SHOUT) return checkgame(textpart, mess); if (mess->id == ERROR && !strcmp("Game not found.", textpart)) { mess->id = GAMES; mess->gamecount = 0; return 1; } if (mess->id == INFO) if (ret = parseinfo(textpart, mess)) return ret; return 1; } return 0; } #ifdef STRTOL long strtol(text, new, dum) char *text; char **new; int dum; { long retu; retu = atol(text); for (*new = text; *new && **new <= '9' && **new >= '0'; (*new)++); return retu; } #endif #ifdef STRSTR char *strstr(s1, s2) char *s1, *s2; { register char *temp; int len; temp = s1; len = strlen(s2); while (temp = strchr(temp, *s2)) { if (!strncmp(temp, s2, len)) return temp; else temp++; } return NULL; } #endif int parsestatus(mesg, s) message *mesg; char *s; { int line, i; char wflag, bflag; if (1 == sscanf(s, " %d:", &line)) { mesg->boardsize = line + 1; for (i = 0, s += 4; *s; i++, s++) switch (*s) { case S_BLACK: mesg->board[line][i] = BLACK; break; case S_WHITE: mesg->board[line][i] = WHITE; break; case S_EMPTY: case S_HOSHI: mesg->board[line][i] = EMPTY; break; case S_WTERR: mesg->board[line][i] = WTERR; break; case S_BTERR: mesg->board[line][i] = BTERR; break; case S_DAME: mesg->board[line][i] = DAME; break; } if (i == line + 1) return 1; } else { if (!mesg->wnext) { sscanf(s, "%[^ ] %[^ ] %d %d %d %c %f %d", mesg->white, mesg->wrank, &(mesg->bcap), &(mesg->wtime), &(mesg->wbyo), &wflag, &(mesg->mykomi), &(mesg->hcap)); if (wflag == 'F') mesg->wbyo = -1; } else { sscanf(s, "%[^ ] %[^ ] %d %d %d %c %f %d", mesg->black, mesg->brank, &(mesg->wcap), &(mesg->btime), &(mesg->bbyo), &bflag, &(mesg->mykomi), &(mesg->hcap)); if (bflag == 'F') mesg->bbyo = -1; } mesg->wnext = !mesg->wnext; } return 0; } #define WHOLENGTH 34 int parsewho(mesg, str) message *mesg; char *str; { if (!strncmp(str, " Info", 5)) { mesg->whocount = 0; strcpy(mesg->text, str); mesg->lines = 1; strcpy(mesg->whofirst, str); } else { strcat(mesg->text, "\n"); strcat(mesg->text, str); mesg->lines++; if (strstr(str, "******")) { strcpy(mesg->wholast, str); return 1; } else { strncpy(mesg->who[mesg->whocount++], str, WHOLENGTH); if (strlen(str) > 40) strncpy(mesg->who[mesg->whocount++], str + 37, WHOLENGTH); } } return 0; } parsegame(mesg, str) message *mesg; char *str; { int fieldcount; char *br, *wr, blackrank[10], whiterank[10]; if (str[1] == '#') { mesg->gamecount = 0; strcpy(mesg->text, str); strcpy(mesg->gamefirst, str); mesg->lines = 1; } else { strcpy(mesg->gamelist[mesg->gamecount].gametext, str); strcat(mesg->gamelist[mesg->gamecount].gametext, "\n"); strcat(mesg->text, "\n"); strcat(mesg->text, str); mesg->lines++; /* hacked for systems that don't like %[^]] */ for (br = str; *br; br++) if (*br == ']') *br = '!'; fieldcount = sscanf(str, "[%3d!%12s [%[^!]! vs.%12s [%[^!]! (%3d %d %d %f %d) ( %d)\n", &(mesg->gamelist[mesg->gamecount].gnum), mesg->gamelist[mesg->gamecount].white, whiterank, mesg->gamelist[mesg->gamecount].black, blackrank, &(mesg->gamelist[mesg->gamecount].mnum), &(mesg->gamelist[mesg->gamecount].bsize), &(mesg->gamelist[mesg->gamecount].hcap), &(mesg->gamelist[mesg->gamecount].komi), &(mesg->gamelist[mesg->gamecount].byo), &(mesg->gamelist[mesg->gamecount].obcount)); br = blackrank; wr = whiterank; if (*br == ' ') br++; if (*wr == ' ') wr++; strcpy(mesg->gamelist[mesg->gamecount].wrank, wr); strcpy(mesg->gamelist[mesg->gamecount].brank, br); if (fieldcount == 11) (mesg->gamecount)++; } } int parseinfo(s, mess) char *s; message *mess; { int ret; extern int boardsize; int row; char col; char text[100]; if (checkgame(s, mess)) { mess->id = ENDGAMEINFO;return 0;} if (!strcmp(s, "Set verbose to be False.")) { mess->id = 0; verbosetog = 1; return 0; } if (!strcmp(s, "Set verbose to be True.")) { mess->id = 0; verbosetog = 0; return 0; } if (1 == sscanf(s, "Set the komi to %f.", &(mess->mykomi))) { mess->id = CHKOMI; return 0; } if (2 == sscanf(s, "Match [%dx%d]", &ret, &ret)) return 0; if (1 == sscanf(s, "Match [%d]", &(mess->gamenum))) { mess->id = MATCH; return 0; } if (1 == sscanf(s, "Creating match [%d]", &(mess->gamenum))) { mess->id = MATCH; return 0; } if (2 == sscanf(s, "Removing @ %c%d", &col, &row)) { if (col > 'I') col--; mess->x = col - 'A'; mess->y = boardsize - row; mess->id = REMOVE; return 0; } if (!strcmp(s, "Type 'done' when finished")) { mess->id = STARTSCORE; return 0; } if (!strncmp(s, "Board is restored", 17)) { mess->id = SCOREUNDO; return 0; } if (strstr(s, "has restored your old game.")) { char eat = 3, match = 0; mess->id = LOAD; for (; eat; eat--) { ret = pollserver(text, 0); if (ret < 0) return ret; if (!match) match = sscanf(text, "%*d Game %d: %*[^(](%d %d %d) vs %*[^(](%d %d %d)", &(mess->gamenum), &(mess->bcap), &(mess->btime), &(mess->bbyo), &(mess->wcap), &(mess->wtime), &(mess->wbyo) ); } return 0; } return 0; } int parseundo(s, gamenum) char *s; int *gamenum; { char mes[2000]; int count; int bogus2, ret; char bogus1; count = sscanf(s, "%*[^ ] undid the last move (%c%d).", &bogus1, &bogus2); if (count == 2) { ret = pollserver(mes, 0); if (ret < 0) return ret; ret = pollserver(mes, 0); if (ret < 0) return ret; sscanf(mes, "%*d Game %d", gamenum); ret = pollserver(mes, 0); if (ret < 0) return ret; return 0; } if (1 == sscanf(s, "%*[^ ] undid the last move (Handicap %d).", &bogus2)) return 0; count = sscanf(s, "Undo in game %d", gamenum); if (count != 1) return 1; /* extra line */ return 0; } int checkgame(s, mess) char *s; message *mess; { if (!strncmp(s,"{Game ",6) && (strstr(s,"resigns.") || strstr(s,"forfeits on time.") || strstr(s, "adjourned."))){ mess->id = ENDGAME; sscanf(s, "{Game %d", &(mess->gamenum)); return 1; } return 0; } int parsekibitz(s, mess) char *s; message *mess; { if (1 == sscanf(s, "Kibitz %[^:]", mess->kibitzer)) return 1; while (*s == ' ') s++; strcpy(mess->kibitz, s); return 0; } parsemove(s, mess) char *s; message *mess; { int mc, y, mv; char c, col; extern int boardsize; if (!strncmp(s, "Game ", 5)) { sscanf(s, "Game %d: %*[^(](%d %d %d) vs %*[^(](%d %d %d)", &(mess->gamenum), &(mess->wcap), &(mess->wtime), &(mess->wbyo), &(mess->bcap), &(mess->btime), &(mess->bbyo)); mess->movecount = 0; return; } mc = sscanf(s, "%3d(%c): %c%d", &mv, &c, &col, &y); if (mc == 3) { if (3 == sscanf(s, "%3d(%c): Handicap %d", &mv, &c, &mc)) { mess->moves[mess->movecount].x = mess->moves[mess->movecount].y = mc + 100; mess->moves[mess->movecount].color = c == 'W' ? 2 : 1; mess->moves[mess->movecount].movenum = mv + 1; mess->movecount++; return; } if (2 == sscanf(s, "%3d(%c): Pass", &mv, &c)) { mess->moves[mess->movecount].x = mess->moves[mess->movecount].y = 99; mess->moves[mess->movecount].color = c == 'W' ? 2 : 1; mess->moves[mess->movecount].movenum = mv + 1; mess->movecount++; return; } } if (col > 'I') col--; mess->moves[mess->movecount].x = col - 'A'; mess->moves[mess->movecount].y = boardsize - y; mess->moves[mess->movecount].color = c == 'W' ? 2 : 1; mess->moves[mess->movecount].movenum = mv + 1; mess->movecount++; } int doneline(inbuf, inptr) char *inbuf; int inptr; { return !loggedon && (inptr > 0 && inbuf[inptr - 1] == ' ') && ((inptr > 1 && inbuf[inptr - 2] == ':') || (inptr > 2 && inbuf[inptr - 2] == '>' && inbuf[inptr - 3] == '#')); } SHAR_EOF fi if test -f 'ascii.c' then echo shar: "will not over-write existing file 'ascii.c'" else cat << \SHAR_EOF > 'ascii.c' #include <curses.h> #define piece char #define TOP 2 #define LEFT 3 #define RIGHT 79 #define min(a,b) (((a)<(b))?(a):(b)) #define TITLEX 6 #define HIGHLIGHT 23 #define CHAR_NOTHING 0 #define CHAR_BLACK 1 #define CHAR_WHITE 2 #define CHAR_DAME 3 #define CHAR_BLACKTERR 4 #define CHAR_WHITETERR 5 #define CHAR_HANDICAP 6 #define CHAR_VERT 7 #define ASC_NUMCHARS 8 WINDOW *boardwin, *serverwin, *iowin; char xAxisChars[] = "ABCDEFGHJKLMNOPQRST"; int inverseFlag = 1; int inverseBorder = 0; int lastwin = 1; int boardsize = -1; char chars[] = ".#O?+-+ "; int servecols = -1; static int init = 0; int endw = -1, endb = -1; int reinit = 0; int doedgemarkers = 0; int dopiecemarkers = 1; setedgemark(mark) int mark; { doedgemarkers = mark; } setpiecemark(mark) int mark; { dopiecemarkers = mark; } setinverse(inv) int inv; { inverseFlag = inv; } setinverseborder(inv) int inv; { inverseBorder = inv; } setborder(ch) char ch; { chars[CHAR_VERT] = ch; } setchars(s) char *s; { int i; for (i = 0; i <= min(CHAR_VERT, strlen(s) - 1); i++) chars[i] = s[i]; } serverrefresh() { if (lastwin) wrefresh(iowin); else wrefresh(serverwin); } boardrefresh() { wrefresh(boardwin); } void initAscii() { if (!init) { init = 1; initscr(); noecho(); crmode(); } } suspend() { move(23, 0); refresh(); echo(); nocrmode(); } redraw() { clearok(stdscr, TRUE); refresh(); clearok(stdscr, FALSE); } unsuspend() { noecho(); crmode(); redraw(); } displaygamenumber(n) int n; { move(0, 0); if (n >= 0) printw("%3d", n); else if (n == -1) printw("-- "); else printw("sta"); refresh(); } boardtitle(bs, ws) char *bs, *ws; { int i; move(0, TITLEX); for (i = 0; i < 35; i++) addch(' '); move(1, TITLEX); for (i = 0; i < 35; i++) addch(' '); if (strlen(bs)) { move(0, TITLEX); printw("Black: %s", bs); endb = TITLEX + 8 + strlen(bs); move(1, TITLEX); printw("White: %s", ws); endw = TITLEX + 8 + strlen(ws); } refresh(); } static void sbinverse() { if (inverseBorder) wstandout(boardwin); } static void set_inverse() { if (inverseFlag) wstandout(boardwin); } static void unset_inverse() { wstandend(boardwin); } setcursor(x, y) int x, y; { wmove(boardwin, TOP + y, LEFT + 2 * x); wrefresh(boardwin); } void drawPiece(i, j, c) int i, j; char c; { wmove(boardwin, TOP + j, LEFT + 2 * i); set_inverse(); waddch(boardwin, c); unset_inverse(); } void deleteBoardAscii() { delwin(boardwin); delwin(serverwin); delwin(iowin); } void endAscii() { init = 0; deleteBoardAscii(); boardsize = -1; clear(); refresh(); echo(); nocrmode(); endwin(); } char boardPiece(x, y, boardsize) int x, y, boardsize; { return (((boardsize == 19 && x == 9) || (boardsize >= 10 && (x == 3 || x == boardsize - 4)) || (boardsize > 6 && boardsize < 10 && (x == 2 || x == boardsize - 3))) && ((boardsize == 19 && y == 9) || (boardsize >= 10 && (y == 3 || y == boardsize - 4)) || (boardsize > 6 && boardsize < 10 && (y == 2 || y == boardsize - 3)))) ? chars[(int) CHAR_HANDICAP] : chars[(int) CHAR_NOTHING]; } drawOneStone(i, j, t) int i, j; piece t; { if (t == 0) drawPiece(i, j, boardPiece(i, j, boardsize)); else drawPiece(i, j, chars[t]); wrefresh(boardwin); } drawStone(i, j, t) int i, j; piece t; { if (t == 0) drawPiece(i, j, boardPiece(i, j, boardsize)); else drawPiece(i, j, chars[t]); } unmarkascii(i, j) int i, j; { if (!init) return; if (i >= 0 && i <= 19) { set_inverse(); if (dopiecemarkers) { wmove(boardwin, TOP + j, LEFT + 2 * i - 1); waddch(boardwin, ' '); wmove(boardwin, TOP + j, LEFT + 2 * i + 1); waddch(boardwin, ' '); } if (doedgemarkers) { wmove(boardwin, TOP + j, LEFT - 1); waddch(boardwin, chars[CHAR_VERT]); wmove(boardwin, TOP + j, LEFT + boardsize * 2 - 1); waddch(boardwin, chars[CHAR_VERT]); unset_inverse(); sbinverse(); wmove(boardwin, TOP - 1, LEFT + i * 2); waddch(boardwin, xAxisChars[i]); wmove(boardwin, TOP + boardsize, LEFT + i * 2); waddch(boardwin, xAxisChars[i]); } unset_inverse(); } } unhighlight(i, j) int i, j; { int k; if (!init) return; move(HIGHLIGHT, 0); for (k = 1; k < 80 - servecols; k++) addch(' '); move(0, TITLEX - 2); printw(" "); move(1, TITLEX - 2); printw(" "); unmarkascii(i, j); } static char *who[] = {"Black", "White"}; showhcap(hcap) int hcap; { if (!init) return; move(0, LEFT + 19 * 2 + 1); if (hcap) printw("%d", hcap); else addch(' '); refresh(); } showkomi(komi) float komi; { if (!init) return; move(1, LEFT + 19 * 2 - 1); printw("%1.1f", komi); refresh(); } highlight(i, j, num, t, btime, bbyo, wtime, wbyo) int i, j; piece t; int btime, bbyo, wtime, wbyo; { int k; if (btime != -1) { move(0, endb); if (btime < 0) btime = 0; if (wtime < 0) wtime = 0; printw("%d:%02d", btime / 60, btime % 60); if (bbyo != -1) printw(", %d", bbyo); addstr(" "); move(1, endw); printw("%d:%02d", wtime / 60, wtime % 60); if (wbyo != -1) printw(", %d", wbyo); addstr(" "); } if (t >= 0) { move(t == 1 ? 1 : 0, TITLEX - 2); printw("->"); } move(HIGHLIGHT, 0); for (k = 1; k < 80 - servecols; k++) addch(' '); if (i == 99) { move(HIGHLIGHT, 0); printw("%s #%d Pass", who[t - 1], num); } else if (i < 100 && num) { move(HIGHLIGHT, 0); printw("%s #%d at %c%d", who[t - 1], num, i + 'A' + (i + 'A' >= 'I' ? 1 : 0), boardsize - j); set_inverse(); if (dopiecemarkers) { wmove(boardwin, TOP + j, LEFT + 2 * i - 1); waddch(boardwin, '>'); wmove(boardwin, TOP + j, LEFT + 2 * i + 1); waddch(boardwin, '<'); } if (doedgemarkers) { wmove(boardwin, TOP + j, LEFT - 1); waddch(boardwin, '>'); wmove(boardwin, TOP + j, LEFT + boardsize * 2 - 1); waddch(boardwin, '<'); unset_inverse(); sbinverse(); wmove(boardwin, TOP - 1, LEFT + i * 2); waddch(boardwin, '!'); wmove(boardwin, TOP + boardsize, LEFT + i * 2); waddch(boardwin, '!'); } unset_inverse(); } } drawpris(pris) int *pris; { move(23, 22); printw("Captured %c: %d %c: %d ", chars[CHAR_BLACK], *pris, chars[CHAR_WHITE], pris[1]); refresh(); } void initBoardAscii(size) int size; { int i, j; if (!reinit) { if (size == boardsize) { for (i = boardsize; i--;) for (j = boardsize; j--;) drawStone(i, j, 0); return; } if (boardsize != -1) deleteBoardAscii(); boardsize = size; clear(); boardwin = subwin(stdscr, boardsize + 4, boardsize * 2 - 1 + 6 + 2, 1, 0); servecols = COLS - 19 * 2 - 6 - 2; serverwin = subwin(stdscr, 22, servecols, 0, 19 * 2 - 1 + 6 + 2); iowin = subwin(stdscr, 2, servecols, 22, 19 * 2 - 1 + 6 + 2); } if (inverseFlag || reinit) { set_inverse(); for (i = LEFT + 1; i < LEFT + boardsize * 2 - 2; i += 2) for (j = TOP; j < TOP + boardsize; j++) mvwaddch(boardwin, j, i, ' '); unset_inverse(); } for (i = boardsize; i--;) { /* left */ wmove(boardwin, TOP + i, LEFT - 3); sbinverse(); wprintw(boardwin, "%2d", boardsize - i); unset_inverse(); set_inverse(); waddch(boardwin, chars[(int) CHAR_VERT]); /* right */ wmove(boardwin, TOP + i, LEFT + boardsize * 2 - 1); waddch(boardwin, chars[(int) CHAR_VERT]); unset_inverse(); sbinverse(); wprintw(boardwin, "%2d", boardsize - i); unset_inverse(); waddch(boardwin, chars[(int) CHAR_VERT]); /* top */ wmove(boardwin, TOP - 1, LEFT + i * 2); sbinverse(); waddch(boardwin, xAxisChars[i]); waddch(boardwin, ' '); unset_inverse(); wmove(boardwin, TOP - 1, LEFT + i * 2 - 1); set_inverse(); /* bottom */ wmove(boardwin, TOP + boardsize, LEFT + i * 2 - 1); unset_inverse(); wmove(boardwin, TOP + boardsize, LEFT + i * 2); sbinverse(); waddch(boardwin, xAxisChars[i]); waddch(boardwin, ' '); unset_inverse(); for (j = boardsize; j--;) drawStone(i, j, 0); } sbinverse(); wmove(boardwin, TOP - 1, LEFT - 3); waddstr(boardwin, " "); wmove(boardwin, TOP + boardsize, LEFT - 3); waddstr(boardwin, " "); wmove(boardwin, TOP - 1, LEFT + 2 * boardsize); waddstr(boardwin, " "); wmove(boardwin, TOP + boardsize, LEFT + 2 * boardsize); waddstr(boardwin, " "); unset_inverse(); wmove(boardwin, size / 2, size / 2); } reinitboardascii() { reinit = 1; initBoardAscii(boardsize); reinit = 0; } clearserver() { wclear(serverwin); wrefresh(serverwin); } addcharline(pos, ch) int pos; char ch; { wmove(iowin, 1, pos); waddch(iowin, ch); wrefresh(iowin); lastwin = 1; } deletechar(pos) int pos; { wmove(iowin, 1, pos); waddch(iowin, ' '); wmove(iowin, 1, pos); wrefresh(iowin); lastwin = 1; } int linesize() { return servecols - 1; } clrline() { wmove(iowin, 1, 0); wclrtoeol(iowin); wrefresh(iowin); } addchar(ch) char ch; { int x, y, maxx, maxy; if (ch == '\r') return; waddch(serverwin, ch); maxy = serverwin->_maxy - 1; /* 20 */ maxx = serverwin->_maxx - 1; /* servecols - 1; */ getyx(serverwin, y, x); if ((x == maxx - 1 && y == maxy) || (ch == '\n' && y == maxy) || y > maxy) { wmove(serverwin, 0, 0); wclrtoeol(serverwin); } else if (x == 0 && y <= maxy) { wclrtoeol(serverwin); wmove(serverwin, y + 1, 0); wclrtoeol(serverwin); wmove(serverwin, y, x); } wrefresh(serverwin); lastwin = 0; } showprefix(s) char *s; { wmove(iowin, 0, 0); wclrtoeol(iowin); if (strlen(s)) wprintw(iowin, "Prefix: '%s'", s); wrefresh(iowin); } /* addstring(s) char *s; { char *p; for (p = s; *p; p++) addchar(*p); } */ void addstring(s) char *s; { char *wordstart; char *curptr; int haveblank, linelen; curptr = wordstart = s; linelen = 0; while (*curptr) { while (*curptr && *curptr != ' ' && *curptr != '\n') { linelen++; curptr++; } if (*curptr) { haveblank = 1; linelen++; curptr++; } else haveblank = 0; if (linelen <= linesize()) { while (wordstart != curptr) addchar(*wordstart++); if (haveblank && *(curptr - 1) == '\n') linelen = 0; } else if (haveblank && (linelen - 1 <= linesize())) { while (wordstart != curptr - 1) addchar(*wordstart++); addchar('\n'); wordstart++; linelen = 0; } else { if ((curptr - wordstart) > linesize()) { while ((curptr - wordstart) > linesize()) { int i; for (i = linesize(); i; i--) addchar(*wordstart++); addchar('\n'); } } else addchar('\n'); linelen = 0; while (wordstart != curptr) { addchar(*wordstart++); linelen++; } } } } bigmess(lines, intext) int lines; char *intext; { WINDOW *savescr; char ch; int i, count; int rest; char *mynl, *localcopy, *text; text = localcopy = (char *) malloc(strlen(intext) + 1); strcpy(text, intext); mynl = ""; if (lines > 22) { rest = lines; lines = 22; } else rest = 0; savescr = newwin(24, 80, 0, 0); overwrite(stdscr, savescr); do { if (rest > 0) { for (mynl = text, count = 22; count && *mynl; mynl++) if (*mynl == '\n') count--; *(mynl - 1) = 0; rest -= 22; } for (i = (24 - lines) / 2 - 1; i < (24 - lines) / 2 + lines + 1; i++) { move(i, 0); clrtoeol(); } move((24 - lines) / 2, 0); addstr(text); refresh(); while (read(0, &ch, 1) != 1); text = mynl; } while (rest > 0); overwrite(savescr, stdscr); refresh(); delwin(savescr); free(localcopy); } SHAR_EOF fi if test -f 'board.c' then echo shar: "will not over-write existing file 'board.c'" else cat << \SHAR_EOF > 'board.c' #include "igc.h" typedef char boardtype[19][19]; int prisoners[2]; int movenum, maxmove; typedef struct { int x, y; char col; } movelist[500]; movelist moves; boardtype board; #define boolean char #define false 0 #define true 1 static int boardsize = -1; int lasti = -1, lastj = -1; clearboard(b, pris) boardtype b; int *pris; { int i, j; pris[0] = pris[1] = 0; for (i = 0; i < boardsize; i++) for (j = 0; j < boardsize; j++) b[i][j] = EMPTY; } initboard(size) int size; { clearboard(board, prisoners); unhighlight(lasti, lastj); showhcap(0); initAscii(); initBoardAscii(size); boardsize = size; maxmove = movenum = 0; } reinitboard(size) int size; { unhighlight(lasti, lastj); showhcap(0); clearboard(board, prisoners); initAscii(); reinitboardascii(); boardsize = size; } boolean inRange(i, j) { return i >= 0 && i < boardsize && j >= 0 && j < boardsize; } boolean alive0(b, m, i, j, t) boardtype b; boardtype m; int i, j; piece t; { piece pt; pt = b[i][j]; if ((pt != EMPTY && pt != t) || m[i][j] != EMPTY) return 0; m[i][j] = (pt == t) ? (piece) 1 : (piece) 2; if (pt == EMPTY) return 1; return (j < boardsize - 1 && alive0(b, m, i, j + 1, t)) || (i < boardsize - 1 && alive0(b, m, i + 1, j, t)) || (i && alive0(b, m, i - 1, j, t)) || (j && alive0(b, m, i, j - 1, t)); } boolean alive(b, i, j) /* Does group at i,j have liberties? */ boardtype b; int i, j; { boardtype m; int p[2]; clearboard(m, p); return alive0(b, m, i, j, b[i][j]); } int removed; int dontdraw = 0; void removeStones0(b, pris, i, j, t) boardtype b; int *pris; int i, j; piece t; { if (b[i][j] != t) return; b[i][j] = EMPTY; if (!dontdraw) drawStone(i, j, 0); removed = 1; pris[t - 1]++; if (j < boardsize - 1) removeStones0(b, pris, i, j + 1, t); if (i < boardsize - 1) removeStones0(b, pris, i + 1, j, t); if (i) removeStones0(b, pris, i - 1, j, t); if (j) removeStones0(b, pris, i, j - 1, t); } void removeStones(b, pris, i, j) boardtype b; int *pris; int i, j; { removed = 0; removeStones0(b, pris, i, j, b[i][j]); /* if (removed) boardrefresh(); */ } void removeGroup(i, j) int i, j; { removeStones(board, prisoners, i, j); } boolean tryKill(b, pris, i, j, t) boardtype b; int *pris; int i, j; piece t; { piece w; if (!inRange(i, j)) return false; w = b[i][j]; if (w != EMPTY && w != t && !alive(b, i, j)) { removeStones(b, pris, i, j); return true; } return false; } void placeStone(b, pris, i, j, t) boardtype b; int *pris; int i, j; piece t; { if (inRange(i, j)) { b[i][j] = t; if (j) tryKill(b, pris, i, j - 1, t); if (j < boardsize - 1) tryKill(b, pris, i, j + 1, t); if (i) tryKill(b, pris, i - 1, j, t); if (i < boardsize - 1) tryKill(b, pris, i + 1, j, t); } } static highlighting = 1; makemove(i, j, num, t, btime, bbyo, wtime, wbyo) int i, j; piece t; int btime, bbyo, wtime, wbyo; { if (movenum != maxmove) { construct(maxmove); } if (highlighting) unhighlight(lasti, lastj); if (num == 1 && i <= 19) showhcap(0); if (i > 100) { sethandicap(board, i - 100); showhcap(i - 100); moves[num].x = moves[num].y = i; moves[num].col = t; maxmove = movenum = num; if (highlighting) highlight(i, j, num, t, btime, bbyo, wtime, wbyo); return; } if (i == 99) { moves[num].x = moves[num].y = 99; moves[num].col = t; maxmove = movenum = num; if (highlighting) { highlight(i, j, num, t, btime, bbyo, wtime, wbyo); drawpris(prisoners); } return; } placeStone(board, prisoners, i, j, t); if (highlighting) highlight(i, j, num, t, btime, bbyo, wtime, wbyo); if (highlighting) drawpris(prisoners); if (highlighting) drawOneStone(i, j, t); else drawStone(i, j, t); lasti = i; lastj = j; moves[num].x = i; moves[num].y = j; moves[num].col = t; maxmove = movenum = num; } unmark() { unmarkascii(lasti, lastj); } construct(mov) int mov; { int i, j; boardtype myboard; int mypris[2]; if (mov > maxmove) mov = maxmove; if (mov < 1) mov = 1; clearboard(myboard, mypris); unhighlight(lasti, lastj); dontdraw = 1; for (i = 1; i <= mov; i++) { if (moves[i].x > 100) sethandicap(myboard, moves[i].x - 100); else if (moves[i].x != 99) { placeStone(myboard, mypris, moves[i].x, moves[i].y, moves[i].col); myboard[moves[i].x][moves[i].y] = moves[i].col; } } dontdraw = 0; for (i = 0; i < boardsize; i++) for (j = 0; j < boardsize; j++) if (board[i][j] != myboard[i][j]) { drawStone(i, j, myboard[i][j]); board[i][j] = myboard[i][j]; } prisoners[0] = mypris[0]; prisoners[1] = mypris[1]; highlight(moves[mov].x, moves[mov].y, mov, moves[mov].col, -1, -1, -1, -1); lasti = moves[mov].x; lastj = moves[mov].y; drawpris(prisoners); movenum = mov; } int savemaxmove = 0, didsave = 0; restoremaxmoves() { didsave = 0; maxmove = savemaxmove; } savemaxmoves() { if (!didsave) { didsave = 1; savemaxmove = maxmove; } } showboard(b) boardtype b; { int i, j; for (i = 0; i < boardsize; i++) for (j = 0; j < boardsize; j++) if (board[i][j] != b[i][j]) { drawStone(i, j, b[i][j]); board[i][j] = b[i][j]; } boardrefresh(); } undo() { int i, j; maxmove--; if (maxmove) construct(maxmove); else { movenum = 0; unhighlight(lasti, lastj); for (i = 0; i < boardsize; i++) for (j = 0; j < boardsize; j++) if (board[i][j] != EMPTY) { drawStone(i, j, EMPTY); board[i][j] = EMPTY; } } } int forward(num) int num; { if (!maxmove) return 1; if (movenum < maxmove) construct(movenum + num); /* construct() does bounds checking */ return 0; } int backward(num) int num; { if (!maxmove) return 1; if (movenum > 1) construct(movenum - num); /* construct() does bounds checking */ return 0; } int beginninggame() { if (!maxmove) return 1; construct(1); return 0; } int endgame() { if (!maxmove) return 1; construct(maxmove); return 0; } int search(i, j) int i, j; { int k; k = maxmove; while (k > 0 && (moves[k].x != i || moves[k].y != j)) k--; if (!k) return 1; construct(k); return 0; } sethighlight(h) int h; { highlighting = h; } #define TOP 0 #define MID 1 #define BOT 2 static int verts[3][26] = { {0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 3, 0, 3, 0, 0, 0, 4}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 6, 0, 0, 0, 0, 0, 9, 0, 10, 0, 0, 0, 12}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 9, 0, 0, 0, 0, 0, 15, 0, 17, 0, 0, 0, 20}, }; sethandicap(board, hand) boardtype board; int hand; { /* This is also used to set the handicap. The 'handi' is the number of * things to set of piece 'p'. */ int top, mid, bot; piece t; top = verts[TOP][boardsize]; mid = verts[MID][boardsize]; bot = verts[BOT][boardsize]; /* All of these drop through, '5' checks for odd points. */ t = 1; switch (hand) { case 9: /* taken care of by handi == 5 */ case 8: drawStone(mid, top, t); board[mid][top] = t; drawStone(mid, bot, t); board[mid][bot] = t; case 7: /* taken care of by handi == 5 */ case 6: drawStone(bot, mid, t); board[bot][mid] = t; drawStone(top, mid, t); board[top][mid] = t; case 5: if (hand & 0x1) { /* odd points, test because of drop through */ drawStone(mid, mid, t); board[mid][mid] = t; } case 4: drawStone(bot, bot, t); board[bot][bot] = t; case 3: drawStone(top, top, t); board[top][top] = t; case 2: drawStone(bot, top, t); board[bot][top] = t; drawStone(top, bot, t); board[top][bot] = t; break; default: break; } } SHAR_EOF fi if test -f 'numbers.h' then echo shar: "will not over-write existing file 'numbers.h'" else cat << \SHAR_EOF > 'numbers.h' typedef enum { UNKNOWN = 0, BEEP = 2, /* \7 telnet */ BOARD = 3, /* Board being drawn */ DOWN = 4, /* The server is going down */ ERROR = 5, /* An error reported */ FIL = 6, /* File being sent */ GAMES = 7, /* Games listing */ HELP = 8, /* Help file */ INFO = 9, /* Generic info */ LAST = 10, /* Last command */ KIBITZ = 11, /* Kibitz strings */ LOAD = 12, /* Loading a game */ LOOK = 13, /* Look */ MESSAGE = 14, /* Message lising */ MOVE = 15, /* Move #:(B) A1 */ OBSERVE = 16, /* Observe report */ PROMPT = 1, /* A Prompt (never) */ PROVERB = 31, /* Go Proverb <=== last value */ REFRESH = 17, /* Refresh of a board */ SAVED = 18, /* Stored command */ SAY = 19, /* Say string */ SCORE = 20, /* Score report */ SHOUT = 21, /* Shout string */ SHOW = 29, /* Shout string */ STATUS = 22, /* Current Game status */ STORED = 23, /* Stored games */ TELL = 24, /* Tell string */ THIST = 25, /* Thist report */ TIM = 26, /* times command */ TRANSLATE = 30, /* Translation info */ WHO = 27, /* who command */ UNDO = 28, /* Undo report */ } MessageType; #define S_BLACK '0' #define S_WHITE '1' #define S_EMPTY '2' #define S_DAME '3' #define S_WTERR '4' #define S_BTERR '5' #define S_HOSHI '6' typedef enum { LOGON = 0, PASSWORD = 1, PASSWD_NEW = 2, PASSWD_CONFIRM = 3, REGISTER = 4, WAITING = 5, PLAYING = 6, SCORING = 7, OBSERVING = 8, TEACHING = 9 } State; SHAR_EOF fi if test -f 'igc.h' then echo shar: "will not over-write existing file 'igc.h'" else cat << \SHAR_EOF > 'igc.h' #define MAXGAMES 50 #define MAXWHO 300 #define MAXNAME 11 #define MAXRANK 6 #define MAXFRIENDS 50 #define piece char #ifdef BCOPY #define bcopy(a,b,c) memcpy(b,a,c) #endif typedef struct { int id; int prompttype; /* if return is prompt */ int x, y; /* used to report removed stones for scoring */ struct { /* if return is play */ int x, y; int movenum; int color; } moves[400]; int movecount; int gamenum; int bcap, btime, bbyo; int wcap, wtime, wbyo; char text[10000]; /* text of message */ int lines; /* number of lines in text */ int gamecount; /* for data from the games command */ struct gametype { int gnum; char white[MAXNAME], wrank[MAXRANK], black[MAXNAME], brank[MAXRANK]; int mnum, bsize, hcap; float komi; int byo, obcount; char gametext[80]; } gamelist[MAXGAMES]; char gamefirst[80]; int boardsize, boardline; float wscore, bscore; piece board[19][19]; int wnext; /* white next? Already have info for black. */ char white[MAXNAME], wrank[MAXRANK], black[MAXNAME], brank[MAXRANK]; int hcap; int beep; char kibitzer[40]; char kibitz[300]; int whocount; char *who[MAXWHO]; char whodata[MAXWHO][40]; char wholast[80]; char whofirst[80]; float mykomi; } message; #define ONSERVER -1 #define MATCH -2 #define QUITMESG -3 #define REMOVE -4 #define SCOREUNDO -5 #define TIMEREP -6 #define TOOMANY -7 #define CHKOMI -8 #define STARTSCORE -9 #define INTRO -10 #define ENDGAME -11 #define ENDGAMEINFO -12 #define BLACK 1 #define WHITE 2 #define EMPTY 0 #define DAME 3 #define BTERR 4 #define WTERR 5 #define KEY -33 SHAR_EOF fi if test -f 'Makefile' then echo shar: "will not over-write existing file 'Makefile'" else cat << \SHAR_EOF > 'Makefile' CC = cc # if you get strstr undefined, add -DSTRSTR to the DEFINES line below # if you get bcopy undefined, add -DBCOPY # if you get strtol undefined, add -DSTRTOL # if you change something in the Makefile, you may need to # type rm *.o before trying to recompile. # The -DDEBUG below causes igc to create dump?.igc files which # contain logs of each IGS session. Remove the -DDEBUG # to suppress creation of the dump files. I may request # the log files from you if you report bugs. DEFINES = -DDEBUG # You may want to change -g (include debug information) into # -O for optimize. If you do this, also run strip on the # igc file: 'strip igc'. This will make the executable # even smaller. CFLAGS = -g $(DEFINES) LIBS = -lcurses -ltermlib # link line for PTX. System V systems need something like this: #LIBS = -lcurses -ltermlib -lsocket -linet -lnsl # Under Irix running Yellow Pages, add -lsun to the link line # Under RS/6000 AIX 3.1, remove the -ltermlib PROGRAM = igc MAN = igc.doc OBJ = socket.o igc.o parse.o ascii.o board.o SRC = socket.c igc.c parse.c ascii.c board.c HDRS = numbers.h igc.h FILES = README $(SRC) $(HDRS) Makefile igc.6 BUGS all: $(PROGRAM) $(MAN) $(PROGRAM): $(OBJ) @echo Loading... @$(CC) $(OBJ) $(LIBS) -o $(PROGRAM) $(MAN): igc.6 nroff -man igc.6 > $(MAN) $(OBJ): $(HDRS) shar: @shar $(FILES) > $(PROGRAM).shar shar2: @shar -m 200000 -f $(PROGRAM) $(FILES) lint: lint $(SRC) -lcurses > lintout SHAR_EOF fi if test -f 'igc.6' then echo shar: "will not over-write existing file 'igc.6'" else cat << \SHAR_EOF > 'igc.6' .TH IGC 6 "7 June 1993" .SH NAME igc - ascii client to Internet Go Server .SH SYNOPSIS .B igc [\-s] [host [port]] .SH DESCRIPTION Go is an ancient asian strategy game based on the capture of territory. Players alternate, placing stones on the board and trying to surround as many empty intersections as possible. The .B Internet Go Server allows players to meet and play interactive games. .B Igc provides a more convenient interface for connections to the .B Internet Go Server. .SH COMMAND LINE OPTIONS .TP 8 .B \-s Supresses autologin. .LP .TP 8 .B [host [port]] Connects to specified host and port number. The host can be specified as a fully qualified hostname, or as an abbreviation. If the abbreviation is used, then the port number cannot be included. The shorthand names supported by default are: .in +2m .ta .ta 7m +\w'mmmmmmm\ \ 'u +\w'hellspark.wharton.upenn.edu\ \ 'u + .nf name host address port site 0 icsi hellspark.wharton.upenn.edu 6969 site 1 pasteur ftp.pasteur.fr 6969 .fi .in -2m If no host is specified, then site 0 is used. To connect to the French site, for example, use 'igc pasteur'. (See the customization section for more information.) .SH OPERATION When .B igc is run, it opens a connection to the go server. Unlike a straight telnet connection, .B igc does not print the '#>' prompt, and your normal suspend key (usually ^Z) will suspend the client. If you use telnet after using .B igc the prompts from the server will be different because the server is in client mode. Log in with username and password at the numeric prompts and then type 'toggle client' to get the normal prompts. .LP Initially, .B igc acts as a direct connection to the server. When a game is displayed, the screen will be split into two windows: one for the board on the left, and one for text interaction with the server on the right. The ESC key will switch between the two windows, and the ^L key will redraw the display (from either window). .LP When the server sends long messages such as the output from the 'games' command, the 'who' command, or the 'help' commmand, it prints the message on top of the board. Press any key to restore the board. If the message is longer than 22 lines, then the message will be displayed in chunks. .LP The names of the players appear above the board, followed by their ranks, and the time remaining. An arrow indicates whose turn it is. You can view only one game at a time (either by observing, or by playing). The number of that game is displayed to the left of the Black's name. This number should be '--' if you are not playing or observing a game. To the right of Black's name, above the right corner of the board (in 19x19 games), is the number of handicap stones. This region is blank if the game is even. To the right of white's name is the komi for the game. Below the board, a line shows the number and coordinates of the last move, and the captured stones are displayed. The display shows the number of black stones which were captured, followed by the number of white stones captured. .LP All of the commands which are active from the board window are single keystroke commands. The cursor can be moved around the board using either the number keys (12346789), the emacs keys (^P ^N ^B ^F) or the rogue keys (hjklyubn). The board keeps track of all moves received so that you can view the history of the game. Note that the server's 'look' and 'status' commands do not generate a move history. When these commands are used, or when a game is scored, a snapshot of the board is obtained from the server and temporarily placed on top of the board. The receipt of a move, or any attempt to move through the game record, will restore the previous display. When the status display is active, the game number area in the upper right corner of the screen reads "sta". The previous display can be restored by the client command 'restore'. .LP .TP 8 0, space, return Makes a move on the board. (Send the coordinates of the cursor to the server.) .LP .TP 8 c Clears the marks on the board which indicate which piece was played last. .LP .TP 8 ^ Clears the server window to the right of the board. .LP .TP 8 comma, period (, and .) Move backwards (comma) or forwards (period) through the moves in the game currently displayed on the board. If a new move arrives while you are observing the game like this, you will be bounced back to the end of the game. .LP .TP 8 <, > Move backwards or forwards by sets of ten moves through the game currently displayed on the board. .LP .TP 8 s, e Jump to start (s) or end (e) of the game displayed on the board. .LP .TP 8 f, / Find the time in the game when a stone was played at the current cursor location, and jump to that move. If a stone was played on one point several times, this command jumps to the latest. .LP Commands in the server window are words rather than single characters. These commands will work in the full screen mode as well when appropriate. The backspace and delete keys will remove the last character you typed, and ^U will kill the whole line. .LP .TP 4 helpigc Display a brief help screen. .LP .TP 4 observe <n> Begin observing game n. If you are already observing a game, this command will stop observing that game and begin observing game n. If you are observing game n, then this command will stop observing game n. This command can be abbreviated as 'ob'. .LP .TP 4 unobserve Stop observing the game you are watching. This command can be abbreviated as 'unob'. .LP .TP 4 peek <n> Peeks at game n. Fetches all the moves from that game without observing so that you can play the game back from the start, or just see what it looks like. .LP .TP 4 restore Restores the active game display which was on the board before a 'look' or 'status' command. This command is only valid when the upper left corner of the screen says "sta". .LP .TP 4 goto <n> Goes to move n in the game displayed on the board. .LP .TP 4 clear Clears the server window .LP .TP 4 noboard Removes the board and returns to full screen interaction with the server. .LP .TP 4 user <name> Prints the line for <name> from the output of the last who command. .LP .TP 4 sort <sort-type> Sets the sorting method for output from the server's 'who' command. Available sorting methods are: none, rank, rating, name, and game. The 'none' type does no sorting. The 'name' type sorts by name, 'rank' sorts by rank, 'rating' sorts by ranks, but distinguishes between stated ranks and computed ones, 'idle' sorts by idle time and 'game' sorts first by the game a player is playing in, second by whether a player is open for games, and finally by rank. The default sorting method is 'name'. .LP .TP 4 gamessort <games-sort-type> Sets the sorting method for output from the server's 'games' command. Available sorting methods are: none, number, obcount. The 'number' type sorts by game number and is the default. The 'obcount' type sorts by the number of observers watching each game. .LP .TP 4 filter Enable filtering of shout commands for friends. (See 'friend' command.) .LP .TP 4 nofilter Disable filtering of shout commands for friends. (See 'friend' command.) .LP .TP 4 friend [name] If the name is given, add that name to the list of friends. If no name is given, then print the current list of friends. When filtering is enabled, only shout commands which start with a name on the friends list will be printed. The friends list is limited to 50 names. .LP .TP 4 unfriend name Remove the specified name from the friends list. .LP .TP 4 inverse Switch board display to inverse video. (This is the default display). .LP .TP 4 noinverse Switch board display to regular video. .LP .TP 4 invedge Display edges with inverse video. .LP .TP 4 noinvedge Display edges with normal video. (This is the default). .LP .TP 4 chars <list> Sets the board characters. The order is empty, black, white, dame, black territory, white territory, hoshi point, border. The characters should appear without spaces betwee them. The default character set is .#O?+-+ with a space for the border character. .LP .TP 4 border <char> Sets the border character to char. If char is omitted then the border is turned off. (This is the default.) .LP .TP 4 beeps <n> Sets the number of beeps sent when sending a beep. The default is one. .LP .TP 4 saybeep Causes .B igc to beep when your opponent says something to you during a game using the say command. Does not cause messages sent with the tell command to beep. .LP .TP 4 nosaybeep Do not beep when your opponent says something to you with the say command. (This is the default.) .LP .TP 4 tellbeep Causes .B igc to beep if anyone tells you anything at any time. Does not cause messages sent with the say command to beep. .LP .TP 4 notellbeep Do not beep when people tell things to you. (This is the default.) .LP .TP 4 prefix <text> Adds text to every line you type to the server. All characters before your text will be used in the prefix. The purpose of this command is to make it easier to hold conversations with someone. To talk with goplayer, you might type 'prefix tell goplayer ' (note the extra space). All subsequent lines would be sent to goplayer. If you start a line with '!' then the prefix will not be used. To turn off the prefix, type '!prefix'. When the prefix is active and the board is displayed, the prefix text is displayed at the bottom of the server window. .LP .TP 4 edgemarks Turns on display of marks at the edge of the board to indicate last move. .LP .TP 4 noedgemarks Turns off display of marks at the edge of the board to indicate last move. (This is the default.) .LP .TP 4 piecemarks Turns on display of marks around the last stone played. (This is the default.) .LP .TP 4 nopiecemarks Turns off display of marks around the last stone played. .SH CUSTOMIZATION The file .B .igcrc is used to do initialization. You do not need to have this file, but it can set up .B igc to suit your desires and it can automatically log you in. You create this file in your home directory yourself, using a text editor (emacs, vi). The following server window commands are supported in the .B .igcrc file: inverse, noinverse, invedge, noinvedge, beeps, saybeep, nosaybeep, chars, border, sort, gamessort, friend, unfriend, filter, nofilter. They can be used to configure the display as desired. .LP Some special commands are supported as well: .LP .TP 4 nointro Supresses the display of the login message which is printed before you login. .LP .TP 4 login <name> Causes .B igc to automatically send <name> as your login name when the connection is established. (This is suppressed by the \-s option.) .LP .TP 4 password <password> Causes .B igc to send <password> as your password. If you use this command, you should make sure that your .B .igcrc file is not world readable. Use the command 'chmod 600 .igcrc' to set the insure that this file is not world readable. (Transmission of <password> is supressed by the \-s option.) .LP .TP 4 site <number> <name> <address> <port> The program keeps a table of ten sites labeled site 0 through site 9. By specifying the desired <number>, you can define new servers. A server has <name> as its shorthand reference, <address> as a fully qualified internet address, and port number <port>. By changing site 0, you can change the default site which is used if .B igc is invoked without parameters. By default, the first two sites are set as described under command line options. The remaining eight sites are undefined. .SH BUGS .LP The server allows command abbreviation, but the client does not. .LP The server doesn't correctly mark the ends of games, so if a game ends while you are playing/observing, the client may still think you are playing/observing. The number in the upper left will say '--' if the client realizes you are not doing anything. If it doesn't, press return a few times in the server window. .LP If someone who is playing a game changes their rank, the change will not be reflected on the screens of other people watching or playing that game. .LP If komi changes during a game, the observers will not see the change. (The players will.) .LP The program cannot handle boards larger than 19x19. .SH AUTHOR Adrian Mariano (adrian@u.washington.edu, adrian on IGS) .SH SEE ALSO LaTeX and Postscript documentation for the IGS is available on ftp.u.washington.edu in public/go/prog/igs.tex.Z and public/go/prog/igs.ps.Z. .LP Other programs: mgt, pcigc, stigc, xigc, xgospel SHAR_EOF fi if test -f 'BUGS' then echo shar: "will not over-write existing file 'BUGS'" else cat << \SHAR_EOF > 'BUGS' can't load selfgames doesn't intercept partial commands SHAR_EOF fi exit 0 # End of shell archive