==03/12/14== Fitting, then, that my first update to my opus is monumental in length. The following are the exercises from chapter 7. These really escalated in complexity. hello1.c #include #include main() { initscr() ; /* turn on curses */ /* send requests */ clear(); /* clear screen */ move(10,20); /* row10,col20 */ addstr("Hello, world"); /* add a string */ move(LINES-1,0); /* move to LL */ refresh(); /* update the screen */ getch(); /* wait for user input */ endwin(); /* turn off curses */ } hello2.c #include #include main() { int i; initscr(); /* turn on curses */ clear(); /* draw some stuff */ for(i=0; i hello3.c #include #include main() { int i; initscr(); clear(); for(i=0; i hello4.c #include #include main() { int i; initscr(); clear(); for(i=0; i hello5.c #include #define LEFTEDGE 10 #define RIGHTEDGE 30 #define ROW 10 main() { char message[] = "Hello"; char blank[] = " "; int dir = +1; int pos = LEFTEDGE ; initscr(); clear(); while(1){ move(ROW,pos); addstr( message ); /* draw string */ move(LINES-1,COLS-1); /* park the cursor */ refresh(); /* show string */ sleep(1); move(ROW,pos); /* erase string */ addstr( blank ); pos += dir; /* advance position */ if ( pos >= RIGHTEDGE ) /* check for bounce */ dir = -1; if ( pos <= LEFTEDGE ) dir = +1; } } Up until now, these 5 examples have been playing with the curses library, creating text and moving text. sleep1.c - demonstrates sleep() #include #include // #define SHHHH main() { void wakeup(int); printf("about to sleep for 4 seconds\n"); signal(SIGALRM, wakeup); /* catch it */ alarm(4); /* set clock */ pause(); /* freeze here */ printf("Morning so soon?\n"); /* back to work */ } void wakeup(int signum) { #ifndef SHHHH printf("Alarm received from kernel\n"); #endif } ticker_demo.c - demonstrates to the programmer how an interval timer can be used to generate regular signals #include #include #include int main() { void countdown(int); signal(SIGALRM, countdown); if ( set_ticker(500) == -1 ) perror("set_ticker"); else while( 1 ) pause(); return 0; } void countdown(int signum) { static int num = 10; printf("%d ..", num--); fflush(stdout); if ( num < 0 ){ printf("DONE!\n"); exit(0); } } /* [from set_ticker.c] * set_ticker( number_of_milliseconds ) * arranges for interval timer to issue SIGALRM's at regular intervals * returns -1 on error, 0 for ok * arg in milliseconds, converted into whole seconds and microseconds * note: set_ticker(0) turns off ticker */ int set_ticker( int n_msecs ) { struct itimerval new_timeset; long n_sec, n_usecs; n_sec = n_msecs / 1000 ; /* int part */ n_usecs = ( n_msecs % 1000 ) * 1000L ; /* remainder */ new_timeset.it_interval.tv_sec = n_sec; /* set reload */ new_timeset.it_interval.tv_usec = n_usecs; /* new ticker value */ new_timeset.it_value.tv_sec = n_sec ; /* store this */ new_timeset.it_value.tv_usec = n_usecs ; /* and this */ return setitimer(ITIMER_REAL, &new_timeset, NULL); } sigdemo3.c - We toyed around with this concept on Tuesday, using signal() #include #include #define INPUTLEN 100 main(int ac, char *av[]) { void inthandler(int); void quithandler(int); char input[INPUTLEN]; int nchars; signal( SIGINT, inthandler ); /* set handler */ signal( SIGQUIT, quithandler ); /* set handler */ do { printf("\nType a message\n"); nchars = read(0, input, (INPUTLEN-1)); if ( nchars == -1 ) perror("read returned an error"); else { input[nchars] = '\0'; printf("You typed: %s", input); } } while( strncmp( input , "quit" , 4 ) != 0 ); } void inthandler(int s) { printf(" Received signal %d .. waiting\n", s ); sleep(2); printf(" Leaving inthandler \n"); } void quithandler(int s) { printf(" Received signal %d .. waiting\n", s ); sleep(3); printf(" Leaving quithandler \n"); } sigactdemo.c - goes beyond signal() and demonstrates how we may utilize sigaction() to intercept signals. #include #include #define INPUTLEN 100 main() { struct sigaction newhandler; /* new settings */ sigset_t blocked; /* set of blocked sigs */ void inthandler(); /* the handler */ char x[INPUTLEN]; /* load these two members first */ newhandler.sa_handler = inthandler; /* handler function */ newhandler.sa_flags = SA_RESETHAND | SA_RESTART; /* options */ /* then build the list of blocked signals */ sigemptyset(&blocked); /* clear all bits */ sigaddset(&blocked, SIGQUIT); /* add SIGQUIT to list */ newhandler.sa_mask = blocked; /* store blockmask */ if ( sigaction(SIGINT, &newhandler, NULL) == -1 ) perror("sigaction"); else while( 1 ){ fgets(x, INPUTLEN, stdin); printf("input: %s", x); } } void inthandler(int s) { printf("Called with signal %d\n", s); sleep(s); printf("done handling signal %d\n", s); } bounce1d.c - user controlled animation, as in user defined speed and direction! VIDJA GAMES #include #include #include /* some global settings main and the handler use */ #define MESSAGE "hello" #define BLANK " " int row; /* current row */ int col; /* current column */ int dir; /* where we are going */ int main() { int delay; /* bigger => slower */ int ndelay; /* new delay */ int c; /* user input */ void move_msg(int); /* handler for timer */ initscr(); crmode(); noecho(); clear(); row = 10; /* start here */ col = 0; dir = 1; /* add 1 to row number */ delay = 200; /* 200ms = 0.2 seconds */ move(row,col); /* get into position */ addstr(MESSAGE); /* draw message */ signal(SIGALRM, move_msg ); set_ticker( delay ); while(1) { ndelay = 0; c = getch(); if ( c == 'Q' ) break; if ( c == ' ' ) dir = -dir; if ( c == 'f' && delay > 2 ) ndelay = delay/2; if ( c == 's' ) ndelay = delay * 2 ; if ( ndelay > 0 ) set_ticker( delay = ndelay ); } endwin(); return 0; } void move_msg(int signum) { signal(SIGALRM, move_msg); /* reset, just in case */ move( row, col ); addstr( BLANK ); col += dir; /* move to new column */ move( row, col ); /* then set cursor */ addstr( MESSAGE ); /* redo message */ refresh(); /* and show it */ /* * now handle borders */ if ( dir == -1 && col <= 0 ) dir = 1; else if ( dir == 1 && col+strlen(MESSAGE) >= COLS ) dir = -1; } bounce2d.c - More advanced version of bounce1d, instead of moving in a completely linear fashion, movement in two directions is now applied simultaneously. MATH. #include #include #include "bounce.h" struct ppball the_ball ; /** the main loop **/ void set_up(); void wrap_up(); int main() { int c; set_up(); while ( ( c = getchar()) != 'Q' ){ if ( c == 'f' ) the_ball.x_ttm--; else if ( c == 's' ) the_ball.x_ttm++; else if ( c == 'F' ) the_ball.y_ttm--; else if ( c == 'S' ) the_ball.y_ttm++; } wrap_up(); } void set_up() /* * init structure and other stuff */ { void ball_move(int); the_ball.y_pos = Y_INIT; the_ball.x_pos = X_INIT; the_ball.y_ttg = the_ball.y_ttm = Y_TTM ; the_ball.x_ttg = the_ball.x_ttm = X_TTM ; the_ball.y_dir = 1 ; the_ball.x_dir = 1 ; the_ball.symbol = DFL_SYMBOL ; initscr(); noecho(); crmode(); signal( SIGINT , SIG_IGN ); mvaddch( the_ball.y_pos, the_ball.x_pos, the_ball.symbol ); refresh(); signal( SIGALRM, ball_move ); set_ticker( 1000 / TICKS_PER_SEC ); /* send millisecs per tick */ } void wrap_up() { set_ticker( 0 ); endwin(); /* put back to normal */ } void ball_move(int signum) { int y_cur, x_cur, moved; signal( SIGALRM , SIG_IGN ); /* dont get caught now */ y_cur = the_ball.y_pos ; /* old spot */ x_cur = the_ball.x_pos ; moved = 0 ; if ( the_ball.y_ttm > 0 && the_ball.y_ttg-- == 1 ){ the_ball.y_pos += the_ball.y_dir ; /* move */ the_ball.y_ttg = the_ball.y_ttm ; /* reset*/ moved = 1; } if ( the_ball.x_ttm > 0 && the_ball.x_ttg-- == 1 ){ the_ball.x_pos += the_ball.x_dir ; /* move */ the_ball.x_ttg = the_ball.x_ttm ; /* reset*/ moved = 1; } if ( moved ){ mvaddch( y_cur, x_cur, BLANK ); mvaddch( y_cur, x_cur, BLANK ); mvaddch( the_ball.y_pos, the_ball.x_pos, the_ball.symbol ); bounce_or_lose( &the_ball ); move(LINES-1,COLS-1); refresh(); } signal( SIGALRM, ball_move); /* for unreliable systems */ } int bounce_or_lose(struct ppball *bp) { int return_val = 0 ; if ( bp->y_pos == TOP_ROW ){ bp->y_dir = 1 ; return_val = 1 ; } else if ( bp->y_pos == BOT_ROW ){ bp->y_dir = -1 ; return_val = 1; } if ( bp->x_pos == LEFT_EDGE ){ bp->x_dir = 1 ; return_val = 1 ; } else if ( bp->x_pos == RIGHT_EDGE ){ bp->x_dir = -1; return_val = 1; } return return_val; } bounce.h - The accompanying header to bounce1d and bounce2d /* bounce.h */ /* some settings for the game */ #define BLANK ' ' #define DFL_SYMBOL 'o' #define TOP_ROW 5 #define BOT_ROW 20 #define LEFT_EDGE 10 #define RIGHT_EDGE 70 #define X_INIT 10 /* starting col */ #define Y_INIT 10 /* starting row */ #define TICKS_PER_SEC 50 /* affects speed */ #define X_TTM 5 #define Y_TTM 8 /** the ping pong ball **/ struct ppball { int y_pos, x_pos, y_ttm, x_ttm, y_ttg, x_ttg, y_dir, x_dir; char symbol ; } ; bounce_async.c and bounce_aio.c are above my head, currently. Here they are, respectively. Hopefully we will dissect these in class. #include #include #include #include /* The state of the game */ #define MESSAGE "hello" #define BLANK " " int row = 10; /* current row */ int col = 0; /* current column */ int dir = 1; /* where we are going */ int delay = 200; /* how long to wait */ int done = 0; main() { void on_alarm(int); /* handler for alarm */ void on_input(int); /* handler for keybd */ void enable_kbd_signals(); initscr(); /* set up screen */ crmode(); noecho(); clear(); signal(SIGIO, on_input); /* install a handler */ enable_kbd_signals(); /* turn on kbd signals */ signal(SIGALRM, on_alarm); /* install alarm handler */ set_ticker(delay); /* start ticking */ move(row,col); /* get into position */ addstr( MESSAGE ); /* draw initial image */ while( !done ) /* the main loop */ pause(); endwin(); } void on_input(int signum) { int c = getch(); /* grab the char */ if ( c == 'Q' || c == EOF ) done = 1; else if ( c == ' ' ) dir = -dir; } void on_alarm(int signum) { signal(SIGALRM, on_alarm); /* reset, just in case */ mvaddstr( row, col, BLANK ); /* note mvaddstr() */ col += dir; /* move to new column */ mvaddstr( row, col, MESSAGE ); /* redo message */ refresh(); /* and show it */ /* * now handle borders */ if ( dir == -1 && col <= 0 ) dir = 1; else if ( dir == 1 && col+strlen(MESSAGE) >= COLS ) dir = -1; } /* * install a handler, tell kernel who to notify on input, enable signals */ void enable_kbd_signals() { int fd_flags; fcntl(0, F_SETOWN, getpid()); fd_flags = fcntl(0, F_GETFL); fcntl(0, F_SETFL, (fd_flags|O_ASYNC)); } And #include #include #include #include #include /* The state of the game */ #define MESSAGE "hello" #define BLANK " " int row = 10; /* current row */ int col = 0; /* current column */ int dir = 1; /* where we are going */ int delay = 200; /* how long to wait */ int done = 0; struct aiocb kbcbuf; /* an aio control buf */ main() { void on_alarm(int); /* handler for alarm */ void on_input(int); /* handler for keybd */ void setup_aio_buffer(); initscr(); /* set up screen */ crmode(); noecho(); clear(); signal(SIGIO, on_input); /* install a handler */ setup_aio_buffer(); /* initialize aio ctrl buff */ aio_read(&kbcbuf); /* place a read request */ signal(SIGALRM, on_alarm); /* install alarm handler */ set_ticker(delay); /* start ticking */ mvaddstr( row, col, MESSAGE ); /* draw initial image */ while( !done ) /* the main loop */ pause(); endwin(); } /* * handler called when aio_read() has stuff to read * First check for any error codes, and if ok, then get the return code */ void on_input(int s) { int c; char *cp = (char *) kbcbuf.aio_buf; /* cast to char * */ /* check for errors */ if ( aio_error(&kbcbuf) != 0 ) perror("reading failed"); else /* get number of chars read */ if ( aio_return(&kbcbuf) == 1 ) { c = *cp; if ( c == 'Q' || c == EOF ) done = 1; else if ( c == ' ' ) dir = -dir; } /* place a new request */ aio_read(&kbcbuf); } void on_alarm(int s) { signal(SIGALRM, on_alarm); /* reset, just in case */ mvaddstr( row, col, BLANK ); /* clear old string */ col += dir; /* move to new column */ mvaddstr( row, col, MESSAGE ); /* draw new string */ refresh(); /* and show it */ /* * now handle borders */ if ( dir == -1 && col <= 0 ) dir = 1; else if ( dir == 1 && col+strlen(MESSAGE) >= COLS ) dir = -1; } /* * set members of struct. * First specify args like those for read(fd, buf, num) and offset * Then specify what to do (send signal) and what signal (SIGIO) */ void setup_aio_buffer() { static char input[1]; /* 1 char of input */ /* describe what to read */ kbcbuf.aio_fildes = 0; /* standard intput */ kbcbuf.aio_buf = input; /* buffer */ kbcbuf.aio_nbytes = 1; /* number to read */ kbcbuf.aio_offset = 0; /* offset in file */ /* describe what to do when read is ready */ kbcbuf.aio_sigevent.sigev_notify = SIGEV_SIGNAL; kbcbuf.aio_sigevent.sigev_signo = SIGIO; /* send sIGIO */ } This chapter contained almost as much information as the preceding 6 chapters. Sometimes I wonder if the author to this book finds joy in anything since he obviously has attained supreme knowledge. ==3/13/14== "" ==3/20/14== Today we continued with Chapter 8, adding to the fork concept. Using fork4 we played with wait() and added some interesting use of exec(). in this case we used execl(). #include #include #include #include int main(int argc, char **argv) { pid_t me, you; char input, *fname; FILE *fptr; int i, j, data[100][2], rank = 0, numproc = 0; int pidlist[5]; for(i=0; i<100; i++) { data[i][0] = i * i; } pidlist[0] = getpid(); for(i = 1; i <= 4; i++) { if(pidlist[0] == getpid()) { rank = rank + 1; pidlist[i] = fork(); } } if (getpid() == pidlist[0]) { printf("I am PID %i, my child processes are: ", pidlist[0]); for(i=1; i<=4; i++) printf("%i ", pidlist[i]); printf("\n"); // could put code to wait for child process termination here for(i = 0; i < rank; i++) { you = wait(&j); printf("child PID %d has finished with status %d\n",you,j); } } else { if(rank==2){ execl("/bin/ls","ls","-l",NULL); } me = getpid(); printf("I am child %i (pid %i), so I will process ", rank, me); printf("elements %i-%i ...\n", ((rank*25)-25), ((((rank+1)*25)-1)-25)); for(i = ((rank*25)-25); i < (((rank+1)*25)-25); i++) data[i][1] = data[i][0] * rank; fname = (char *) malloc (sizeof(char) * 8); sprintf(fname, "rank%i", rank); fptr = fopen(fname, "w"); fprintf(fptr, "%i\n", (rank*25)-25); fprintf(fptr, "%i\n", (((rank+1)*25)-1)-25); for(i = rank*25-25; i < ((rank+1)*25)-25; i++) fprintf(fptr, "%i\t%i\n", data[i][0], data[i][1]); fclose(fptr); sleep(rank * 2+60); } return(0); }