瀏覽代碼

first commit

Stehpen Corya 5 月之前
當前提交
c094d4e767
共有 79 個文件被更改,包括 3368 次插入0 次删除
  1. 1 0
      README.md
  2. 19 0
      lab01/Makefile
  3. 15 0
      lab01/answers.txt
  4. 73 0
      lab01/more01.c
  5. 78 0
      lab01/more02.c
  6. 125 0
      lab01/more03.c
  7. 13 0
      lab02/Makefile
  8. 二進制
      lab02/who2
  9. 97 0
      lab02/who2.c
  10. 69 0
      lab02/who2.c.1
  11. 二進制
      lab03/Lab03.pdf
  12. 8 0
      lab03/Makefile
  13. 50 0
      lab03/append.c
  14. 5 0
      lab03/f1.c
  15. 5 0
      lab03/f2.c
  16. 5 0
      lab03/func.h
  17. 7 0
      lab03/main.c
  18. 19 0
      lab03/readFile.c
  19. 15 0
      lab03/writeToFile.c
  20. 二進制
      lab04/Lab04.pdf
  21. 19 0
      lab04/Makefile
  22. 36 0
      lab04/fileinfo.c
  23. 14 0
      lab04/filesize.c
  24. 19 0
      lab04/gid_to_name.c
  25. 6 0
      lab04/gid_to_name.h
  26. 38 0
      lab04/ls1.c
  27. 145 0
      lab04/ls2.c
  28. 86 0
      lab04/ls3.c
  29. 23 0
      lab04/mode_to_letters.c
  30. 6 0
      lab04/mode_to_letters.h
  31. 30 0
      lab04/sample-getgrouplist.c
  32. 24 0
      lab04/show_file_info.c
  33. 6 0
      lab04/show_file_info.h
  34. 二進制
      lab04/submission.zip
  35. 19 0
      lab04/uid_to_name.c
  36. 6 0
      lab04/uid_to_name.h
  37. 1 0
      lab05/.~lock.Lab05_text.docx#
  38. 二進制
      lab05/Lab05.pdf
  39. 二進制
      lab05/Lab05_text.docx
  40. 7 0
      lab05/Makefile
  41. 1 0
      lab05/demodir.txt
  42. 77 0
      lab05/spwd.c
  43. 二進制
      lab06/ECE28200 Lab06.docx
  44. 7 0
      lab06/Makefile
  45. 65 0
      lab06/lockingappend.c
  46. 二進制
      lab07/Lab07.docx
  47. 43 0
      lab07/Makefile
  48. 38 0
      lab07/play_again0.c
  49. 67 0
      lab07/play_again1.c
  50. 66 0
      lab07/play_again2.c
  51. 108 0
      lab07/play_again3.c
  52. 114 0
      lab07/play_again3a.c
  53. 120 0
      lab07/play_again3b.c
  54. 127 0
      lab07/play_again4.c
  55. 149 0
      lab07/play_again_extended.c
  56. 81 0
      lab07/rotate.c
  57. 49 0
      lab07/sigdemo1.c
  58. 19 0
      lab07/sigdemo2.c
  59. 1 0
      lab08/.gitignore
  60. 二進制
      lab08/Chapter4 Source Code.zip
  61. 二進制
      lab08/Lab08_2025.docx
  62. 55 0
      lab08/Makefile
  63. 27 0
      lab08/bounce.h
  64. 74 0
      lab08/bounce1d.c
  65. 130 0
      lab08/bounce2d.c
  66. 117 0
      lab08/bounce_aio.c
  67. 83 0
      lab08/bounce_async.c
  68. 23 0
      lab08/hello1.c
  69. 27 0
      lab08/hello2.c
  70. 26 0
      lab08/hello3.c
  71. 26 0
      lab08/hello4.c
  72. 34 0
      lab08/hello5.c
  73. 194 0
      lab08/pong.c
  74. 124 0
      lab08/pong_sp.c
  75. 32 0
      lab08/set_ticker.c
  76. 42 0
      lab08/sigactdemo.c
  77. 49 0
      lab08/sigdemo3.c
  78. 26 0
      lab08/sleep1.c
  79. 58 0
      lab08/ticker_demo.c

+ 1 - 0
README.md

@@ -0,0 +1 @@
+# ECE 282

+ 19 - 0
lab01/Makefile

@@ -0,0 +1,19 @@
+#
+# Makefile for Chapter 01
+#
+# Type  make    to compile all the programs
+# in the chapter 
+#
+all: more01 more02 more03
+
+clean:
+	rm -f more01 more02 more03
+
+more01: more01.c 
+	cc -o more01 more01.c 
+
+more02: more02.c 
+	cc -o more02 more02.c 
+
+more03: more03.c
+	cc -o more03 more03.c

+ 15 - 0
lab01/answers.txt

@@ -0,0 +1,15 @@
+a) date prints the number of seconds since UNIX epoch
+b) who shows which users are logged in
+c) whoami shows the current user
+d) who am i does nothing
+e) pwd prints the current directory
+f) cd changes the working directory
+g) mkdir creates a new directory
+h) rmdir removes a directory
+i) rm removes a file or a directory and its contents with the -r flag
+j) cp copies a file
+k) mv moves a file
+l) ls lists the files in a directory (with permissions)
+m) cat concatenates a file or stream
+n) more outputs a file to the terminal with the option to scroll
+o) less does the same as more but starts at the end of the file

+ 73 - 0
lab01/more01.c

@@ -0,0 +1,73 @@
+/* more01.c  - version 0.1 of more
+ *	read and print 24 lines then pause for a few special commands
+ */
+
+#include	<stdio.h>
+#include	<stdlib.h>
+
+#define	PAGELEN	24
+#define	LINELEN	512
+
+void do_more(FILE *);
+int  see_more();
+
+int main( int ac , char *av[] )
+{
+	FILE	*fp;
+
+	if ( ac == 1 )
+		do_more( stdin );
+	else
+		while ( --ac )
+			if ( (fp = fopen( *++av , "r" )) != NULL )
+			{
+				do_more( fp ) ; 
+				fclose( fp );
+			}
+			else
+				exit(1);
+	return 0;
+}
+
+void do_more( FILE *fp )
+/*
+ *  read PAGELEN lines, then call see_more() for further instructions
+ */
+{
+	char	line[LINELEN];
+	int	num_of_lines = 0;
+	int	see_more(), reply;
+
+	while ( fgets( line, LINELEN, fp ) ){		/* more input	*/
+		if ( num_of_lines == PAGELEN ) {	/* full screen?	*/
+			reply = see_more();		/* y: ask user  */
+			if ( reply == 0 )		/*    n: done   */
+				break;
+			num_of_lines -= reply;		/* reset count	*/
+		}
+		if ( fputs( line, stdout )  == EOF )	/* show line	*/
+			exit(1);			/* or die	*/
+		num_of_lines++;				/* count it	*/
+	}
+}
+
+int see_more()
+/*
+ *	print message, wait for response, return # of lines to advance
+ *	q means no, space means yes, CR means one line
+ */
+{
+	int	c;
+
+	printf("\033[7m more? \033[m");		/* reverse on a vt100	*/
+	while( (c=getchar()) != EOF )			/* get response	*/
+	{
+		if ( c == 'q' )			/* q -> N		*/
+			return 0;
+		if ( c == ' ' )			/* ' ' => next page	*/
+			return PAGELEN;		/* how many to show	*/
+		if ( c == '\n' )		/* Enter key => 1 line	*/
+			return 1;		
+	}
+	return 0;
+}

+ 78 - 0
lab01/more02.c

@@ -0,0 +1,78 @@
+/*  more02.c  - version 0.2 of more
+ *	read and print 24 lines then pause for a few special commands
+ *      feature of version 0.2: reads from /dev/tty for commands
+ */
+#include	<stdio.h>
+#include	<stdlib.h>
+
+#define	PAGELEN	24
+#define	LINELEN	512
+
+void do_more(FILE *);
+int see_more(FILE *);
+
+int main( int ac , char *av[] )
+{
+	FILE	*fp;
+
+	if ( ac == 1 )
+		do_more( stdin );
+	else
+		while ( --ac )
+			if ( (fp = fopen( *++av , "r" )) != NULL )
+			{
+				do_more( fp ) ; 
+				fclose( fp );
+			}
+			else
+				exit(1);
+	return 0;
+}
+
+void do_more( FILE *fp )
+/*
+ *  read PAGELEN lines, then call see_more() for further instructions
+ */
+{
+	char	line[LINELEN];
+	int	num_of_lines = 0;
+	int	see_more(FILE *), reply;
+	FILE	*fp_tty;
+
+	fp_tty = fopen( "/dev/tty", "r" );	   /* NEW: cmd stream   */
+	if ( fp_tty == NULL )			   /* if open fails     */
+		exit(1);                           /* no use in running */
+
+	while ( fgets( line, LINELEN, fp ) ){		/* more input	*/
+		if ( num_of_lines == PAGELEN ) {	/* full screen?	*/
+			reply = see_more(fp_tty);  /* NEW: pass FILE *  */
+			if ( reply == 0 )		/*    n: done   */
+				break;
+			num_of_lines -= reply;		/* reset count	*/
+		}
+		if ( fputs( line, stdout )  == EOF )	/* show line	*/
+			exit(1);			/* or die	*/
+		num_of_lines++;				/* count it	*/
+	}
+}
+
+int see_more(FILE *cmd)				   /* NEW: accepts arg  */
+/*
+ *	print message, wait for response, return # of lines to advance
+ *	q means no, space means yes, CR means one line
+ */
+{
+	int	c;
+
+	printf("\033[7m more? \033[m");		/* reverse on a vt100	*/
+	while( (c=getc(cmd)) != EOF )		/* NEW: reads from tty  */
+	{
+		if ( c == 'q' )			/* q -> N		*/
+			return 0;
+		if ( c == ' ' )			/* ' ' => next page	*/
+			return PAGELEN;		/* how many to show	*/
+		if ( c == '\n' )		/* Enter key => 1 line	*/
+			return 1;		
+	}
+	return 0;
+}

+ 125 - 0
lab01/more03.c

@@ -0,0 +1,125 @@
+/*  more02.c  - version 0.2 of more
+ *	read and print 24 lines then pause for a few special commands
+ *      feature of version 0.2: reads from /dev/tty for commands
+ */
+#include	<stdio.h>
+#include	<stdlib.h>
+#include    <string.h>
+
+#define	PAGELEN	24
+#define	LINELEN	512
+
+void do_more(FILE *);
+int see_more(FILE *);
+
+int main( int ac , char *av[] )
+{
+    char flag[] = "-o";
+    char *outname;
+    char *inname;
+    int c;
+
+	FILE	*fp;
+    FILE    *outfile;
+
+    if ( ac == 4 )
+    {
+        for ( int i = 0; i < ac; i++)
+        {
+            if ( ! strcmp (av[i], flag) )
+            {
+                outname = av[i+1];
+                printf ("%s\n", outname);
+                if ( i == 1 )
+                {
+                    inname = av[3];
+                }
+                if ( i == 2 )
+                {
+                    inname = av[1];
+                }
+                printf ("%s\n", inname);
+            }
+        }
+
+        fp = fopen (inname, "r");
+        outfile = fopen (outname, "w");
+        while ( (c = fgetc (fp) ) != EOF )
+        {
+            fputc( c, outfile );
+        }
+        fclose (outfile);
+        fclose (fp);
+
+        printf ("%s\n", "here");
+        fp = fopen (inname, "r");
+        do_more (fp);
+        fclose (fp);
+        printf ("%s\n", "here1");
+    }
+
+	if ( ac == 1 )
+    {
+		do_more( stdin );
+    }
+    if ( ac == 2 )
+    {
+		while ( --ac )
+			if ( (fp = fopen( *++av , "r" )) != NULL )
+			{
+				do_more( fp );
+				fclose( fp );
+			}
+			else
+				exit(1);
+    }
+	return 0;
+}
+
+void do_more( FILE *fp )
+/*
+ *  read PAGELEN lines, then call see_more() for further instructions
+ */
+{
+	char	line[LINELEN];
+	int	num_of_lines = 0;
+	int	see_more(FILE *), reply;
+	FILE	*fp_tty;
+
+	fp_tty = fopen( "/dev/tty", "r" );	   /* NEW: cmd stream   */
+	if ( fp_tty == NULL )			   /* if open fails     */
+		exit(1);                           /* no use in running */
+
+	while ( fgets( line, LINELEN, fp ) ){		/* more input	*/
+		if ( num_of_lines == PAGELEN ) {	/* full screen?	*/
+			reply = see_more(fp_tty);  /* NEW: pass FILE *  */
+			if ( reply == 0 )		/*    n: done   */
+				break;
+			num_of_lines -= reply;		/* reset count	*/
+		}
+		if ( fputs( line, stdout )  == EOF )	/* show line	*/
+			exit(1);			/* or die	*/
+		num_of_lines++;				/* count it	*/
+	}
+}
+
+int see_more(FILE *cmd)				   /* NEW: accepts arg  */
+/*
+ *	print message, wait for response, return # of lines to advance
+ *	q means no, space means yes, CR means one line
+ */
+{
+	int	c;
+
+	printf("\033[7m more? \033[m");		/* reverse on a vt100	*/
+	while( (c=getc(cmd)) != EOF )		/* NEW: reads from tty  */
+	{
+		if ( c == 'q' )			/* q -> N		*/
+			return 0;
+		if ( c == ' ' )			/* ' ' => next page	*/
+			return PAGELEN;		/* how many to show	*/
+		if ( c == '\n' )		/* Enter key => 1 line	*/
+			return 1;		
+	}
+	return 0;
+}

