games@tekred.TEK.COM (09/15/88)
Submitted by: Hans Korneder <uunet!altger!korn> Comp.sources.games: Volume 5, Issue 64 Archive-name: mazewar-V from the author: [[Here goes a small game, which runs under Unix-III, Unix-V.{1,2,3} and different flavours of Xenix. The special thing about is: it uses named pipes as a communication mechanism between the processes. Thus it's a "realtime" interactive multiuser-game without sockets!]] #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: README Makefile globals.h daemon.c maze.c user.c # Wrapped by billr@saab on Wed Sep 14 13:29:49 1988 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'README' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'README'\" else echo shar: Extracting \"'README'\" \(1256 characters\) sed "s/^X//" >'README' <<'END_OF_FILE' X/* X * This file is part of "mazewar", an interactive X * multiuser action game for non-BSD-Unix-systems. X * Copyright (C) 1988 Hans Korneder korn@altger.uucp X * Permission is granted to the public X * to copy all parts of the source, as long as no money X * is made out of it, and the copyrightmessage is not removed. X */ X XOnce upon a time, there was a quite nice game on the net; XIt was in interactive fullscreen multiuser action game. XIt just had one small drawback: It used 'sockets', Xa mechanism not available under my Unix V. X XTaking the idea, I rewrote a similar game, using Xnamed pipes as an interprocess communication feature. XThat game was successfully ported to Unix-III, Unix-V.{2,3}, Xand even several Xenixes. X XTo install: X- compile the programs (according to the Makefile), X- start up the serverdaemon-process in the background (this X process needs root-privileges; it has to be started only once; X best place is in some /etc/rc-script), X- start the user-processes and have fun! (instructions X are displayed on the screen). X- send money to me :-) X- send error-reports to /dev/null :-) X- send improvements to me ! X X XHope, you have fun with it! X XHans Korneder, korn@altger.uucp XWaldschulstr. 69 X8000 Muenchen 82 XFed. Rep. of Germany END_OF_FILE if test 1256 -ne `wc -c <'README'`; then echo shar: \"'README'\" unpacked with wrong size! fi # end of 'README' fi if test -f 'Makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Makefile'\" else echo shar: Extracting \"'Makefile'\" \(445 characters\) sed "s/^X//" >'Makefile' <<'END_OF_FILE' XSHELL=/bin/sh XCFLAGS=-O XSRCES= user.c daemon.c maze.c XINCLS= globals.h XOBJS = $(SRCES:.c=.o) Xall: mazewar mazedaemon Xmazewar: user.o maze.o X cc user.o maze.o -lcurses -ltermcap -o mazewar Xmazedaemon: daemon.o maze.o X cc daemon.o maze.o -o mazedaemon X$(OBJS): globals.h Xtape:; tar cv README Makefile $(INCLS) $(SRCES) Xclean:; rm -f a.out core $(OBJS) Xlove:; @echo "my place or yours?" Xshar:; shar README Makefile $(INCLS) $(SRCES) > mazewar.shar END_OF_FILE if test 445 -ne `wc -c <'Makefile'`; then echo shar: \"'Makefile'\" unpacked with wrong size! fi # end of 'Makefile' fi if test -f 'globals.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'globals.h'\" else echo shar: Extracting \"'globals.h'\" \(1333 characters\) sed "s/^X//" >'globals.h' <<'END_OF_FILE' X/* X * This file is part of "mazewar", an interactive X * multiuser action game for non-BSD-Unix-systems. X * Copyright (C) 1988 Hans Korneder korn@altger.uucp X * Permission is granted to the public X * to copy all parts of the source, as long as no money X * is made out of it, and the copyrightmessage is not removed. X */ X X#define MAZE_DAEMON "/usr/local/lib/mw_daemon_pipe" X#define MAZE_PIPE "/tmp/mw_user_XXXXXX" X#define MAZE_SCORES "/usr/local/lib/mw_score_tbl" X X/* message-typen */ X#define MESSAGES 12345 X#define ANMELD MESSAGES+0 /* new player comes in */ X#define SP_ANZ MESSAGES+4 /* show player status */ X#define BEWEGUNG MESSAGES+5 /* player moves */ X#define BILD_NEU MESSAGES+7 /* screen refresh */ X#define EXIT 127 X Xstruct anmeldung /* from the keyboard-client to the server */ X { X int an_magic; X int an_pid; X int an_uid; X char an_pipe[32]; X } ; X Xstruct sp_anzeige /* fromm the server to the screen client */ X { X int sp_magic; X int sp_pid; X int sp_lfd_nr; X long sp_score; X int sp_x_pos; X int sp_y_pos; X char sp_name[9]; X char sp_richtg; X char sp_flag; /* 1=in the game, 2=visible */ X } ; X Xstruct bewegung /* from the keyboard client to the server */ X { X int be_magic; X int be_pid; X int be_code; /* also uid ! */ X } ; X X#define MAZE_ROWS 19 X#define MAZE_COLS 40 Xextern char maze[MAZE_ROWS][MAZE_COLS]; END_OF_FILE if test 1333 -ne `wc -c <'globals.h'`; then echo shar: \"'globals.h'\" unpacked with wrong size! fi # end of 'globals.h' fi if test -f 'daemon.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'daemon.c'\" else echo shar: Extracting \"'daemon.c'\" \(7906 characters\) sed "s/^X//" >'daemon.c' <<'END_OF_FILE' X/* X * This file is part of "mazewar", an interactive X * multiuser action game for non-BSD-Unix-systems. X * Copyright (C) 1988 Hans Korneder korn@altger.uucp X * Permission is granted to the public X * to copy all parts of the source, as long as no money X * is made out of it, and the copyrightmessage is not removed. X */ X X#include <signal.h> X#include <pwd.h> X#include "globals.h" X#define N_PLAYERS 10 X Xstruct player X { X int p_pid; X int p_fd; X int p_uid; X int p_x_pos; X int p_y_pos; X char p_name[9]; X char p_richtg; X long p_score; X char p_pipe[32]; X int last_x[N_PLAYERS]; X int last_y[N_PLAYERS]; X int last_r[N_PLAYERS]; X long last_s[N_PLAYERS]; X } players[N_PLAYERS]; X Xint delta_x[4] = { 1,0,-1,0 }; Xint delta_y[4] = { 0,-1,0,1 }; X Xint player; Xint user_pipe_fd, score_fd; X Xcatch(s) Xint s; X { X signal(s,catch); X } X Xget_user_info(uid) Xint uid; X { X extern struct passwd *getpwuid(); X struct passwd *pwd; X pwd = getpwuid(uid); X if ( pwd ) strcpy(players[player].p_name,pwd->pw_name); X else sprintf(players[player].p_name,"*%06d*",uid); X if ( score_fd >= 0 ) X { X lseek(score_fd,((long)uid)*sizeof(long),0); X read(score_fd,&(players[player].p_score),sizeof(long)); X } X else players[player].p_score = 0L; X } X Xmain() X { X extern long time(); X setpgrp(); X catch(SIGALRM); X catch(SIGPIPE); X nice(-10); nice(-10); nice(-10); nice(-10); X srand((unsigned)time((long *)0)); X umask(0); X score_fd = open(MAZE_SCORES,2); X for(;;) X { X unlink(MAZE_DAEMON); X mknod(MAZE_DAEMON,010622,0); X user_pipe_fd = open(MAZE_DAEMON,0); X if ( user_pipe_fd < 0 ) exit(1); X for(player=0; player<N_PLAYERS; player++) X players[player].p_pid = 0; X while(process_mesg()); X close(user_pipe_fd); X sleep(2); X } X } X Xreposition_player(p) Xint p; X { X extern int rand(); X int y,x; X do { X x = rand() % MAZE_COLS; X y = rand() % MAZE_ROWS; X } while ( maze[y][x] != ' ' ); X players[p].p_x_pos = x; X players[p].p_y_pos = y; X players[p].p_richtg = rand()%4; X } X Xint process_mesg() X { X struct bewegung bew; X if ( read(user_pipe_fd,&bew,sizeof(bew))<=0 ) return 0; X switch ( bew.be_magic ) X { X case ANMELD: X { X int p; X char answer_pipe[32]; X read(user_pipe_fd,answer_pipe,sizeof(answer_pipe)); X for(player=0; player<N_PLAYERS; player++) X if ( ! players[player].p_pid ) break; X if ( player==N_PLAYERS ) break; X strcpy(players[player].p_pipe,answer_pipe); X players[player].p_fd = open(players[player].p_pipe,1); X if ( players[player].p_fd<0 ) break; X players[player].p_pid = bew.be_pid; X players[player].p_uid = bew.be_code; X get_user_info(bew.be_code); X reposition_player(player); X for(p=0; p<N_PLAYERS; p++) X players[player].last_x[p] = -1, X players[player].last_s[p] = -1000000000; X determine_visibility(); X break; X } X case BEWEGUNG: X for(player=0; player<N_PLAYERS; player++) X if ( players[player].p_pid==bew.be_pid ) break; X if ( player==N_PLAYERS ) break; X do_cmd(bew.be_code); X determine_visibility(); X break; X } X return 1; X } X Xsend_player_info(p1,p2,x,y,sicht) /* send info 'bout p1 to p2 */ Xint p1,p2,x,y,sicht; X { X struct sp_anzeige spa; X spa.sp_magic = SP_ANZ; X spa.sp_pid = players[p1].p_pid; X spa.sp_lfd_nr = p1; X spa.sp_flag = sicht|1; X spa.sp_score = players[p1].p_score; X spa.sp_x_pos = x; X spa.sp_y_pos = y; X spa.sp_richtg = players[p1].p_richtg; X strcpy(spa.sp_name,players[p1].p_name); X tell(p2,spa); X } X Xdo_cmd(cmd) Xint cmd; X { X int p; X switch ( cmd ) X { X case EXIT: /* leave game */ X log_out(player); X break; X case 'S': /* shoot */ X { X int new_x, new_y, p; X players[player].p_score -= 1; /* one shot costs 1 pt */ X new_x=players[player].p_x_pos; X new_y=players[player].p_y_pos; X for(;;) X { X new_x += delta_x[players[player].p_richtg]; X new_y += delta_y[players[player].p_richtg]; X if ( maze[new_y][new_x] != ' ' ) break; X for(p=0; p<N_PLAYERS; p++) X if( players[p].p_pid && X player!=p && X players[p].p_x_pos==new_x && X players[p].p_y_pos==new_y ) X { X players[p].p_score -= 10; X reposition_player(p); X players[player].p_score += 10; X } X } X break; X } X case 'A': /* turn right */ X players[player].p_richtg = (players[player].p_richtg+1)%4; X break; X case 'D': /* turn left */ X players[player].p_richtg = (players[player].p_richtg+3)%4; X break; X case 'X': /* turn back */ X players[player].p_richtg = (players[player].p_richtg+2)%4; X break; X case 'R': /* reposition */ X players[player].p_score -= 5; /* one repos costs 5 pts */ X reposition_player(player); X break; X case 'W': /* walk */ X { X int new_x, new_y; X new_x = players[player].p_x_pos + X delta_x[players[player].p_richtg]; X new_y = players[player].p_y_pos + X delta_y[players[player].p_richtg]; X if ( maze[new_y][new_x] == ' ' ) X { X players[player].p_x_pos = new_x; X players[player].p_y_pos = new_y; X } X break; X } X case ' ': /* backwalk */ X { X int new_x, new_y; X new_x = players[player].p_x_pos + X delta_x[(players[player].p_richtg+2)%4]; X new_y = players[player].p_y_pos + X delta_y[(players[player].p_richtg+2)%4]; X if ( maze[new_y][new_x] == ' ' ) X { X players[player].p_x_pos = new_x; X players[player].p_y_pos = new_y; X } X break; X } X break; X } X } X Xlog_out(p) Xint p; X { X int play; X /* recursion can occur, therefore use local structs ! */ X struct sp_anzeige raus; X if ( score_fd >= 0 ) X { X lseek(score_fd,((long)players[p].p_uid)*sizeof(long),0); X write(score_fd,&(players[player].p_score),sizeof(long)); X } X raus.sp_magic = SP_ANZ; X raus.sp_pid = players[p].p_pid; X raus.sp_lfd_nr = p; X raus.sp_x_pos = players[p].p_x_pos; X raus.sp_y_pos = players[p].p_y_pos; X raus.sp_flag = 0; X for(play=0; play<N_PLAYERS; play++) X tell(play,raus); X close (players[p].p_fd ); X unlink(players[p].p_pipe); X players[p].p_pid = 0; X } X Xtell(p,spa) Xint p; Xstruct sp_anzeige spa; X { X if ( players[p].p_pid ) X { X int n_bytes; X alarm(3); X n_bytes = write(players[p].p_fd,&spa,sizeof(spa)); X alarm(0); X if ( n_bytes<1 ) X { X players[p].p_pid = 0; /* avoid endless recursion */ X log_out(p); /* recursion */ X } X } X } X Xdetermine_visibility() X { X register i,j; /* speedup */ X for(i=0; i<N_PLAYERS; i++) X if ( players[i].p_pid ) X for(j=0; j<N_PLAYERS; j++) X if ( players[j].p_pid ) X { X int visibel; X register struct player *pi, *pj; /* speedup */ X pi = players + i; pj = players + j; X visibel = (pi->p_x_pos == pj->p_x_pos) X || (pi->p_y_pos == pj->p_y_pos) ; X if ( visibel ) X { X /* i can view j. */ X /* did he see him before X at the same position ? */ X if ( (pj->p_x_pos == pi->last_x[j]) && X (pj->p_y_pos == pi->last_y[j]) && X (pj->p_richtg== pi->last_r[j]) && X (pj->p_score == pi->last_s[j]) ) X { /* then: nothing to do. */ } X else /* he was somewhere else before. */ X { X /* was he in the game at all ? */ X if ( pi->last_x[j]>=0 ) X /* did he just look in another direction? */ X if ( (pj->p_x_pos == pi->last_x[j]) && X (pj->p_y_pos == pi->last_y[j]) ) X { /* nothing to erase then. */ } X else X /* his last position has to be erased X on the screen. */ X send_player_info(j,i,pi->last_x[j],pi->last_y[j],0); X /* store new position and send it. */ X pi->last_x[j] = pj->p_x_pos; X pi->last_y[j] = pj->p_y_pos; X pi->last_r[j] = pj->p_richtg; X pi->last_s[j] = pj->p_score; X send_player_info(j,i,pi->last_x[j],pi->last_y[j],2); X } X } X else X { X /* i cannot view j. did he not see him before? */ X if ( pi->last_x[j]<0 ) X /* if score changed, display though */ X if ( pi->last_s[j] == pj->p_score ) X { /* nothing to do here */ } X else X { X send_player_info(j,i,pi->last_x[j],pi->last_y[j],0); X pi->last_s[j] = pj->p_score; X } X else /* he was visibel before. */ X { X /* his last position on the screen has to be erased */ X send_player_info(j,i,pi->last_x[j],pi->last_y[j],0); X pi->last_x[j] = -1; X } X } X } X } X X/* END */ END_OF_FILE if test 7906 -ne `wc -c <'daemon.c'`; then echo shar: \"'daemon.c'\" unpacked with wrong size! fi # end of 'daemon.c' fi if test -f 'maze.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'maze.c'\" else echo shar: Extracting \"'maze.c'\" \(1450 characters\) sed "s/^X//" >'maze.c' <<'END_OF_FILE' X/* X * This file is part of "mazewar", an interactive X * multiuser action game for non-BSD-Unix-systems. X * Copyright (C) 1988 Hans Korneder korn@altger.uucp X * Permission is granted to the public X * to copy all parts of the source, as long as no money X * is made out of it, and the copyrightmessage is not removed. X */ X X#include "globals.h" X Xchar maze[MAZE_ROWS][MAZE_COLS] = { X/* 0123456789012345678901234567890123456789 */ X/* 0 */ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", X/* 1 */ "X X X X X X X", X/* 2 */ "X X X X X X XX X XX X XXXX XXXX XXXXXX X", X/* 3 */ "X X X X X X X X X X X X X", X/* 4 */ "X X X X X X XX XX X X XXXXXX XXX", X/* 4 */ "X X X X X X X X X XXX X X", X/* 5 */ "X X XXX XXXXXX XXXX X XXXX XXXXXXX X X X", X/* 6 */ "X X X X X X", X/* 7 */ "X XXXX XXXXXXX X XXXXXXXXX XXXXXXX X X X", X/* 8 */ "X X X X X X X X", X/* 9 */ "X XX XXX XXXXX X XXX X XXXXXX X XX XXX X", X/* 10 */ "X X X X X X X", X/* 11 */ "X X XX X X X X XXXXX XXXX XXXXXXXXXX XXX", X/* 12 */ "X X X X X X X X X X X", X/* 13 */ "X X XX X X X X X X X X XXXXXX XXXXX XXXX", X/* 14 */ "X X X X X X X X", X/* 15 */ "XX XXXXX X X XXX XXXXXXX X XXXX X XXXX X", X/* 16 */ "X X X X X X", X/* 17 */ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", X} ; END_OF_FILE if test 1450 -ne `wc -c <'maze.c'`; then echo shar: \"'maze.c'\" unpacked with wrong size! fi # end of 'maze.c' fi if test -f 'user.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'user.c'\" else echo shar: Extracting \"'user.c'\" \(4907 characters\) sed "s/^X//" >'user.c' <<'END_OF_FILE' X/* X * This file is part of "mazewar", an interactive X * multiuser action game for non-BSD-Unix-systems. X * Copyright (C) 1988 Hans Korneder korn@altger.uucp X * Permission is granted to the public X * to copy all parts of the source, as long as no money X * is made out of it, and the copyrightmessage is not removed. X */ X X#include <signal.h> X#include <curses.h> X#include "globals.h" X Xchar *user_pipe_name; Xint user_pipe_fd, daemon_pipe_fd; Xint parent_pid, child_pid; Xchar richtung[4] = { '>','^','<','v' }; X Xcatch(s) Xint s; X { X signal(s,catch); X } X Xfehler(text) Xchar *text; X { X standout(); X mvaddstr(23,0,text); X standend(); X refresh(); X sleep(4); X } X Xmain() X { X catch(SIGALRM); X catch(SIGPIPE); X parent_pid = getpid(); X initscr(); noecho(); raw(); X draw_maze(); X if ( init_pipes() ) play_the_game(); X clear(); refresh(); noraw(); echo(); endwin(); X } X Xdraw_maze() X { X int x,y; X erase(); X for(y=0; y<MAZE_ROWS; y++) X { X move(y,0); X for(x=0; x<MAZE_COLS; x++) X if ( maze[y][x] != ' ' ) addstr("[]"); X else addstr(" "); X } X mvaddstr(19,0,"a = turn left"); X mvaddstr(20,0,"d = turn right"); X mvaddstr(21,0,"x = turn back"); X mvaddstr(22,0,"s = shoot"); X mvaddstr(23,0,"q = quit"); X mvaddstr(19,20,"w = walk"); X mvaddstr(20,20,"_ = walk back"); X mvaddstr(21,20,"r = reposition"); X refresh(); X } X Xint init_pipes() X { X int n_bytes; X extern char *mktemp(); X struct anmeldung anm; X umask(0); X user_pipe_name = mktemp(MAZE_PIPE); X if ( mknod(user_pipe_name,010600,0)<0 ) X { X fehler("MAZE_PIPE cannot be created"); X return 0; X } X user_pipe_fd = open(user_pipe_name,2); X if ( user_pipe_fd<0 ) X { X fehler("MAZE_PIPE cannot be opened"); X return 0; X } X alarm(3); X daemon_pipe_fd = open(MAZE_DAEMON,1); X alarm(0); X if ( daemon_pipe_fd<0 ) X { X fehler("MAZE_DAEMON_PIPE cannot be opened"); X return 0; X } X X /* startup message to the daemon */ X anm.an_magic = ANMELD; X anm.an_pid = parent_pid; X anm.an_uid = getuid(); X strcpy(anm.an_pipe,user_pipe_name); X alarm(3); X n_bytes = write(daemon_pipe_fd,&anm,sizeof(anm)); X alarm(0); X if ( n_bytes<0 ) X { X fehler("startupmessage to the daemon could not be sent"); X return 0; X } X X return 1; X } X Xplay_the_game() X { X switch( child_pid=fork() ) X { X case -1: X fehler("cannot fork"); X break; X case 0: /* child */ X child_proc(); X break; X default: /* parent */ X parent_proc(); X break; X } X } X Xchild_proc() X { X struct sp_anzeige spa; X close(user_pipe_fd); X user_pipe_fd = open(user_pipe_name,0); X while ( read(user_pipe_fd,&spa,sizeof(spa))>0 ) X switch ( spa.sp_magic ) X { X case BILD_NEU: X clearok(stdscr); X refresh(); X break; X case SP_ANZ: X if ( spa.sp_flag & 1 ) /* within the game */ X mvprintw(19+spa.sp_lfd_nr%5,40+(spa.sp_lfd_nr/5)*20, X "%c: %-8.8s %6d", spa.sp_lfd_nr+'A', spa.sp_name, X spa.sp_score); X else /* Aus dem Spiel raus */ X mvaddstr(19+spa.sp_lfd_nr%5,40+(spa.sp_lfd_nr/5)*20, X " "); X if ( spa.sp_flag & 2 ) /* visible */ X { X move(spa.sp_y_pos,spa.sp_x_pos*2); X if ( spa.sp_pid==parent_pid ) X addch(richtung[spa.sp_richtg]); X else X addch(spa.sp_lfd_nr + 'A'); X addch(richtung[spa.sp_richtg]); X } X else X mvaddstr(spa.sp_y_pos,spa.sp_x_pos*2," "); X refresh(); X break; X } X exit(0); X } X Xparent_proc() X { X long now; X int code, status; X struct bewegung bew; X struct sp_anzeige spa; X static long last_shot = 0; X extern long time(); X X bew.be_magic = BEWEGUNG; X bew.be_pid = parent_pid; X spa.sp_magic = BILD_NEU; X do switch( code=getch() ) X { X case 'a': case 'A': X bew.be_code = 'A'; X if ( write(daemon_pipe_fd,&bew,sizeof(bew) )<0 ) code=EXIT; X break; X case 'd': case 'D': X bew.be_code = 'D'; X if ( write(daemon_pipe_fd,&bew,sizeof(bew) )<0 ) code=EXIT; X break; X case 'x': case 'X': X bew.be_code = 'X'; X if ( write(daemon_pipe_fd,&bew,sizeof(bew) )<0 ) code=EXIT; X break; X case 'w': case 'W': X bew.be_code = 'W'; X if ( write(daemon_pipe_fd,&bew,sizeof(bew) )<0 ) code=EXIT; X break; X case ' ': case '_': X bew.be_code = ' '; X if ( write(daemon_pipe_fd,&bew,sizeof(bew) )<0 ) code=EXIT; X break; X case 's': case 'S': X /* allow for 1 shot per second */ X now = time((long *)0); X if ( last_shot == now ) break; X last_shot = now; X bew.be_code = 'S'; X if ( write(daemon_pipe_fd,&bew,sizeof(bew) )<0 ) code=EXIT; X break; X case 'r': case 'R': X bew.be_code = 'R'; X if ( write(daemon_pipe_fd,&bew,sizeof(bew) )<0 ) code=EXIT; X break; X case 'Q': case 'q': case 127: case 4: /* ^D */ X code = EXIT; X bew.be_code = EXIT; X if ( write(daemon_pipe_fd,&bew,sizeof(bew) )<0 ) code=EXIT; X break; X case 12: /* ^L */ case 022: /* ^R */ X if ( write(user_pipe_fd ,&spa,sizeof(spa) )<0 ) code=EXIT; X break; X } X while ( code!=EXIT ); X close(user_pipe_fd); X while ( wait(&status) != child_pid ) ; X } X Xmsg(t)char*t;{write(2,t,strlen(t));} X/* ENDE */ END_OF_FILE if test 4907 -ne `wc -c <'user.c'`; then echo shar: \"'user.c'\" unpacked with wrong size! fi # end of 'user.c' fi echo shar: End of shell archive. exit 0