تابع ()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 <stdio.h>
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 <string.h>
void *memset(void s[.n], int c, size_t n);
/* case-changer.c */
#include <stdio.h>
#include <string.h>
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 <stdio.h>
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 <string.h>
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 <string.h>
size_t strlen(const char *s);
/* mph-to-kph.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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
<ctrl-D>
$ 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
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
<ctrl-d>
$ 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