+ 13 - 0
lab02/Makefile

@@ -0,0 +1,13 @@
+#
+# Makefile for Chapter 01
+#
+# Type  make    to compile all the programs
+# in the chapter 
+#
+all: who2
+
+clean:
+	rm -f who2
+
+who2: who2.c
+	gcc -o who2 who2.c

二進制
lab02/who2


+ 97 - 0
lab02/who2.c

@@ -0,0 +1,97 @@
+/* who2.c  - read /etc/utmp and list info therein
+ *         - suppresses empty records
+ *         - formats time nicely
+ */
+#include        <stdio.h>
+#include        <unistd.h>
+#include        <utmp.h>
+#include        <fcntl.h>
+#include        <time.h>
+#include	<string.h>
+
+/* #define      SHOWHOST */
+
+void showtime(long);
+void show_info(struct utmp *);
+
+int main( int ac , char *av[] )
+{
+	char arg2[] = "am";
+	char arg3[] = "i";
+
+        struct utmp     utbuf;          /* read info into here */
+        int             utmpfd;         /* read from this descriptor */
+
+        if ( (utmpfd = open(UTMP_FILE, O_RDONLY)) == -1 ){
+                perror(UTMP_FILE);
+                exit(1);
+        }
+
+	if (ac == 1) {
+	        while( read(utmpfd, &utbuf, sizeof(utbuf)) == sizeof(utbuf) )
+       	        	show_info( &utbuf );
+	}
+
+	if ( ac > 1 ) {
+		if ( ! strcmp (av[1], arg2 ) ) {
+			if ( ! strcmp (av[2], arg3) ) {
+				// user has typed "who am i"
+				while( read(utmpfd, &utbuf, sizeof(utbuf)) == sizeof(utbuf) )
+                        		// show_info( &utbuf );
+					show_name ( &utbuf );
+			}
+		}
+	}
+
+       	close(utmpfd);
+
+
+        return 0;
+}
+
+void show_name( struct utmp *utbufp )
+{
+        if ( utbufp->ut_type != USER_PROCESS )
+                return;
+	printf("%s\n", utbufp->ut_name);      /* the logname  */
+}
+
+/*
+ *      show info()
+ *                      displays the contents of the utmp struct
+ *                      in human readable form
+ *                      * displays nothing if record has no user name
+ */
+void show_info( struct utmp *utbufp )
+{
+        if ( utbufp->ut_type != USER_PROCESS )
+                return;
+
+        printf("%-8.8s", utbufp->ut_name);      /* the logname  */
+        printf(" ");                            /* a space      */
+        printf("%-8.8s", utbufp->ut_line);      /* the tty      */
+        printf(" ");                            /* a space      */
+        showtime( utbufp->ut_time );            /* display time */
+#ifdef SHOWHOST
+        if ( utbufp->ut_host[0] != '\0' )
+                printf(" (%s)", utbufp->ut_host);/* the host    */
+#endif
+        printf("\n");                          /* newline      */
+}
+
+void showtime( long timeval )
+/*
+ *      displays time in a format fit for human consumption
+ *      uses ctime to build a string then picks parts out of it
+ *      Note: %12.12s prints a string 12 chars wide and LIMITS
+ *      it to 12chars.
+ */
+{
+        char    *cp;                    /* to hold address of time      */
+
+        cp = ctime(&timeval);           /* convert time to string       */
+                                        /* string looks like            */
+                                        /* Mon Feb  4 00:46:40 EST 1991 */
+                                        /* 0123456789012345.            */
+        printf("%12.12s", cp+4 );       /* pick 12 chars from pos 4     */
+}

+ 69 - 0
lab02/who2.c.1

@@ -0,0 +1,69 @@
+/* who2.c  - read /etc/utmp and list info therein
+ *         - suppresses empty records
+ *         - formats time nicely
+ */
+#include        <stdio.h>
+#include        <unistd.h>
+#include        <utmp.h>
+#include        <fcntl.h>
+#include        <time.h>
+
+/* #define      SHOWHOST */
+
+void showtime(long);
+void show_info(struct utmp *);
+
+int main()
+{
+        struct utmp     utbuf;          /* read info into here */
+        int             utmpfd;         /* read from this descriptor */
+
+        if ( (utmpfd = open(UTMP_FILE, O_RDONLY)) == -1 ){
+                perror(UTMP_FILE);
+                exit(1);
+        }
+
+        while( read(utmpfd, &utbuf, sizeof(utbuf)) == sizeof(utbuf) )
+                show_info( &utbuf );
+        close(utmpfd);
+        return 0;
+}
+/*
+ *      show info()
+ *                      displays the contents of the utmp struct
+ *                      in human readable form
+ *                      * displays nothing if record has no user name
+ */
+void show_info( struct utmp *utbufp )
+{
+        if ( utbufp->ut_type != USER_PROCESS )
+                return;
+
+        printf("%-8.8s", utbufp->ut_name);      /* the logname  */
+        printf(" ");                            /* a space      */
+        printf("%-8.8s", utbufp->ut_line);      /* the tty      */
+        printf(" ");                            /* a space      */
+        showtime( utbufp->ut_time );            /* display time */
+#ifdef SHOWHOST
+        if ( utbufp->ut_host[0] != '\0' )
+                printf(" (%s)", utbufp->ut_host);/* the host    */
+#endif
+        printf("\n");                          /* newline      */
+}
+
+void showtime( long timeval )
+/*
+ *      displays time in a format fit for human consumption
+ *      uses ctime to build a string then picks parts out of it
+ *      Note: %12.12s prints a string 12 chars wide and LIMITS
+ *      it to 12chars.
+ */
+{
+        char    *cp;                    /* to hold address of time      */
+
+        cp = ctime(&timeval);           /* convert time to string       */
+                                        /* string looks like            */
+                                        /* Mon Feb  4 00:46:40 EST 1991 */
+                                        /* 0123456789012345.            */
+        printf("%12.12s", cp+4 );       /* pick 12 chars from pos 4     */
+}

二進制
lab03/Lab03.pdf


+ 8 - 0
lab03/Makefile

@@ -0,0 +1,8 @@
+all: append
+
+clean:
+	rm append
+
+append: append.c
+	gcc -o append append.c
+

+ 50 - 0
lab03/append.c

@@ -0,0 +1,50 @@
+#include        <stdio.h>
+#include	<string.h>
+#include	<stdlib.h>
+
+int main( int ac , char *av[] )
+{
+
+	// print the help flag thing
+	if ( (ac < 2 ) || ( ! strcmp (av[1], "--help") ) ) {
+		printf ("%s\n", "This program appends a source file to a destination file.");
+		printf ("%s\n", "syntax:");
+		printf ("\t%s\n", "append DESTINATION SOURCE");
+	} else {
+		if (ac < 3) {
+			printf ("%s\n", "Destination file must be provided.");
+			printf ("%s\n", "See 'append --help'.");
+			return 1;
+		} else {
+			// av[1] is destination
+			// av[2] is source
+			FILE *destination, *source;
+
+			// open the source file
+			source = fopen (av[2], "r");
+
+			// error if there is no source
+			if ( !source ) {
+				printf ("Error: Source file '%s' not found.\n", av[2]);
+				return 1;
+			}
+
+			// buffer for reading
+			char buffer[128];
+
+			// open (or create) the destination file
+			destination = fopen (av[1], "a");
+
+			// read into buffer and write to file
+			while (fgets (buffer, sizeof (buffer), source)) {
+				fprintf (destination, "%s", buffer);
+			}
+
+			// clean up
+			fclose (source);
+			fclose (destination);
+		}
+	}
+
+	return 0;
+}

+ 5 - 0
lab03/f1.c

@@ -0,0 +1,5 @@
+#include "func.h"
+
+void f1(){
+	printf("I am F1\n");
+}

+ 5 - 0
lab03/f2.c

@@ -0,0 +1,5 @@
+#include "func.h"
+
+void f2(){
+	printf("I am F2\n");
+}

+ 5 - 0
lab03/func.h

@@ -0,0 +1,5 @@
+#pragma once
+#include <stdio.h>
+
+void f1();
+void f2();

+ 7 - 0
lab03/main.c

@@ -0,0 +1,7 @@
+#include "func.h"
+
+int main(){
+	f1();
+	f2();
+	return 0;
+}

+ 19 - 0
lab03/readFile.c

@@ -0,0 +1,19 @@
+/* fgets example 
+ * http://www.cplusplus.com/reference/cstdio/fgets/
+ */
+#include <stdio.h>
+
+int main()
+{
+   FILE * pFile;
+   char mystring [100];
+
+   pFile = fopen ("myfile.txt" , "r");
+   if (pFile == NULL) perror ("Error opening file");
+   else {
+     if ( fgets (mystring , 100 , pFile) != NULL )
+       puts (mystring);
+     fclose (pFile);
+   }
+   return 0;
+}

+ 15 - 0
lab03/writeToFile.c

@@ -0,0 +1,15 @@
+/* fputs example */
+#include <stdio.h>
+
+int main ()
+{
+   FILE * pFile;
+   char sentence [256];
+
+   printf ("Enter sentence to append: ");
+   fgets (sentence,256,stdin);
+   pFile = fopen ("mylog.txt","a");
+   fputs (sentence,pFile);
+   fclose (pFile);
+   return 0;
+}

二進制
lab04/Lab04.pdf


+ 19 - 0
lab04/Makefile

@@ -0,0 +1,19 @@
+all: ls3
+
+clean:
+	rm ls3 mode_to_letters.o gid_to_name.o uid_to_name.o show_file_info.o ls3.o
+
+ls3: ls3.c mode_to_letters.o gid_to_name.o uid_to_name.o show_file_info.o ls3.o
+	gcc -g -o ls3 *.o
+
+mode_to_letters.o: mode_to_letters.c
+	gcc -g -c mode_to_letters.c
+
+gid_to_name.o: gid_to_name.c
+	gcc -g -c gid_to_name.c
+
+uid_to_name.o: uid_to_name.c
+	gcc -g -c uid_to_name.c
+
+show_file_info.o: show_file_info.c
+	gcc -g -c show_file_info.c

+ 36 - 0
lab04/fileinfo.c

