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 <stdio.h> #include <curses.h> 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 <stdio.h> #include <curses.h> main() { int i; initscr(); /* turn on curses */ clear(); /* draw some stuff */ for(i=0; i<LINES; i++ ){ /* in a loop */ move( i, i+i ); if ( i%2 == 1 ) standout(); addstr("Hello, world"); if ( i%2 == 1 ) standend(); } refresh(); /* update the screen */ getch(); /* wait for user input */ endwin(); /* reset the tty etc */ }
hello3.c
#include <stdio.h> #include <curses.h> main() { int i; initscr(); clear(); for(i=0; i<LINES; i++ ){ move( i, i+i ); if ( i%2 == 1 ) standout(); addstr("Hello, world"); if ( i%2 == 1 ) standend(); sleep(1); refresh(); } endwin(); }
hello4.c
#include <stdio.h> #include <curses.h> main() { int i; initscr(); clear(); for(i=0; i<LINES; i++ ){ move( i, i+i ); if ( i%2 == 1 ) standout(); addstr("Hello, world"); if ( i%2 == 1 ) standend(); refresh(); sleep(1); move(i,i+i); /* move back */ addstr(" "); /* erase line */ } endwin(); }
hello5.c
#include <curses.h> #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 <stdio.h> #include <signal.h> // #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 <stdio.h> #include <sys/time.h> #include <signal.h> 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 <stdio.h> #include <signal.h> #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 <stdio.h> #include <signal.h> #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 <stdio.h> #include <curses.h> #include <signal.h> /* 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 <curses.h> #include <signal.h> #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 <stdio.h> #include <curses.h> #include <signal.h> #include <fcntl.h> /* 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 <stdio.h> #include <curses.h> #include <signal.h> #include <aio.h> #include <string.h> /* 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.
“”
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<stdio.h> #include<stdlib.h> #include<sys/types.h> #include<unistd.h> 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); }