====== تابع ()fgets - خواندن از stdin به شکل pipe-friendly ====== ---- ==== Section 1 ==== // man 3 fgets /* fgets() reads in at most one less than size characters from stream and stores them into the * buffer pointed to by s. Reading stops after an EOF or a newline. If a newline is read, it is * stored into the buffer. A terminating null byte ('\0') is stored after the last character in * the buffer. * fgets() returns s on success, and NULL on error or when end of file occurs while no characters * have been read. */ #include char *fgets(char *s, int size, FILE *stream); // man 3 memset /* memset - fills the first n bytes of the memory area pointed to by s with the constant byte c */ #include void *memset(void s[.n], int c, size_t n); /* case-changer.c */ #include #include int main(void) { char c[20] = { 0 }; char newcase[20] = { 0 }; int i; while(fgets(c, sizeof(c), stdin) != NULL) { for(i=0; i<=sizeof(c); i++) { /* Upper case to lower case */ if ( (c[i] >= 65) && (c[i] <= 90) ) { newcase[i] = c[i] + 32; } /* Lower case to upper case */ if ( (c[i] >= 97 && c[i] <= 122) ) { newcase[i] = c[i] - 32; } } printf("%s\n", newcase); /* zero out the arrays so there are no left-overs in the next run */ memset(c, 0, sizeof(c)); memset(newcase, 0, sizeof(newcase)); } return 0; } $ make case-changer cc case-changer.c -o case-changer $ ./case-changer hello HELLO AbCdEf aBcDeF $ ls / | head -n 5 | ./case-changer BIN BOOT COMMAND DEV ETC $ man ls | egrep '^[A-Z]+$' | ./case-changer name synopsis description author copyright /* ascii-table.c */ #include int main(void) { char c; for (c = 65; c<=90; c++) { printf("%c = %d ", c, c); /* upper case */ printf("%c = %d\n", c+32, c+32); /* lower case */ } return 0; } $ make ascii-table cc ascii-table.c -o ascii-table $ ./ascii-table A = 65 a = 97 B = 66 b = 98 C = 67 c = 99 D = 68 d = 100 E = 69 e = 101 F = 70 f = 102 G = 71 g = 103 H = 72 h = 104 I = 73 i = 105 J = 74 j = 106 K = 75 k = 107 L = 76 l = 108 M = 77 m = 109 N = 78 n = 110 O = 79 o = 111 P = 80 p = 112 Q = 81 q = 113 R = 82 r = 114 S = 83 s = 115 T = 84 t = 116 U = 85 u = 117 V = 86 v = 118 W = 87 w = 119 X = 88 x = 120 Y = 89 y = 121 Z = 90 z = 122 ---- ==== Section 2 ==== // man 3 strspn /* The strspn() function returns the number of bytes in the initial segment of s which consist * only of bytes from accept. */ #include size_t strspn(const char *s, const char *accept); // man 3 strlen /* The strlen() function calculates the length of the string pointed to by s, excluding the * terminating null byte ('\0'). */ #include size_t strlen(const char *s); /* mph-to-kph.c */ #include #include #include int main(void) { char mph[10] = { 0 }; while(fgets(mph, sizeof(mph), stdin) != NULL) { /* Check if mph is numeric * (and do conversion) */ if( strspn(mph, "0123456789.-\n") == strlen(mph) ) { printf("%.1f\n", (atof(mph)*1.60934) ); } /* If mph is NOT numeric, print error * and return */ else { fprintf(stderr, "Found non-numeric" " value\n"); return 1; } } return 0; } $ make mph-to-kph cc mph-to-kph.c -o mph-to-kph $ ./mph-to-kph 50 80.5 60 96.6 100 160.9 hello Found non-numeric value $ echo $? 1 $ ./mph-to-kph 50 80.5 $ echo $? 0 $ cat avg.txt 10-minute average: 61 mph 30-minute average: 55 mph 45-minute average: 54 mph 60-minute average: 52 mph 90-minute average: 52 mph 99-minute average: nn mph $ awk '{print $3}' avg.txt 61 55 54 52 52 nn $ awk '{print $3}' avg.txt | ./mph-to-kph 98.2 88.5 86.9 83.7 83.7 Found non-numeric value $ awk '{print $3}' avg.txt | ./mph-to-kph 2> /dev/null | sed -e 's,$, km/h,' 98.2 km/h 88.5 km/h 86.9 km/h 83.7 km/h 83.7 km/h ---- ==== Section 3 ==== /* mph-to-kph_v2.c */ #define _XOPEN_SOURCE 500 #include #include #include #include void printHelp(FILE *stream, char progname[]); int main(int argc, char *argv[]) { char mph[10] = { 0 }; int opt; int cont = 0; /* Parse command-line options */ while ((opt = getopt(argc, argv, "ch")) != -1) { switch(opt) { case 'h': printHelp(stdout, argv[0]); return 0; case 'c': cont = 1; break; default: printHelp(stderr, argv[0]); return 1; } } while(fgets(mph, sizeof(mph), stdin) != NULL) { /* Check if mph is numeric * (and do conversion) */ if( strspn(mph, "0123456789.-\n") == strlen(mph) ) { printf("%.1f\n", (atof(mph)*1.60934) ); } /* If mph is NOT numeric, print error * and return */ else { fprintf(stderr, "Found non-numeric " "value\n"); if (cont == 1) /* Check if -c is set */ { continue; /* Skip and continue if * -c is set */ } else { return 1; /* Abort if -c is not set */ } } } return 0; } void printHelp(FILE *stream, char progname[]) { fprintf(stream, "%s [-c] [-h]\n", progname); fprintf(stream, " -c continues even though a non" "-numeric value was detected in the input\n" " -h print help\n"); } $ make mph-to-kph_v2 cc mph-to-kph_v2.c -o mph-to-kph_v2 $ ./mph-to-kph_v2 60 96.6 40 64.4 hello Found non-numeric value $ ./mph-to-kph_v2 -c 50 80.5 90 144.8 hello Found non-numeric value 10 16.1 20 32.2 $ cat avg-with-garbage.txt 10-minute average: 61 mph 30-minute average: 55 mph 45-minute average: 54 mph 60-minute average: 52 mph 90-minute average: 52 mph 99-minute average: nn mph 120-minute average: 49 mph 160-minute average: 47 mph 180-minute average: nn mph error reading data from interface 200-minute average: 43 mph $ awk '{print $3}' avg-with-garbage.txt 61 55 54 52 52 nn 49 47 nn data 43 $ awk '{print $3}' avg-with-garbage.txt | ./mph-to-kph_v2 -c 98.2 88.5 86.9 83.7 83.7 Found non-numeric value 78.9 75.6 Found non-numeric value Found non-numeric value 69.2 $ awk '{print $3}' avg-with-garbage.txt | ./mph-to-kph_v2 -c 2> errors.txt 1> output.txt $ cat output.txt 98.2 88.5 86.9 83.7 83.7 78.9 75.6 69.2 $ cat errors.txt Found non-numeric value Found non-numeric value Found non-numeric value