@@ -0,0 +1,36 @@
+/* statinfo.c - demonstrates using stat() to obtain
+ *              file information.
+ *            - some members are just numbers...
+ */
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+void show_stat_info(char *, struct stat *);
+
+int main(int ac, char *av[])
+{
+    struct stat info;        /* buffer for file info */
+
+    if (ac>1)
+        if( stat(av[1], &info) != -1 ){
+            show_stat_info( av[1], &info );
+            return 0;
+        }
+        else
+            perror(av[1]);  /* report stat() errors  */
+    return 1;
+}
+void show_stat_info(char *fname, struct stat *buf)
+/*
+ * displays some info from stat in a name=value format
+ */
+{
+    printf("   mode: %o\n", buf->st_mode);         /* type + mode */
+    printf("  links: %d\n", buf->st_nlink);        /* # links     */
+    printf("   user: %d\n", buf->st_uid);          /* user id     */
+    printf("  group: %d\n", buf->st_gid);          /* group id    */
+    printf("   size: %d\n", buf->st_size);         /* file size   */
+    printf("modtime: %d\n", buf->st_mtime);        /* modified    */
+    printf("   name: %s\n", fname );               /* filename    */
+}

+ 14 - 0
lab04/filesize.c

@@ -0,0 +1,14 @@
+/* filesize.c - prints size of passwd file */
+
+#include <stdio.h>
+#include <sys/stat.h>
+
+int main()
+{
+	struct stat infobuf;              /* place to store info */
+
+	if ( stat( "/etc/passwd", &infobuf) == -1 )  /* get info */
+		perror("/etc/passwd");
+	else
+		printf(" The size of /etc/passwd is %d\n", infobuf.st_size );
+}

+ 19 - 0
lab04/gid_to_name.c

@@ -0,0 +1,19 @@
+#include        <grp.h>
+#include	<stddef.h>
+#include	<stdio.h>
+
+char *gid_to_name( gid_t gid )
+/*
+ *      returns pointer to group number gid. used getgrgid(3)
+ */
+{
+        struct group *getgrgid(), *grp_ptr;
+        static  char numstr[10];
+
+        if ( ( grp_ptr = getgrgid(gid) ) == NULL ){
+                sprintf(numstr,"%d", gid);
+                return numstr;
+        }
+        else
+                return grp_ptr->gr_name;
+}

+ 6 - 0
lab04/gid_to_name.h

@@ -0,0 +1,6 @@
+#ifndef	gid_to_name_H
+#define	gid_to_name_H
+
+char *gid_to_name( gid_t );
+
+#endif

+ 38 - 0
lab04/ls1.c

@@ -0,0 +1,38 @@
+/** ls1.c
+ **   purpose  list contents of directory or directories
+ **   action   if no args, use .  else list files in args
+ **/
+#include	<stdio.h>
+#include	<sys/types.h>
+#include	<dirent.h>
+
+void do_ls(char []);
+
+main(int ac, char *av[])
+{
+	if ( ac == 1 )
+		do_ls( "." );
+	else
+		while ( --ac ){
+			printf("%s:\n", *++av );
+			do_ls( *av );
+		}
+}
+
+void do_ls( char dirname[] )
+/*
+ *	list files in directory called dirname
+ */
+{
+	DIR		*dir_ptr;		/* the directory */
+	struct dirent	*direntp;		/* each entry	 */
+
+	if ( ( dir_ptr = opendir( dirname ) ) == NULL )
+		fprintf(stderr,"ls1: cannot open %s\n", dirname);
+	else
+	{
+		while ( ( direntp = readdir( dir_ptr ) ) != NULL )
+			printf("%s\n", direntp->d_name );
+		closedir(dir_ptr);
+	}
+}

+ 145 - 0
lab04/ls2.c

@@ -0,0 +1,145 @@
+/* ls2.c
+ *	purpose  list contents of directory or directories
+ *	action   if no args, use .  else list files in args
+ *	note     uses stat and pwd.h and grp.h 
+ *	BUG: try ls2 /tmp  
+ */
+#include	<stdio.h>
+#include	<sys/types.h>
+#include	<dirent.h>
+#include	<sys/stat.h>
+
+void do_ls(char[]);
+void dostat(char *);
+void show_file_info( char *, struct stat *);
+void mode_to_letters( int , char [] );
+char *uid_to_name( uid_t );
+char *gid_to_name( gid_t );
+
+main(int ac, char *av[])
+{
+	if ( ac == 1 )
+		do_ls( "." );
+	else
+		while ( --ac ){
+			printf("%s:\n", *++av );
+			do_ls( *av );
+		}
+}
+
+void do_ls( char dirname[] )
+/*
+ *	list files in directory called dirname
+ */
+{
+	DIR		*dir_ptr;		/* the directory */
+	struct dirent	*direntp;		/* each entry	 */
+
+	if ( ( dir_ptr = opendir( dirname ) ) == NULL )
+		fprintf(stderr,"ls1: cannot open %s\n", dirname);
+	else
+	{
+		while ( ( direntp = readdir( dir_ptr ) ) != NULL )
+			dostat( direntp->d_name );
+		closedir(dir_ptr);
+	}
+}
+
+void dostat( char *filename )
+{
+	struct stat info;
+
+	if ( stat(filename, &info) == -1 )		/* cannot stat	 */
+		perror( filename );			/* say why	 */
+	else					/* else show info	 */
+		show_file_info( filename, &info );
+}
+
+void show_file_info( char *filename, struct stat *info_p )
+/*
+ * display the info about 'filename'.  The info is stored in struct at *info_p
+ */
+{
+	char	*uid_to_name(), *ctime(), *gid_to_name(), *filemode();
+	void	mode_to_letters();
+        char    modestr[11];
+
+	mode_to_letters( info_p->st_mode, modestr );
+
+	printf( "%s"    , modestr );
+	printf( "%4d "  , (int) info_p->st_nlink);	
+	printf( "%-8s " , uid_to_name(info_p->st_uid) );
+	printf( "%-8s " , gid_to_name(info_p->st_gid) );
+	printf( "%8ld " , (long)info_p->st_size);
+	printf( "%.12s ", 4+ctime(&info_p->st_mtime));
+	printf( "%s\n"  , filename );
+
+}
+
+/*
+ * utility functions
+ */
+
+/*
+ * This function takes a mode value and a char array
+ * and puts into the char array the file type and the 
+ * nine letters that correspond to the bits in mode.
+ * NOTE: It does not code setuid, setgid, and sticky
+ * codes
+ */
+void mode_to_letters( int mode, char str[] )
+{
+    strcpy( str, "----------" );           /* default=no perms */
+
+    if ( S_ISDIR(mode) )  str[0] = 'd';    /* directory?       */
+    if ( S_ISCHR(mode) )  str[0] = 'c';    /* char devices     */
+    if ( S_ISBLK(mode) )  str[0] = 'b';    /* block device     */
+
+    if ( mode & S_IRUSR ) str[1] = 'r';    /* 3 bits for user  */
+    if ( mode & S_IWUSR ) str[2] = 'w';
+    if ( mode & S_IXUSR ) str[3] = 'x';
+
+    if ( mode & S_IRGRP ) str[4] = 'r';    /* 3 bits for group */
+    if ( mode & S_IWGRP ) str[5] = 'w';
+    if ( mode & S_IXGRP ) str[6] = 'x';
+
+    if ( mode & S_IROTH ) str[7] = 'r';    /* 3 bits for other */
+    if ( mode & S_IWOTH ) str[8] = 'w';
+    if ( mode & S_IXOTH ) str[9] = 'x';
+}
+
+#include	<pwd.h>
+
+char *uid_to_name( uid_t uid )
+/* 
+ *	returns pointer to username associated with uid, uses getpw()
+ */	
+{
+	struct	passwd *getpwuid(), *pw_ptr;
+	static  char numstr[10];
+
+	if ( ( pw_ptr = getpwuid( uid ) ) == NULL ){
+		sprintf(numstr,"%d", uid);
+		return numstr;
+	}
+	else
+		return pw_ptr->pw_name ;
+}
+
+#include	<grp.h>
+
+char *gid_to_name( gid_t gid )
+/*
+ *	returns pointer to group number gid. used getgrgid(3)
+ */
+{
+	struct group *getgrgid(), *grp_ptr;
+	static  char numstr[10];
+
+	if ( ( grp_ptr = getgrgid(gid) ) == NULL ){
+		sprintf(numstr,"%d", gid);
+		return numstr;
+	}
+	else
+		return grp_ptr->gr_name;
+}

+ 86 - 0
lab04/ls3.c

@@ -0,0 +1,86 @@
+/* ls3.c
+ *	purpose  list contents of directory or directories
+ *	action   if no args, use .  else list files in args
+ *	note     uses stat and pwd.h and grp.h 
+ *	BUG: try ls3 /tmp  
+ */
+#include	<stdio.h>
+#include	<sys/types.h>
+#include	<dirent.h>
+#include	<sys/stat.h>
+#include	<string.h>
+#include	<stdlib.h>
+
+#include	"mode_to_letters.h"
+#include	"gid_to_name.h"
+#include	"show_file_info.h"
+#include	"uid_to_name.h"
+
+void do_ls(char[]);
+void dostat(char *, char *);
+
+int main(int ac, char *av[])
+{
+	if ( ac == 1 )
+		do_ls( "." );
+	else
+		while ( --ac ){
+			printf("%s:\n", *++av );
+			do_ls( *av );
+		}
+}
+
+void do_ls( char dirname[] )
+/*
+ * List files in directory called dirname
+ */
+{
+    DIR *dir_ptr;         // Directory pointer
+    struct dirent *direntp;  // Each entry in directory
+
+    if ( (dir_ptr = opendir(dirname)) == NULL )   // Open directory
+    {
+        fprintf(stderr, "ls3: cannot open %s\n", dirname);
+    }
+    else
+    {
+        // Read each entry in the directory
+        while ( (direntp = readdir(dir_ptr)) != NULL )
+        {
+            // Skip . and .. directories
+            if ( strcmp(direntp->d_name, ".") == 0 || strcmp(direntp->d_name, "..") == 0 )
+                continue;
+
+            // Construct the full path
+            char *full_path = (char *)malloc(strlen(dirname) + strlen(direntp->d_name) + 2);  // +2 for '/' and '\0'
+            if (!full_path) {
+                fprintf(stderr, "Memory allocation error\n");
+                closedir(dir_ptr);
+                return;
+            }
+
+            // Concatenate the directory path and file name
+            if (dirname[strlen(dirname) - 1] == '/')  // If dirname ends with '/', just concatenate
+                sprintf(full_path, "%s%s", dirname, direntp->d_name);
+            else  // If dirname doesn't end with '/', add a '/'
+                sprintf(full_path, "%s/%s", dirname, direntp->d_name);
+
+            // Call dostat to display file info
+            dostat(full_path, direntp->d_name);
+
+            // Free the allocated memory for full_path
+            free(full_path);
+        }
+        closedir(dir_ptr);
+    }
+}
+
+void dostat( char *full_path, char *filename )
+{
+    struct stat info;
+
+    if ( stat(full_path, &info) == -1 )  // Cannot stat file
+        perror(filename);  // Show error
+    else  // Show file info
+        show_file_info(filename, &info);
+}

+ 23 - 0
lab04/mode_to_letters.c

@@ -0,0 +1,23 @@
+#include	<sys/stat.h>
+#include	<string.h>
+
+void mode_to_letters( int mode, char str[] )
+{
+    strcpy( str, "----------" );           /* default=no perms */
+
+    if ( S_ISDIR(mode) )  str[0] = 'd';    /* directory?       */
+    if ( S_ISCHR(mode) )  str[0] = 'c';    /* char devices     */
+    if ( S_ISBLK(mode) )  str[0] = 'b';    /* block device     */
+
+    if ( mode & S_IRUSR ) str[1] = 'r';    /* 3 bits for user  */
+    if ( mode & S_IWUSR ) str[2] = 'w';
+    if ( mode & S_IXUSR ) str[3] = 'x';
+
+    if ( mode & S_IRGRP ) str[4] = 'r';    /* 3 bits for group */
+    if ( mode & S_IWGRP ) str[5] = 'w';
+    if ( mode & S_IXGRP ) str[6] = 'x';
+
+    if ( mode & S_IROTH ) str[7] = 'r';    /* 3 bits for other */
+    if ( mode & S_IWOTH ) str[8] = 'w';
+    if ( mode & S_IXOTH ) str[9] = 'x';
+}

+ 6 - 0
lab04/mode_to_letters.h

@@ -0,0 +1,6 @@
+#ifndef mode_to_letters_H
+#define mode_to_letters_H
+
+void mode_to_letters( int , char [] );
+
+#endif

+ 30 - 0
lab04/sample-getgrouplist.c

@@ -0,0 +1,30 @@
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include <sys/types.h>
+#include <grp.h>
+
+void main()
+{
+	gid_t  rgid, egid, sgid, *groups;
+	struct group *grp;
+	int num = 100, retval;
+	
+	if( getresgid(&rgid, &egid, &sgid) == -1 )
+	{
+		printf("Error\n");
+		exit(1);
+	}
+	
+	printf("%d %d %d\n", rgid, egid, sgid);
+
+	if( (retval = getgrouplist( "hessamla", rgid, groups, &num)) <= num ){
+		printf("Number of groups: %d\n", num);
+		while ( retval--){
+			printf("%d\n", groups[retval]);
+		}
+	}
+	return;	
+}

+ 24 - 0
lab04/show_file_info.c

@@ -0,0 +1,24 @@
+#include	<stdio.h>
+#include	<sys/stat.h>
+#include	"show_file_info.h"
+
+void show_file_info( char *filename, struct stat *info_p )
+/*
+ * display the info about 'filename'.  The info is stored in struct at *info_p
+ */
+{
+        char    *uid_to_name(), *ctime(), *gid_to_name(), *filemode();
+        void    mode_to_letters();
+        char    modestr[11];
+
+        mode_to_letters( info_p->st_mode, modestr );
+
+        printf( "%s"    , modestr );
+        printf( "%4d "  , (int) info_p->st_nlink);
+        printf( "%-8s " , uid_to_name(info_p->st_uid) );
+        printf( "%-8s " , gid_to_name(info_p->st_gid) );
+        printf( "%8ld " , (long)info_p->st_size);
+        printf( "%.12s ", 4+ctime(&info_p->st_mtime));
+        printf( "%s\n"  , filename );
+
+}

+ 6 - 0
lab04/show_file_info.h

@@ -0,0 +1,6 @@
+#ifndef	show_file_info_H
+#define	show_file_info_H
+
+void show_file_info( char *, struct stat *);
+
+#endif

二進制
lab04/submission.zip


+ 19 - 0
lab04/uid_to_name.c

@@ -0,0 +1,19 @@
+#include        <pwd.h>
+#include	<stddef.h>
+#include	<stdio.h>
+
+char *uid_to_name( uid_t uid )
+/*
+ *      returns pointer to username associated with uid, uses getpw()
+ */
+{
+        struct  passwd *getpwuid(), *pw_ptr;
+        static  char numstr[10];
+
+        if ( ( pw_ptr = getpwuid( uid ) ) == NULL ){
+                sprintf(numstr,"%d", uid);
+                return numstr;
+        }
+        else
+                return pw_ptr->pw_name ;
+}

+ 6 - 0
lab04/uid_to_name.h

@@ -0,0 +1,6 @@
+#ifndef	uid_to_name_H
+#define	uid_to_name_h
+
+char *uid_to_name( uid_t );
+
+#endif

+ 1 - 0
lab05/.~lock.Lab05_text.docx#

@@ -0,0 +1 @@
+,stephen,E5470,11.03.2025 16:45,file:///home/stephen/.config/libreoffice/4;

二進制
lab05/Lab05.pdf


二進制
lab05/Lab05_text.docx


+ 7 - 0
lab05/Makefile

@@ -0,0 +1,7 @@
+all: spwd
+
+clean:
+	rm -f spwd
+
+spwd: spwd.c
+	gcc -o spwd spwd.c

+ 1 - 0
lab05/demodir.txt

@@ -0,0 +1 @@
+mkdir demodir; cd demodir; touch a; mkdir c; cd c; touch d1; touch d2

+ 77 - 0
lab05/spwd.c

@@ -0,0 +1,77 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <string.h>
+#include <unistd.h>
+
+ino_t get_inode(char *);
+void printpathto(ino_t);
+void inum_to_name(ino_t, char *, int);
+
+int main() {
+    printpathto(get_inode(".")); /* Print path to current directory */
+    putchar('\n');               /* Newline after path */
+    return 0;
+}
+
+void printpathto(ino_t this_inode) {
+    ino_t parent_inode;
+    char its_name[BUFSIZ];
+
+    parent_inode = get_inode("..");
+
+    if (this_inode == parent_inode) { 
+        /* Base case: we are at the root directory */
+        printf("/");
+        return;
+    }
+
+    chdir("..");  /* Move up one directory */
+    inum_to_name(this_inode, its_name, BUFSIZ); /* Get directory name */
+
+    printpathto(parent_inode); /* Recursive call */
+
+    /* Ensure correct formatting: No extra slash */
+    if (strcmp(its_name, "/") != 0) {
+        if (parent_inode != this_inode) { /* Avoid leading double slash */
+            printf("%s%s", (parent_inode == get_inode(".")) ? "" : "/", its_name);
+        }
+    }
+}
+
+void inum_to_name(ino_t inode_to_find, char *namebuf, int buflen) {
+    DIR *dir_ptr;
+    struct dirent *direntp;
+
+    dir_ptr = opendir(".");
+    if (dir_ptr == NULL) {
+        perror("opendir");
+        exit(1);
+    }
+
+    while ((direntp = readdir(dir_ptr)) != NULL) {
+        if (direntp->d_ino == inode_to_find) {
+            strncpy(namebuf, direntp->d_name, buflen);
+            namebuf[buflen - 1] = '\0';  /* Ensure null termination */
+            closedir(dir_ptr);
+            return;
+        }
+    }
+
+    fprintf(stderr, "Error: inode %lu not found in directory\n", (unsigned long)inode_to_find);
+    closedir(dir_ptr);
+    exit(1);
+}
+
+ino_t get_inode(char *fname) {
+    struct stat info;
+
+    if (stat(fname, &info) == -1) {
+        fprintf(stderr, "Cannot stat ");
+        perror(fname);
+        exit(1);
+    }
+    return info.st_ino;
+}

二進制
lab06/ECE28200 Lab06.docx


+ 7 - 0
lab06/Makefile

@@ -0,0 +1,7 @@
+all: lockingappend
+
+clean:
+	rm -f lockingappend
+
+spwd: lockingappend.c
+	gcc -o lockingappend lockingappend.c

+ 65 - 0
lab06/lockingappend.c

@@ -0,0 +1,65 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#define MAX_ATTEMPTS 5	// Maximum retry attempts
+
+int main(int argc, char *argv[]) {
+	if (argc < 3) {
+		fprintf(stderr, "Usage: %s <target_file> \"text to append\"\n", argv[0]);
+		return 1;
+	}
+
+	char *target_file = argv[1];
+	char *text_to_append = argv[2];
+	char lock_file[256];
+
+	// Generate lock file name
+	snprintf(lock_file, sizeof(lock_file), "%s.LCK", target_file);
+
+	// Check if the target file exists; if not, create it
+	struct stat buffer;
+	if (stat(target_file, &buffer) != 0) {
+		// File does not exist, create it
+		printf("Target file does not exist. Creating %s...\n", target_file);
+		FILE *file = fopen(target_file, "w");
+		if (!file) {
+			perror("Error creating file");
+			return 1;
+		}
+		fclose(file);
+	}
+
+	int attempts = 0;
+
+	while (attempts < MAX_ATTEMPTS) {
+		if (link(target_file, lock_file) == 0) {
+			// Link created successfully
+			printf("Lock acquired: %s\n", lock_file);
+
+			FILE *file = fopen(target_file, "a");
+			if (file) {
+				fprintf(file, "%s\n", text_to_append);
+				fclose(file);
+				printf("Text appended to %s\n", target_file);
+			} else {
+				perror("fopen");
+			}
+
+			// used for debugging
+			// sleep(5);
+			unlink(lock_file);
+			// Remove the lock
+			printf("Lock released: %s\n", lock_file);
+			return 0;
+		} else {
+			perror("link");
+			sleep(1);
+			attempts++;
+		}
+	}
+
+	printf("Failed to acquire lock after %d attempts.\n", MAX_ATTEMPTS);
+	return 1;
+}

二進制
lab07/Lab07.docx


+ 43 - 0
lab07/Makefile

@@ -0,0 +1,43 @@
+#
+# Makefile for Chapter 06
+#
+# Type  make    to compile all the programs
+# in the chapter 
+#
+all: play_again0 play_again1 play_again2 play_again3 play_again3a play_again3b play_again4 \
+	rotate sigdemo1 sigdemo2
+
+clean:
+	rm -f play_again0 play_again1 play_again2 play_again3 play_again3a play_again3b play_again4 \
+		rotate sigdemo1 sigdemo2
+
+play_again0: play_again0.c
+	cc -o play_again0 play_again0.c
+
+play_again1: play_again1.c
+	cc -o play_again1 play_again1.c
+
+play_again2: play_again2.c
+	cc -o play_again2 play_again2.c
+
+play_again3: play_again3.c
+	cc -o play_again3 play_again3.c
+
+play_again3a: play_again3a.c
+	cc -o play_again3a play_again3a.c
+
+play_again3b: play_again3b.c
+	cc -o play_again3b play_again3b.c
+
+play_again4: play_again4.c
+	cc -o play_again4 play_again4.c
+
+rotate: rotate.c
+	cc -o rotate rotate.c
+
+sigdemo1: sigdemo1.c
+	cc -o sigdemo1 sigdemo1.c
+
+sigdemo2: sigdemo2.c
+	cc -o sigdemo2 sigdemo2.c
+

+ 38 - 0
lab07/play_again0.c

@@ -0,0 +1,38 @@
+/* play_again0.c
+ *	purpose: ask if user wants another transaction
+ *	 method: ask a question, wait for yes/no answer
+ *	returns: 0=>yes, 1=>no
+ *	 better: eliminate need to press return 
+ */
+#include	<stdio.h>
+#include	<termios.h>
+
+#define	QUESTION	"Do you want another transaction"
+
+int get_response( char * );
+
+int main()
+{
+	int	response;
+
+	response = get_response(QUESTION);	/* get some answer	*/
+	return response;
+}
+int get_response(char *question)
+/*
+ * purpose: ask a question and wait for a y/n answer
+ *  method: use getchar and ignore non y/n answers
+ * returns: 0=>yes, 1=>no
+ */
+{
+	printf("%s (y/n)?", question);
+	while(1){
+		switch( getchar() ){
+			case 'y': 
+			case 'Y': return 0;
+			case 'n': 
+			case 'N': 
+			case EOF: return 1;
+		}
+	}
+}

+ 67 - 0
lab07/play_again1.c

@@ -0,0 +1,67 @@
+/* play_again1.c
+ *	purpose: ask if user wants another transaction
+ *	 method: set tty into char-by-char mode, read char, return result
+ *	returns: 0=>yes, 1=>no
+ *	 better: do no echo inappropriate input
+ */
+#include	<stdio.h>
+#include	<termios.h>
+
+#define	QUESTION	"Do you want another transaction"
+
+main()
+{
+	int	response;
+
+	tty_mode(0);				/* save tty mode	*/
+	set_crmode();				/* set chr-by-chr mode	*/
+	response = get_response(QUESTION);	/* get some answer	*/
+	tty_mode(1);				/* restore tty mode	*/
+	return response;
+}
+int get_response(char *question)
+/*
+ * purpose: ask a question and wait for a y/n answer
+ *  method: use getchar and complain about non y/n answers
+ * returns: 0=>yes, 1=>no
+ */
+{
+	int input;
+	printf("%s (y/n)?", question);
+	while(1){
+		switch( input = getchar() ){
+			case 'y': 
+			case 'Y': return 0;
+			case 'n': 
+			case 'N': 
+			case EOF: return 1;
+			default:
+				printf("\ncannot understand %c, ", input);
+				printf("Please type y or no\n");
+		}
+	}
+}
+
+set_crmode()
+/* 
+ * purpose: put file descriptor 0 (i.e. stdin) into chr-by-chr mode
+ *  method: use bits in termios
+ */
+{
+	struct	termios	ttystate;
+
+	tcgetattr( 0, &ttystate);		/* read curr. setting	*/
+	ttystate.c_lflag        &= ~ICANON;	/* no buffering		*/
+	ttystate.c_cc[VMIN]     =  1;		/* get 1 char at a time	*/
+	tcsetattr( 0 , TCSANOW, &ttystate);	/* install settings	*/
+}
+
+/* how == 0 => save current mode,  how == 1 => restore mode */
+tty_mode(int how)
+{
+	static struct termios original_mode;
+	if ( how == 0 )
+		tcgetattr(0, &original_mode);
+	else
+		return tcsetattr(0, TCSANOW, &original_mode); 
+}

+ 66 - 0
lab07/play_again2.c

@@ -0,0 +1,66 @@
+/* play_again2.c
+ *	purpose: ask if user wants another transaction
+ *	 method: set tty into char-by-char mode and no-echo mode
+ *		 read char, return result
+ *	returns: 0=>yes, 1=>no
+ *	 better: timeout if user walks away
+ *	
+ */
+#include	<stdio.h>
+#include	<termios.h>
+
+#define	QUESTION	"Do you want another transaction"
+
+main()
+{
+	int	response;
+
+	tty_mode(0);				/* save mode */
+	set_cr_noecho_mode();			/* set -icanon, -echo	*/
+	response = get_response(QUESTION);	/* get some answer	*/
+	tty_mode(1);				/* restore tty state	*/
+	return response;
+}
+
+int get_response(char *question)
+/*
+ * purpose: ask a question and wait for a y/n answer
+ *  method: use getchar and ignore non y/n answers
+ * returns: 0=>yes, 1=>no
+ */
+{
+	printf("%s (y/n)?", question);
+	while(1){
+		switch( getchar() ){
+			case 'y': 
+			case 'Y': return 0;
+			case 'n': 
+			case 'N': 
+			case EOF: return 1;
+		}
+	}
+}
+set_cr_noecho_mode()
+/* 
+ * purpose: put file descriptor 0 into chr-by-chr mode and noecho mode
+ *  method: use bits in termios
+ */
+{
+	struct	termios	ttystate;
+
+	tcgetattr( 0, &ttystate);		/* read curr. setting	*/
+	ttystate.c_lflag    	&= ~ICANON;	/* no buffering		*/
+	ttystate.c_lflag    	&= ~ECHO;	/* no echo either	*/
+	ttystate.c_cc[VMIN]  	=  1;		/* get 1 char at a time	*/
+	tcsetattr( 0 , TCSANOW, &ttystate);	/* install settings	*/
+}
+
+/* how == 0 => save current mode,  how == 1 => restore mode */
+tty_mode(int how)
+{
+	static struct termios original_mode;
+	if ( how == 0 )
+		tcgetattr(0, &original_mode);
+	else
+		return tcsetattr(0, TCSANOW, &original_mode); 
+}

+ 108 - 0
lab07/play_again3.c

@@ -0,0 +1,108 @@
+/* play_again3.c
+ *	purpose: ask if user wants another transaction
+ *	 method: set tty into chr-by-chr, no-echo mode
+ *		 set tty into no-delay mode
+ *		 read char, return result
+ *	returns: 0=>yes, 1=>no, 2=>timeout
+ *	 better: reset terminal mode on Interrupt
+ */
+#include	<stdio.h>
+#include	<termios.h>
+#include	<fcntl.h>
+#include	<string.h>
+
+#define	ASK		"Do you want another transaction"
+#define	TRIES	   3	                                   /* max tries */
+#define SLEEPTIME  2                                       /* time per try */
+#define	BEEP       putchar('\a')                           /* alert user */
+
+main()
+{
+	int	response;
+
+	tty_mode(0);				/* save current mode	*/
+	set_cr_noecho_mode();			/* set -icanon, -echo	*/
+	set_nodelay_mode();			/* noinput => EOF	*/
+	response = get_response(ASK, TRIES);	/* get some answer	*/
+	tty_mode(1);				/* restore orig mode	*/
+	return response;
+}
+get_response( char *question , int maxtries)
+/*
+ * purpose: ask a question and wait for a y/n answer or maxtries
+ *  method: use getchar and complain about non-y/n input
+ * returns: 0=>yes, 1=>no, 2=>timeout
+ */
+{
+	int	input;
+
+	printf("%s (y/n)?", question);			/* ask		*/
+	fflush(stdout);					/* force output	*/
+	while ( 1 ){
+		sleep(SLEEPTIME);			/* wait a bit	*/
+		input = tolower(get_ok_char());        	/* get next chr */
+		if ( input == 'y' )
+			return 0;
+		if ( input == 'n' )
+			return 1;
+		if ( maxtries-- == 0 )			/* outatime?	*/
+			return 2;			/* sayso	*/
+		BEEP;
+	}
+}
+/*
+ *  skip over non-legal chars and return y,Y,n,N or EOF
+ */
+get_ok_char()
+{
+	int c;
+	while( ( c = getchar() ) != EOF && strchr("yYnN",c) == NULL )
+		;
+	return c;
+}
+
+set_cr_noecho_mode()
+/* 
+ * purpose: put file descriptor 0 into chr-by-chr mode and noecho mode
+ *  method: use bits in termios
+ */
+{
+	struct	termios	ttystate;
+
+	tcgetattr( 0, &ttystate);		/* read curr. setting	*/
+	ttystate.c_lflag    	&= ~ICANON;	/* no buffering		*/
+	ttystate.c_lflag    	&= ~ECHO;	/* no echo either	*/
+	ttystate.c_cc[VMIN]  	=  1;		/* get 1 char at a time	*/
+	tcsetattr( 0 , TCSANOW, &ttystate);	/* install settings	*/
+}
+
+set_nodelay_mode()
+/*
+ * purpose: put file descriptor 0 into no-delay mode
+ *  method: use fcntl to set bits
+ *   notes: tcsetattr() will do something similar, but it is complicated
+ */
+{
+	int	termflags;
+
+	termflags = fcntl(0, F_GETFL);		/* read curr. settings	*/
+	termflags |= O_NDELAY;			/* flip on nodelay bit	*/
+	fcntl(0, F_SETFL, termflags);		/* and install 'em	*/
+}
+
+/* how == 0 => save current mode,  how == 1 => restore mode */
+/* this version handles termios and fcntl flags             */
+
+tty_mode(int how)
+{
+	static struct termios original_mode;
+	static int            original_flags;
+	if ( how == 0 ){
+		tcgetattr(0, &original_mode);
+		original_flags = fcntl(0, F_GETFL);
+	}
+	else {
+		tcsetattr(0, TCSANOW, &original_mode); 
+		fcntl( 0, F_SETFL, original_flags);	
+	}
+}

+ 114 - 0
lab07/play_again3a.c

@@ -0,0 +1,114 @@
+/* play_again3.c
+ *	purpose: ask if user wants another transaction
+ *	 method: set tty into chr-by-chr, no-echo mode
+ *		 set tty into no-delay mode
+ *		 read char, return result
+ *	returns: 0=>yes, 1=>no, 2=>timeout
+ *	 better: reset terminal mode on Interrupt
+ */
+#include	<stdio.h>
+#include	<termios.h>
+#include	<fcntl.h>
+#include	<string.h>
+#include	<signal.h>
+
+#define	ASK		"Do you want another transaction"
+#define	TRIES	   3	                                   /* max tries */
+#define SLEEPTIME  2                                       /* time per try */
+#define	BEEP       putchar('\a')                           /* alert user */
+
+main()
+{
+	int	response;
+
+    signal( SIGINT, SIG_IGN );
+    signal( SIGTSTP, SIG_IGN );
+    signal( SIGQUIT, SIG_IGN );
+
+	tty_mode(0);				/* save current mode	*/
+	set_cr_noecho_mode();			/* set -icanon, -echo	*/
+	set_nodelay_mode();			/* noinput => EOF	*/
+	response = get_response(ASK, TRIES);	/* get some answer	*/
+	tty_mode(1);				/* restore orig mode	*/
+	return response;
+}
+get_response( char *question , int maxtries)
+/*
+ * purpose: ask a question and wait for a y/n answer or maxtries
+ *  method: use getchar and complain about non-y/n input
+ * returns: 0=>yes, 1=>no, 2=>timeout
+ */
+{
+	int	input;
+
+	printf("%s (y/n)?", question);			/* ask		*/
+	fflush(stdout);					/* force output	*/
+	while ( 1 ){
+		sleep(SLEEPTIME);			/* wait a bit	*/
+		input = tolower(get_ok_char());        	/* get next chr */
+		if ( input == 'y' )
+			return 0;
+		if ( input == 'n' )
+			return 1;
+		if ( maxtries-- == 0 )			/* outatime?	*/
+			return 2;			/* sayso	*/
+		BEEP;
+	}
+}
+/*
+ *  skip over non-legal chars and return y,Y,n,N or EOF
+ */
+get_ok_char()
+{
+	int c;
+	while( ( c = getchar() ) != EOF && strchr("yYnN",c) == NULL )
+		;
+	return c;
+}
+
+set_cr_noecho_mode()
+/* 
+ * purpose: put file descriptor 0 into chr-by-chr mode and noecho mode
+ *  method: use bits in termios
+ */
+{
+	struct	termios	ttystate;
+
+	tcgetattr( 0, &ttystate);		/* read curr. setting	*/
+	ttystate.c_lflag    	&= ~ICANON;	/* no buffering		*/
+	ttystate.c_lflag    	&= ~ECHO;	/* no echo either	*/
+	ttystate.c_cc[VMIN]  	=  1;		/* get 1 char at a time	*/
+	tcsetattr( 0 , TCSANOW, &ttystate);	/* install settings	*/
+}
+
+set_nodelay_mode()
+/*
+ * purpose: put file descriptor 0 into no-delay mode
+ *  method: use fcntl to set bits
+ *   notes: tcsetattr() will do something similar, but it is complicated
+ */
+{
+	int	termflags;
+
+	termflags = fcntl(0, F_GETFL);		/* read curr. settings	*/
+	termflags |= O_NDELAY;			/* flip on nodelay bit	*/
+	fcntl(0, F_SETFL, termflags);		/* and install 'em	*/
+}
+
+/* how == 0 => save current mode,  how == 1 => restore mode */
+/* this version handles termios and fcntl flags             */
+
+tty_mode(int how)
+{
+	static struct termios original_mode;
+	static int            original_flags;
+	if ( how == 0 ){
+		tcgetattr(0, &original_mode);
+		original_flags = fcntl(0, F_GETFL);
+	}
+	else {
+		tcsetattr(0, TCSANOW, &original_mode); 
+		fcntl( 0, F_SETFL, original_flags);	
+	}
+}
+

+ 120 - 0
lab07/play_again3b.c

@@ -0,0 +1,120 @@
+/* play_again3.c
+ *	purpose: ask if user wants another transaction
+ *	 method: set tty into chr-by-chr, no-echo mode
+ *		 set tty into no-delay mode
+ *		 read char, return result
+ *	returns: 0=>yes, 1=>no, 2=>timeout
+ *	 better: reset terminal mode on Interrupt
+ */
+#include	<stdio.h>
+#include	<termios.h>
+#include	<fcntl.h>
+#include	<string.h>
+#include	<signal.h>
+
+#define	ASK		"Do you want another transaction"
+#define	TRIES	   3	                                   /* max tries */
+#define SLEEPTIME  2                                       /* time per try */
+#define	BEEP       putchar('\a')                           /* alert user */
+
+/* Signal handler to restore terminal settings */
+void handle_signal(int sig) {
+    tty_mode(1);  // Restore terminal mode
+    exit(2);
+}
+
+main()
+{
+	int	response;
+
+    signal( SIGINT, handle_signal );
+    signal( SIGTSTP, handle_signal );
+    signal( SIGQUIT, handle_signal );
+
+	tty_mode(0);				/* save current mode	*/
+	set_cr_noecho_mode();			/* set -icanon, -echo	*/
+	set_nodelay_mode();			/* noinput => EOF	*/
+	response = get_response(ASK, TRIES);	/* get some answer	*/
+	tty_mode(1);				/* restore orig mode	*/
+	return response;
+}
+get_response( char *question , int maxtries)
+/*
+ * purpose: ask a question and wait for a y/n answer or maxtries
+ *  method: use getchar and complain about non-y/n input
+ * returns: 0=>yes, 1=>no, 2=>timeout
+ */
+{
+	int	input;
+
+	printf("%s (y/n)?", question);			/* ask		*/
+	fflush(stdout);					/* force output	*/
+	while ( 1 ){
+		sleep(SLEEPTIME);			/* wait a bit	*/
+		input = tolower(get_ok_char());        	/* get next chr */
+		if ( input == 'y' )
+			return 0;
+		if ( input == 'n' )
+			return 1;
+		if ( maxtries-- == 0 )			/* outatime?	*/
+			return 2;			/* sayso	*/
+		BEEP;
+	}
+}
+/*
+ *  skip over non-legal chars and return y,Y,n,N or EOF
+ */
+get_ok_char()
+{
+	int c;
+	while( ( c = getchar() ) != EOF && strchr("yYnN",c) == NULL )
+		;
+	return c;
+}
+
+set_cr_noecho_mode()
+/* 
+ * purpose: put file descriptor 0 into chr-by-chr mode and noecho mode
+ *  method: use bits in termios
+ */
+{
+	struct	termios	ttystate;
+
+	tcgetattr( 0, &ttystate);		/* read curr. setting	*/
+	ttystate.c_lflag    	&= ~ICANON;	/* no buffering		*/
+	ttystate.c_lflag    	&= ~ECHO;	/* no echo either	*/
+	ttystate.c_cc[VMIN]  	=  1;		/* get 1 char at a time	*/
+	tcsetattr( 0 , TCSANOW, &ttystate);	/* install settings	*/
+}
+
+set_nodelay_mode()
+/*
+ * purpose: put file descriptor 0 into no-delay mode
+ *  method: use fcntl to set bits
+ *   notes: tcsetattr() will do something similar, but it is complicated
+ */
+{
+	int	termflags;
+
+	termflags = fcntl(0, F_GETFL);		/* read curr. settings	*/
+	termflags |= O_NDELAY;			/* flip on nodelay bit	*/
+	fcntl(0, F_SETFL, termflags);		/* and install 'em	*/
+}
+
+/* how == 0 => save current mode,  how == 1 => restore mode */
+/* this version handles termios and fcntl flags             */
+
+tty_mode(int how)
+{
+	static struct termios original_mode;
+	static int            original_flags;
+	if ( how == 0 ){
+		tcgetattr(0, &original_mode);
+		original_flags = fcntl(0, F_GETFL);
+	}
+	else {
+		tcsetattr(0, TCSANOW, &original_mode); 
+		fcntl( 0, F_SETFL, original_flags);	
+	}
+}
+

+ 127 - 0
lab07/play_again4.c

@@ -0,0 +1,127 @@
+/* play_again4.c
+ *	purpose: ask if user wants another transaction
+ *	 method: set tty into chr-by-chr, no-echo mode
+ *		 set tty into no-delay mode
+ *		 read char, return result
+ *		 resets terminal modes on SIGINT, ignores SIGQUIT
+ *	returns: 0=>yes, 1=>no, 2=>timeout
+ *	 better: reset terminal mode on Interrupt
+ */
+#include	<stdio.h>
+#include	<termios.h>
+#include	<fcntl.h>
+#include	<string.h>
+#include	<signal.h>
+
+#define	ASK		"Do you want another transaction"
+#define	TRIES	   3	                                   /* max tries */
+#define SLEEPTIME  2                                       /* time per try */
+#define	BEEP       putchar('\a')                           /* alert user */
+
+
+main()
+{
+	int	response;
+	void	ctrl_c_handler(int);
+
+	tty_mode(0);				/* save current mode	*/
+	set_cr_noecho_mode();			/* set -icanon, -echo	*/
+	set_nodelay_mode();			/* noinput => EOF	*/
+	signal( SIGINT, ctrl_c_handler );	/* handle INT		*/
+	signal( SIGQUIT, SIG_IGN );		/* ignore QUIT signals	*/
+	response = get_response(ASK, TRIES);	/* get some answer	*/
+	tty_mode(1);				/* reset orig mode	*/
+	return response;
+}
+get_response( char *question , int maxtries)
+/*
+ * purpose: ask a question and wait for a y/n answer or timeout
+ *  method: use getchar and complain about non-y/n input
+ * returns: 0=>yes, 1=>no
+ */
+{
+	int	input;
+
+	printf("%s (y/n)?", question);			/* ask		*/
+	fflush(stdout);					/* force output	*/
+	while ( 1 ){
+		sleep(SLEEPTIME);			/* wait a bit	*/
+		input = tolower(get_ok_char());         /* get next chr */
+		if ( input == 'y' )
+			return 0;
+		if ( input == 'n' )
+			return 1;
+		if ( maxtries-- == 0 )			/* outatime?	*/
+			return 2;			/* sayso	*/
+		BEEP;
+	}
+}
+
+/*
+ *  skip over non-legal chars and return y,Y,n,N or EOF
+ */
+get_ok_char()
+{
+	int c;
+	while( ( c = getchar() ) != EOF && strchr("yYnN",c) == NULL )
+		;
+	return c;
+}
+set_cr_noecho_mode()
+/* 
+ * purpose: put file descriptor 0 into chr-by-chr mode and noecho mode
+ *  method: use bits in termios
+ */
+{
+	struct	termios	ttystate;
+
+	tcgetattr( 0, &ttystate);		/* read curr. setting	*/
+	ttystate.c_lflag    	&= ~ICANON;	/* no buffering		*/
+	ttystate.c_lflag    	&= ~ECHO;	/* no echo either	*/
+	ttystate.c_cc[VMIN]  	=  1;		/* get 1 char at a time	*/
+	tcsetattr( 0 , TCSANOW, &ttystate);	/* install settings	*/
+}
+
+set_nodelay_mode()
+/*
+ * purpose: put file descriptor 0 into no-delay mode
+ *  method: use fcntl to set bits
+ *   notes: tcsetattr() will do something similar, but it is complicated
+ */
+{
+	int	termflags;
+
+	termflags = fcntl(0, F_GETFL);		/* read curr. settings	*/
+	termflags |= O_NDELAY;			/* flip on nodelay bit	*/
+	fcntl(0, F_SETFL, termflags);		/* and install 'em	*/
+}
+
+/* how == 0 => save current mode,  how == 1 => restore mode */
+/* this version handles termios and fcntl flags             */
+
+tty_mode(int how)
+{
+	static struct termios original_mode;
+	static int            original_flags;
+	static int            stored = 0;
+
+	if ( how == 0 ){
+		tcgetattr(0, &original_mode);
+		original_flags = fcntl(0, F_GETFL);
+		stored = 1;
+	}
+	else if ( stored ) {
+		tcsetattr(0, TCSANOW, &original_mode); 
+		fcntl( 0, F_SETFL, original_flags);	
+	}
+}
+
+void ctrl_c_handler(int signum)
+/*
+ * purpose: called if SIGINT is detected
+ *  action: reset tty and scram
+ */
+{
+	tty_mode(1);
+	exit(2);
+}

+ 149 - 0
lab07/play_again_extended.c

@@ -0,0 +1,149 @@
+/* play_again4.c
+ *	purpose: ask if user wants another transaction
+ *	 method: set tty into chr-by-chr, no-echo mode
+ *		 set tty into no-delay mode
+ *		 read char, return result
+ *		 resets terminal modes on SIGINT, ignores SIGQUIT
+ *	returns: 0=>yes, 1=>no, 2=>timeout
+ *	 better: reset terminal mode on Interrupt
+ */
+#include	<stdio.h>
+#include	<termios.h>
+#include	<fcntl.h>
+#include	<string.h>
+#include	<signal.h>
+#include        <time.h>
+
+#define	ASK		"Do you want another transaction"
+#define	TRIES	   3	                                   /* max tries */
+#define SLEEPTIME  2                                       /* time per try */
+#define	BEEP       putchar('\a')                           /* alert user */
+
+
+main()
+{
+	int	response;
+	void	ctrl_c_handler(int);
+
+	tty_mode(0);				/* save current mode	*/
+	set_cr_noecho_mode();			/* set -icanon, -echo	*/
+	set_nodelay_mode();			/* noinput => EOF	*/
+	signal( SIGINT, ctrl_c_handler );	/* handle INT		*/
+	signal( SIGQUIT, SIG_IGN );		/* ignore QUIT signals	*/
+	response = get_response(ASK, TRIES);	/* get some answer	*/
+	tty_mode(1);				/* reset orig mode	*/
+	return response;
+}
+get_response( char *question , int maxtries)
+/*
+ * purpose: ask a question and wait for a y/n answer or timeout
+ *  method: use getchar and complain about non-y/n input
+ * returns: 0=>yes, 1=>no
+ */
+{
+	int	input;
+
+	printf("%s (y/n)?", question);			/* ask		*/
+	fflush(stdout);					/* force output	*/
+	//while ( 1 ){
+		//sleep(SLEEPTIME);			/* wait a bit	*/
+		input = tolower(get_ok_char());         /* get next chr */
+		if ( input == 'y' )
+			return 0;
+		if ( input == 'n' )
+			return 1;
+		if ( maxtries-- == 0 )			/* outatime?	*/
+			return 2;			/* sayso	*/
+		BEEP;
+	//}
+}
+
+/*
+ *  skip over non-legal chars and return y,Y,n,N or EOF
+ */
+get_ok_char()
+{
+	int c = 0;
+	time_t keypressed_time = time(0);
+	printf("\nkeypressed time first update: %d\n", keypressed_time);
+	//while( ( c = getchar() ) != EOF && strchr("yYnN",c) == NULL ){
+	while(1){
+		if( (c=getchar()) != EOF ){ // a key is pressed{
+			
+			keypressed_time = time(0);
+			//printf("Key pressed: %x\n", c);
+			putchar(c);
+			//printf("keypressed time 2: %d\n", keypressed_time);
+		}
+		//if( strchr("yYnN", c) != NULL ){
+		//	printf("Key pressed: %c\n", c);
+		//	return c;
+		//}
+		if(keypressed_time + 3 < time(0) ){ //wait 3 seconds
+			printf("\ncurrent  time : %d\n", time(0));
+			printf("keypressed time 2: %d\n", keypressed_time);
+			return 'n';
+		} 
+	}
+		
+		;
+	return c;
+}
+set_cr_noecho_mode()
+/* 
+ * purpose: put file descriptor 0 into chr-by-chr mode and noecho mode
+ *  method: use bits in termios
+ */
+{
+	struct	termios	ttystate;
+
+	tcgetattr( 0, &ttystate);		/* read curr. setting	*/
+	ttystate.c_lflag    	&= ~ICANON;	/* no buffering		*/
+	ttystate.c_lflag    	&= ~ECHO;	/* no echo either	*/
+	ttystate.c_cc[VMIN]  	=  1;		/* get 1 char at a time	*/
+	tcsetattr( 0 , TCSANOW, &ttystate);	/* install settings	*/
+}
+
+set_nodelay_mode()
+/*
+ * purpose: put file descriptor 0 into no-delay mode
+ *  method: use fcntl to set bits
+ *   notes: tcsetattr() will do something similar, but it is complicated
+ */
+{
+	int	termflags;
+
+	termflags = fcntl(0, F_GETFL);		/* read curr. settings	*/
+	termflags |= O_NDELAY;			/* flip on nodelay bit	*/
+	fcntl(0, F_SETFL, termflags);		/* and install 'em	*/
+}
+
+/* how == 0 => save current mode,  how == 1 => restore mode */
+/* this version handles termios and fcntl flags             */
+
+tty_mode(int how)
+{
+	static struct termios original_mode;
+	static int            original_flags;
+	static int            stored = 0;
+
+	if ( how == 0 ){
+		tcgetattr(0, &original_mode);
+		original_flags = fcntl(0, F_GETFL);
+		stored = 1;
+	}
+	else if ( stored ) {
+		tcsetattr(0, TCSANOW, &original_mode); 
+		fcntl( 0, F_SETFL, original_flags);	
+	}
+}
+
+void ctrl_c_handler(int signum)
+/*
+ * purpose: called if SIGINT is detected
+ *  action: reset tty and scram
+ */
+{
+	tty_mode(1);
+	exit(2);
+}

+ 81 - 0
lab07/rotate.c

@@ -0,0 +1,81 @@
+/* rotate.c : map a->b, b->c, .. z->a
+ *   purpose: useful for showing tty modes
+ */
+
+#include	<stdio.h>
+#include	<termios.h>
+#include	<fcntl.h>
+#include	<string.h>
+#include	<signal.h>
+
+int main()
+{
+    int c;
+
+    signal( SIGINT, SIG_IGN );
+    signal( SIGTSTP, SIG_IGN );
+    signal( SIGQUIT, SIG_IGN );
+
+	tty_mode(0);				/* save current mode	*/
+	set_cr_noecho_mode();			/* set -icanon, -echo	*/
+
+
+    while ( ( c=getchar() ) != EOF ){
+        if ( c == 'Q') {
+            tty_mode(1);
+            exit(0);
+        }
+        else if ( c == 'z' )  
+            c = 'a';
+        else if (islower(c))
+            c++;
+        putchar(c);
+    }
+}
+
+
+set_cr_noecho_mode()
+/* 
+ * purpose: put file descriptor 0 into chr-by-chr mode and noecho mode
+ *  method: use bits in termios
+ */
+{
+	struct	termios	ttystate;
+
+	tcgetattr( 0, &ttystate);		/* read curr. setting	*/
+	ttystate.c_lflag    	&= ~ICANON;	/* no buffering		*/
+	ttystate.c_lflag    	&= ~ECHO;	/* no echo either	*/
+	ttystate.c_cc[VMIN]  	=  1;		/* get 1 char at a time	*/
+	tcsetattr( 0 , TCSANOW, &ttystate);	/* install settings	*/
+}
+
+set_nodelay_mode()
+/*
+ * purpose: put file descriptor 0 into no-delay mode
+ *  method: use fcntl to set bits
+ *   notes: tcsetattr() will do something similar, but it is complicated
+ */
+{
+	int	termflags;
+
+	termflags = fcntl(0, F_GETFL);		/* read curr. settings	*/
+	termflags |= O_NDELAY;			/* flip on nodelay bit	*/
+	fcntl(0, F_SETFL, termflags);		/* and install 'em	*/
+}
+
+/* how == 0 => save current mode,  how == 1 => restore mode */
+/* this version handles termios and fcntl flags             */
+
+tty_mode(int how)
+{
+	static struct termios original_mode;
+	static int            original_flags;
+	if ( how == 0 ){
+		tcgetattr(0, &original_mode);
+		original_flags = fcntl(0, F_GETFL);
+	}
+	else {
+		tcsetattr(0, TCSANOW, &original_mode); 
+		fcntl( 0, F_SETFL, original_flags);	
+	}
+}

+ 49 - 0
lab07/sigdemo1.c

@@ -0,0 +1,49 @@
+/* sigdemo1.c - shows how a signal handler works.
+ *            - run this and press Ctrl-C a few times
+ *            - counts how many times Ctrl-C is pressed and exits after a certain count
+ */
+
+#include    <stdio.h>
+#include    <signal.h>
+#include    <stdlib.h>
+#include    <unistd.h>
+
+int count = 0;  // Global variable to keep track of Ctrl-C presses
+int max_count = 16;  // The number of times Ctrl-C should be pressed before exiting
+
+void f(int signum)  /* Signal handler */
+{
+    printf("OUCH!");
+    for (int i = 0; i < count; i++) {  // Print the increasing number of exclamation points
+        printf("!");
+    }
+    printf("\n");
+
+    count++;  // increment the count
+
+    if (count >= max_count) {
+        exit(0); // exit clean after max count is reached
+    }
+}
+
+int main(int argc, char *argv[])
+{
+
+    if (argc == 2) {
+        max_count = atoi(argv[1]);  // make argv[1] to an integer
+
+    }
+
+    signal( SIGINT, f ); // do f on SIGINT
+    // ignore these
+    signal( SIGTSTP, SIG_IGN );
+    signal( SIGQUIT, SIG_IGN );
+
+    // enter a main loop
+    while (1) {
+        sleep(1);  // slow down the loop
+    }
+
+    return 0;
+}
+

+ 19 - 0
lab07/sigdemo2.c

@@ -0,0 +1,19 @@
+/* sigdemo2.c - shows how to ignore a signal
+ *            - press Ctrl-\ to kill this one
+ */
+
+#include	<stdio.h>
+#include	<signal.h>
+
+main()
+{
+	signal( SIGINT, SIG_IGN );
+
+	printf("you can't stop me!\n");
+	while( 1 )
+	{
+		sleep(1);
+		printf("haha\n");
+	}
+}
+

+ 1 - 0
lab08/.gitignore

@@ -0,0 +1 @@
+.~lock*

二進制
lab08/Chapter4 Source Code.zip


二進制
lab08/Lab08_2025.docx


+ 55 - 0
lab08/Makefile

@@ -0,0 +1,55 @@
+# Makefile for Chapter 07
+
+# List all the programs to be built here
+all: bounce1d bounce2d bounce_aio bounce_async hello1 	\
+	hello2 hello3 hello4 hello5 sigactdemo sigdemo3 \
+	sleep1 ticker_demo pong
+
+# Define a target for cleaning up
+clean:
+	rm -f bounce1d bounce2d bounce_aio bounce_async hello1 	\
+		hello2 hello3 hello4 hello5 sigactdemo sigdemo3 \
+		sleep1 ticker_demo pong
+
+# Rules for building each program
+bounce1d: bounce1d.c set_ticker.c -lcurses
+	gcc -o bounce1d bounce1d.c set_ticker.c -lcurses
+
+bounce2d: bounce2d.c set_ticker.c -lcurses
+	gcc -o bounce2d bounce2d.c set_ticker.c -lcurses
+
+bounce_aio: bounce_aio.c set_ticker.c -lrt  -lcurses
+	gcc -o bounce_aio bounce_aio.c set_ticker.c -lrt  -lcurses
+
+bounce_async: bounce_async.c set_ticker.c -lcurses
+	gcc -o bounce_async bounce_async.c set_ticker.c -lcurses
+
+hello1: hello1.c -lcurses
+	gcc -o hello1 hello1.c -lcurses
+
+hello2: hello2.c -lcurses
+	gcc -o hello2 hello2.c -lcurses
+
+hello3: hello3.c -lcurses
+	gcc -o hello3 hello3.c -lcurses
+
+hello4: hello4.c -lcurses
+	gcc -o hello4 hello4.c -lcurses
+
+hello5: hello5.c -lcurses
+	gcc -o hello5 hello5.c -lcurses
+
+sigactdemo: sigactdemo.c
+	gcc -o sigactdemo sigactdemo.c
+
+sigdemo3: sigdemo3.c
+	gcc -o sigdemo3 sigdemo3.c
+
+sleep1: sleep1.c 
+	gcc -o sleep1 sleep1.c 
+
+ticker_demo: ticker_demo.c 
+	gcc -o ticker_demo ticker_demo.c
+
+pong: pong.c set_ticker.c -lcurses
+	gcc -o pong pong.c set_ticker.c -lcurses

+ 27 - 0
lab08/bounce.h

@@ -0,0 +1,27 @@
+/* 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 ;
+
+	} ;

+ 74 - 0
lab08/bounce1d.c

@@ -0,0 +1,74 @@
+/* bounce1d.c
+ *	purpose	animation with user controlled speed and direction
+ *	note	the handler does the animation
+ *		the main program reads keyboard input
+ *	compile	cc bounce1d.c set_ticker.c -lcurses -o bounce1d
+ */
+#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;
+}

+ 130 - 0
lab08/bounce2d.c

@@ -0,0 +1,130 @@
+/*  bounce2d 1.0	
+ *	bounce a character (default is 'o') around the screen
+ *	defined by some parameters
+ *
+ *	user input: 	s slow down x component, S: slow y component
+ *		 	f speed up x component,  F: speed y component
+ *			Q quit
+ *
+ *	blocks on read, but timer tick sends SIGALRM caught by ball_move
+ *	build:   cc bounce2d.c set_ticker.c -lcurses -o bounce2d
+ */
+
+#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;
+}
+

+ 117 - 0
lab08/bounce_aio.c

@@ -0,0 +1,117 @@
+/* bounce_aio.c
+ *	purpose	animation with user control, using aio_read() etc
+ *	note	set_ticker() sends SIGALRM, handler does animation
+ *		keyboard sends SIGIO, main only calls pause()
+ *	compile cc bounce_aio.c set_ticker.c -lrt  -lcurses -o bounce_aio
+ */
+#include	<stdio.h>
+#include	<curses.h>
+#include	<signal.h>
+#include	<aio.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 dummy)
+{
+	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;
+			else if( c == '+' ){
+				delay += 10;
+				set_ticker(delay);
+			}
+			else if( c == '-' ){
+				delay -= 10;
+				set_ticker(delay);
+			}
+		}
+
+	/* place a new request */
+	aio_read(&kbcbuf);
+}
+
+void on_alarm(int dummy)
+{
+	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   */
+}

+ 83 - 0
lab08/bounce_async.c

@@ -0,0 +1,83 @@
+/* bounce_async.c
+ *	purpose	animation with user control, using O_ASYNC on fd
+ *	note	set_ticker() sends SIGALRM, handler does animation
+ *		keyboard sends SIGIO, main only calls pause()
+ *	compile	cc bounce_async.c set_ticker.c -lcurses -o bounce_async
+ */
+#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));
+}
+

+ 23 - 0
lab08/hello1.c

@@ -0,0 +1,23 @@
+/* hello1.c
+ *	purpose	 show the minimal calls needed to use curses
+ *	outline  initialize, draw stuff, wait for input, quit
+ */
+
+#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	*/
+}

+ 27 - 0
lab08/hello2.c

@@ -0,0 +1,27 @@
+/* hello2.c
+ *	purpose	 show how to use curses functions with a loop 
+ *	outline	 initialize, draw stuff, wrap up
+ */
+
+#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	*/
+}

+ 26 - 0
lab08/hello3.c

@@ -0,0 +1,26 @@
+/* hello3.c
+ *	purpose	 using refresh and sleep for animated effects
+ *	outline	 initialize, draw stuff, wrap up
+ */
+#include	<stdio.h>
+#include	<curses.h>
+
+main()
+{
+	int	i;
+
+	initscr();
+	   clear();
+	   for(i=0; i<LINES; i++ ){
+	   clear();
+		move( i, i+i );
+		if ( i%2 == 1 ) 
+			standout();
+		addstr("Hello, world");
+		if ( i%2 == 1 ) 
+			standend();
+		sleep(1);
+		refresh();
+	   }
+	endwin();
+}

+ 26 - 0
lab08/hello4.c

@@ -0,0 +1,26 @@
+/* hello4.c
+ *	purpose	show how to use erase, time, and draw for animation
+ */
+#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();
+}

+ 34 - 0
lab08/hello5.c

@@ -0,0 +1,34 @@
+/* hello5.c
+ *    purpose  bounce a message back and forth across the screen
+ *    compile  cc hello5.c -lcurses -o hello5
+ */
+#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		*/
+		usleep(100000);
+		move(ROW,pos);			/* erase string		*/
+		addstr( blank );
+		pos += dir;			/* advance position	*/
+		if ( pos >= RIGHTEDGE )		/* check for bounce	*/
+			dir = -1;
+		if ( pos <= LEFTEDGE )
+			dir = +1;
+	  }
+}

+ 194 - 0
lab08/pong.c

@@ -0,0 +1,194 @@
+#include <ncurses.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define BALL_SYMBOL "O"
+#define BORDER "#"
+#define PADDLE "||"
+
+struct Ball {
+    int px, py, dx, dy;
+};
+
+struct Paddle {
+    int px, py, length;
+};
+
+int main(void) {
+    int sleep_time = 20000;
+    int time = 0;
+    int hits = 0, misses = 0, best = 0, streak = 0, quit = 0, frame = 1, left_score = 0, right_score = 0;
+    int max_y, max_x;
+    struct Ball ball;
+    struct Paddle paddle1, paddle2;
+    int i;
+
+    system("clear");
+    initscr();
+    curs_set(0);
+    cbreak();
+    noecho();
+    nodelay(stdscr, 1);
+    start_color();
+    init_pair(1, COLOR_CYAN, COLOR_BLACK);
+    init_pair(2, COLOR_YELLOW, COLOR_BLACK);
+    init_pair(3, COLOR_GREEN, COLOR_BLACK);
+
+    getmaxyx(stdscr, max_y, max_x);
+
+    // Initialize ball
+    ball.py = max_y / 2;
+    ball.px = max_x / 2;
+    ball.dy = rand() & 1 ? 1 : -1;
+    ball.dx = rand() & 1 ? 1 : -1;
+
+    // Initialize paddles
+    paddle1.length = 6;
+    paddle1.py = (max_y / 2) - (paddle1.length / 2);
+    paddle1.px = max_x - 3;
+
+    paddle2.length = 6;
+    paddle2.py = (max_y / 2) - (paddle2.length / 2);
+    paddle2.px = 1;
+
+    // Game loop
+    while (!quit) {
+
+        getmaxyx(stdscr, max_y, max_x);
+
+        // Timer
+        if (frame % (1000000 / sleep_time) == 0) {
+            time++;
+        }
+
+        // Draw stats
+        mvprintw(0, 0, "Hits: %d  Misses: %d  Streak: %d  Best: %d  Time: %d | Score left: %d  Score right: %d | ",
+                 hits, misses, streak, best, time, left_score, right_score);
+
+
+        // Draw controls
+        mvprintw(max_y - 1, 0, "Controls: left up -> \',\' left down -> \'o\'; right up -> \'r\' right down -> \'n\'; speed up -> \'f\' slow down -> \'s\'; quit -> \'Q\'");
+
+        // Draw borders
+        attron(COLOR_PAIR(3));
+        for (i = 0; i < max_x; i++) {
+            mvprintw(1, i, BORDER);
+            mvprintw(max_y - 2, i, BORDER);
+        }
+        attroff(COLOR_PAIR(3));
+
+        // Clear old paddles
+        for (i = 2; i < max_y - 2; i++) {
+            mvprintw(i, paddle1.px, "  ");
+            mvprintw(i, paddle2.px, "  ");
+        }
+
+        // Draw paddles
+        attron(COLOR_PAIR(1));
+        for (i = 0; i < paddle1.length; i++) {
+            mvprintw(paddle1.py + i, paddle1.px, PADDLE);
+        }
+        for (i = 0; i < paddle2.length; i++) {
+            mvprintw(paddle2.py + i, paddle2.px, PADDLE);
+        }
+        attroff(COLOR_PAIR(1));
+
+        // Clear previous ball position
+        mvprintw(ball.py, ball.px, " ");
+
+        // Ball collisions
+        if ((ball.py + ball.dy) < 2 || (ball.py + ball.dy) > max_y - 3) {
+            ball.dy *= -1;
+        }
+
+        // Right paddle collision (Player 1)
+        if ((ball.px + ball.dx == paddle1.px) &&
+            (ball.py + ball.dy >= paddle1.py) &&
+            (ball.py + ball.dy < paddle1.py + paddle1.length)) {
+            hits++;
+            streak++;
+            if (streak > best) best = streak;
+            ball.dx *= -1;
+        }
+
+        // Left paddle collision (Player 2)
+        if ((ball.px + ball.dx == paddle2.px + 1) &&
+            (ball.py + ball.dy >= paddle2.py) &&
+            (ball.py + ball.dy < paddle2.py + paddle2.length)) {
+            hits++;
+            streak++;
+            if (streak > best) best = streak;
+            ball.dx *= -1;
+        }
+
+        // Ball goes past right paddle
+        if (ball.px > max_x) {
+            left_score++;
+            misses++;
+            streak = 0;
+            ball.py = max_y / 2;
+            ball.px = max_x / 2;
+            ball.dy = rand() & 1 ? 1 : -1;
+            ball.dx = rand() & 1 ? 1 : -1;
+        }
+
+        // Ball goes past Player 2's paddle (left side)
+        if (ball.px < 1) {
+            right_score++;
+            misses++;
+            streak = 0;
+            ball.py = max_y / 2;
+            ball.px = max_x / 2;
+            ball.dy = rand() & 1 ? 1 : -1;
+            ball.dx = rand() & 1 ? 1 : -1;
+        }
+
+        // Ball movement
+        if (frame % 4 == 0) {
+            ball.py += ball.dy;
+            ball.px += ball.dx;
+        }
+
+        // Draw ball
+        attron(COLOR_PAIR(2));
+        mvprintw(ball.py, ball.px, BALL_SYMBOL);
+        attroff(COLOR_PAIR(2));
+
+        // Input
+        switch (getch()) {
+            case 'r': // Player 1 up
+                if (paddle1.py > 2) paddle1.py -= 1;
+                break;
+            case 'n': // Player 1 down
+                if (paddle1.py + paddle1.length < max_y - 2) paddle1.py += 1;
+                break;
+            case ',': // Player 2 up
+                if (paddle2.py > 2) paddle2.py -= 1;
+                break;
+            case 'o': // Player 2 down
+                if (paddle2.py + paddle2.length < max_y - 2) paddle2.py += 1;
+                break;
+            case 'f': // Speed up
+                if (sleep_time > 1000) {
+                    sleep_time -= 1000;
+                }
+                break;
+            case 's': // Slow down
+                if (sleep_time < 30000) {
+                    sleep_time += 1000;
+                }
+                break;
+            case 'Q':
+                quit = 1;
+                break;
+        }
+
+        frame++;
+        usleep(sleep_time);
+    }
+
+    // Exit
+    endwin();
+    system("clear");
+    return 0;
+}

+ 124 - 0
lab08/pong_sp.c

@@ -0,0 +1,124 @@
+#include <ncurses.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define BALL_SYMBOL "O"
+#define BORDER "#"
+#define PADDLE "||"
+
+#define SLEEP_TIME 20000
+
+struct Ball {
+    int px, py, dx, dy;
+};
+
+struct Paddle {
+    int px, py, length;
+};
+
+int main(void) {
+    // initialization
+    int hits = 0, misses = 0, best = 0, streak = 0, quit = 0, frame = 1, max_y,
+        max_x;
+    struct Ball ball;
+    struct Paddle paddle;
+    system("clear");
+    initscr();
+    curs_set(0);
+    cbreak();
+    noecho();
+    nodelay(stdscr, 1);
+    start_color();
+    init_pair(1, COLOR_CYAN, COLOR_BLACK);
+    init_pair(2, COLOR_YELLOW, COLOR_BLACK);
+    init_pair(3, COLOR_GREEN, COLOR_BLACK);
+    getmaxyx(stdscr, max_y, max_x);
+    ball.py = max_y / 2;
+    ball.px = max_x / 2;
+    ball.dy = rand() & 1 ? 1 : -1;
+    ball.dx = rand() & 1 ? 1 : -1;
+    paddle.length = 6;
+    paddle.py = (max_y / 2) - (paddle.length / 2);
+    paddle.px = max_x - 3;
+
+    // game logic
+    while (!quit) {
+        // drawing
+        getmaxyx(stdscr, max_y, max_x);
+        mvprintw(
+            0, 0,
+            "Hits: %d     Misses: %d     Streak: %d     Best: %d     Time: %d",
+            hits, misses, streak, best, frame / 50);  // draw stats
+        attron(COLOR_PAIR(3));
+        int i;
+        for ( i = 0; i < max_x; i++) {  // draw top borders
+            mvprintw(1, i, BORDER);
+            mvprintw(max_y - 1, i, BORDER);
+        }
+        for ( i = 1; i < max_y; i++) {  // draw side border
+            mvprintw(i, 0, BORDER);
+        }
+        attroff(COLOR_PAIR(3));
+        attron(COLOR_PAIR(1));
+        paddle.px = max_x - 3;  // in case window was resized update paddle x-pos
+        for ( i = 0; i < paddle.length; i++) {
+            mvprintw(paddle.py + i, paddle.px, PADDLE);  // draw paddle
+        }
+        attroff(COLOR_PAIR(1));
+        attron(COLOR_PAIR(2));
+        mvprintw(ball.py, ball.px, BALL_SYMBOL);  // draw ball
+        attroff(COLOR_PAIR(2));
+
+        // collisions
+        if ((ball.py + ball.dy) < 2 ||
+            (ball.py + ball.dy) > max_y - 2) {  // ball-top collision
+            ball.dy *= -1;
+        }
+        if ((ball.px + ball.dx) < 1) {  // ball-side collision
+            ball.dx *= -1;
+        }
+        if ((ball.px + ball.dx == paddle.px) &&
+            (ball.py + ball.dy >= paddle.py) &&
+            (ball.py + ball.dy <=
+             (paddle.py + paddle.length))) {  // ball-paddle collision
+            hits--;
+            streak++;
+            if (streak > best) best = streak;
+            ball.dx *= -1;
+        }
+        if (ball.px > max_x) {  // ball has passed the paddle
+            misses++;
+            streak = 0;
+            ball.py = max_y / 2;
+            ball.px = max_x / 2;
+            ball.dy = rand() & 1 ? 1 : -1;
+            ball.dx = rand() & 1 ? 1 : -1;
+        }
+        if (frame % 4 == 0) {
+            ball.py += ball.dy;
+            ball.px += ball.dx;
+        }
+
+        // input
+        switch (getch()) {
+            case 'j':
+                if (paddle.py - 1 > 1) paddle.py -= 1;
+                break;
+
+            case 'k':
+                if ((paddle.py + paddle.length) + 1 < max_y) paddle.py += 1;
+                break;
+
+            case 'Q':
+                quit = 1;
+                break;
+        }
+        frame++;
+        usleep(SLEEP_TIME);
+    }
+    // exit
+    endwin();
+    system("clear");
+    return 0;
+}
+

+ 32 - 0
lab08/set_ticker.c

@@ -0,0 +1,32 @@
+#include	<stdio.h>
+#include        <sys/time.h>
+#include        <signal.h>
+
+/*
+ *      set_ticker.c
+ *          set_ticker( number_of_milliseconds )
+ *                   arranges for the interval timer to issue
+ *                   SIGALRM's at regular intervals
+ *          returns -1 on error, 0 for ok
+ *
+ *      arg in milliseconds, converted into micro seoncds
+ */
+
+
+set_ticker( n_msecs )
+{
+        struct itimerval new_timeset;
+        long    n_sec, n_usecs;
+
+        n_sec = n_msecs / 1000 ;
+        n_usecs = ( n_msecs % 1000 ) * 1000L ;
+
+        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);
+}
+
+

+ 42 - 0
lab08/sigactdemo.c

@@ -0,0 +1,42 @@
+/* sigactdemo.c
+ *               purpose: shows use of sigaction()
+ *               feature: blocks ^\ while handling ^C
+ *                        does not reset ^C handler, so two kill
+ */
+
+#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);
+}

+ 49 - 0
lab08/sigdemo3.c

@@ -0,0 +1,49 @@
+/* sigdemo3.c
+ *	purpose:   show answers to signal questions
+ *	question1: does the handler stay in effect after a signal arrives?
+ *	question2: what if a signalX arrives while handling signalX?
+ *      question3: what if a signalX arrives while handling signalY?
+ *      question4: what happens to read() when a signal arrives?
+ */
+
+#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");
+}

+ 26 - 0
lab08/sleep1.c

@@ -0,0 +1,26 @@
+/* sleep1.c
+ *	purpose	show how sleep works
+ *	usage	sleep1
+ *	outline	sets handler, sets alarm, pauses, then returns
+ */
+#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
+}

+ 58 - 0
lab08/ticker_demo.c

@@ -0,0 +1,58 @@
+/* ticker_demo.c
+ *    demonstrates use of interval timer to generate reqular
+ *    signals, which are in turn caught and used to count down
+ */
+
+#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);
+}
+
+