Skip to content

Commit ab6cf2d

Browse files
New solution.
1 parent 888de06 commit ab6cf2d

File tree

6 files changed

+294
-197
lines changed

6 files changed

+294
-197
lines changed

c/lezione15/cat.c

+32-37
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,38 @@
1-
#include <stdlib.h>
21
#include <stdio.h>
2+
#include <string.h>
3+
#include <errno.h>
34
#include <unistd.h>
5+
#include <fcntl.h>
46
#include <sys/wait.h>
57

6-
int main(int argc, char **argv) {
8+
int main(int argc, char **argv)
9+
{
10+
if(argc < 2) {
11+
fprintf(stderr, "Specificare il nome di un file\n");
12+
return 1;
13+
}
714

8-
if (argc != 2) {
9-
printf("Utilizzo del comando: %s <file>", argv[0]);
10-
return 1;
11-
}
12-
13-
char *filename = argv[1];
14-
15-
int file = open(filename, O_RDONLY);
16-
17-
if(!file) {
18-
fprintf(stderr, "Errore nell’apertura del file!\n");
19-
return 2;
20-
}
21-
22-
int pipes[2] = { };
23-
if(pipe(pipes) == -1) {
24-
perror("pipe()");
25-
return 1;
26-
}
27-
28-
pid_t ls = fork();
29-
switch(ls) {
30-
case -1:
31-
perror("fork()");
32-
exit(2);
33-
case 0: // figlio
34-
dup2(file, 1); // redirigo stdout
35-
close(pipes[1]);
36-
execlp("ls", "ls", "-l", NULL);
37-
perror("ls"); // se arrivo qui, execlp() ha fallito
38-
return 2;
39-
} // il padre prosegue
40-
41-
42-
15+
int fd = open(argv[1], O_RDONLY);
16+
if(fd == -1) {
17+
fprintf(stderr, "Impossibile aprire il file %s: %s\n",
18+
argv[1], strerror(errno));
19+
return 2;
20+
}
21+
22+
int pid = fork();
23+
switch(pid) {
24+
case -1:
25+
perror("fork()");
26+
return 3;
27+
case 0: // figlio
28+
dup2(fd, 0);
29+
execlp("cat", "cat", NULL);
30+
perror("Impossibile eseguire il comando cat");
31+
return 4;
32+
default:
33+
wait(NULL);
34+
close(fd);
35+
}
36+
37+
return 0;
4338
}

c/lezione15/es2/Makefile

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
2+
exec_pipes: exec_pipes.o freadline.o
3+
clang exec_pipes.o freadline.o -o exec_pipes
4+
5+
%.o: %.c freadline.h
6+
clang -c -g -o $@ $<
7+
8+
clean:
9+
rm -f *.o exec_pipes
10+

c/lezione15/es2/exec_pipes.c

+172
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <ctype.h>
4+
#include <string.h>
5+
#include <errno.h>
6+
#include <unistd.h>
7+
#include <sys/wait.h>
8+
9+
#include "freadline.h"
10+
11+
void exec_line(char *line, int nline);
12+
void exec_cmd(char **argv, int in, int out);
13+
char **split(char *str);
14+
15+
int main(int argc, char **argv)
16+
{
17+
if(argc < 2) {
18+
fprintf(stderr, "Specificare il nome di un file\n");
19+
return 1;
20+
}
21+
22+
FILE *file = fopen(argv[1], "r");
23+
if(!file) {
24+
fprintf(stderr, "Impossibile aprire il file %s: %s\n",
25+
argv[1], strerror(errno));
26+
}
27+
28+
char *line = NULL;
29+
int n = 0;
30+
31+
while(1)
32+
{
33+
++n;
34+
line = freadline(file, line);
35+
if(!line) {
36+
if(ferror(file)) {
37+
perror("Errore di lettura");
38+
return 2;
39+
}
40+
return 0;
41+
}
42+
43+
pid_t pid=fork();
44+
switch(pid) {
45+
case -1:
46+
perror("fork()");
47+
return 3;
48+
case 0:
49+
fclose(file);
50+
exec_line(line, n);
51+
default:
52+
waitpid(pid,NULL,0);
53+
}
54+
}
55+
56+
fclose(file);
57+
return 0;
58+
}
59+
60+
void exec_line(char *line, int nline)
61+
{
62+
char *first = line;
63+
char *second = NULL;
64+
65+
// prima salto qualsiasi cosa che sia uno spazio all'inizio della riga
66+
while(isspace(*line))
67+
++line;
68+
69+
if(*line == '\0') // in modo da poter accorgermi di linee vuote ed ignorarle
70+
exit(0);
71+
72+
if(*line == '|') {
73+
fprintf(stderr, "Manca il primo comando alla riga %d\n", nline);
74+
exit(3);
75+
}
76+
77+
// trovo l'inizio del secondo comando cercando il simbolo di pipe
78+
char *sep = strchr(line, '|');
79+
if(sep == NULL) {
80+
fprintf(stderr, "Manca il secondo comando alla riga %d\n", nline);
81+
exit(3);
82+
}
83+
84+
second = sep + 1;
85+
*sep = 0;
86+
87+
// salto eventuali spazi o tabulazioni prima dell'inizio del secondo comando
88+
for(; (*second)==' ' || (*second)=='\t'; second++);
89+
90+
char **argv1 = split(first);
91+
char **argv2 = split(second);
92+
93+
int pipes[2];
94+
pipe(pipes);
95+
96+
int pid1 = fork();
97+
if(pid1 == -1) {
98+
perror("fork()");
99+
exit(4);
100+
}
101+
102+
if(pid1 == 0) { // figlio 1
103+
close(pipes[0]);
104+
exec_cmd(argv1, 0, pipes[1]);
105+
}
106+
107+
int pid2 = fork();
108+
if(pid2 == -1) {
109+
perror("fork()");
110+
exit(3);
111+
}
112+
113+
if(pid2 == 0) { // figlio 2
114+
close(pipes[1]);
115+
exec_cmd(argv2, pipes[0], 1);
116+
}
117+
118+
close(pipes[0]);
119+
close(pipes[1]);
120+
121+
waitpid(pid1,NULL,0);
122+
waitpid(pid2,NULL,0);
123+
free(argv1);
124+
free(argv2);
125+
126+
exit(0);
127+
}
128+
129+
void exec_cmd(char **argv, int in, int out)
130+
{
131+
if(in != 0)
132+
dup2(in, 0);
133+
if(out != 1)
134+
dup2(out, 1);
135+
136+
execvp(argv[0], argv);
137+
fprintf(stderr, "Impossibile eseguire %s: %s\n", argv[0], strerror(errno));
138+
exit(5);
139+
}
140+
141+
char **split(char *str)
142+
{
143+
int size = 5;
144+
int found = 0;
145+
char **strings = calloc(size, sizeof(char *));
146+
147+
int parola = 0; // 1: siamo dentro ad una parola, 0: siamo in mezzo a spazi
148+
for(char *p = str; *p; ++p)
149+
{
150+
// se l'array è pieno lo rialloco
151+
if(found == size - 1) {
152+
size = 2 * size + 1;
153+
strings = realloc(strings, sizeof(char *) * size);
154+
}
155+
156+
// All'inizio di una parola incremento 'found' e imposto il puntatore
157+
if(!parola && !isspace(*p)) {
158+
parola = 1;
159+
strings[found] = p;
160+
++found;
161+
}
162+
163+
if(parola && isspace(*p)) {
164+
parola = 0;
165+
*p = 0;
166+
}
167+
}
168+
169+
strings[found] = NULL;
170+
171+
return strings;
172+
}

c/lezione15/es2/freadline.c

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
2+
/*
3+
* freadline.c
4+
*
5+
* File contenente funzioni varie utili per l'implementazione di file_exec.c
6+
*/
7+
8+
#include "freadline.h"
9+
10+
#include <stdio.h>
11+
#include <string.h>
12+
#include <stdlib.h>
13+
14+
char *freadline(FILE *file, char *line)
15+
{
16+
int size = 0;
17+
int read = 0;
18+
19+
// Se siamo già alla fine del file, restituiamo NULL e liberiamo la memoria
20+
if(feof(file)) {
21+
free(line);
22+
return NULL;
23+
}
24+
25+
// Se ci hanno passato già una stringa in input riutilizzeremo la memoria,
26+
// quindi ci informiamo su quanto lunga è la stringa (la memoria già allocata
27+
// potrebbe essere di più).
28+
if(line != NULL)
29+
size = strlen(line) + 1;
30+
31+
// Leggiamo un carattere alla volta riallocando quando necessario.
32+
for(char c = fgetc(file); c != '\n' && c != EOF; c = fgetc(file), ++read)
33+
{
34+
if(read == size) {
35+
size = size * 2 + 1;
36+
line = realloc(line, size);
37+
}
38+
39+
line[read] = c;
40+
}
41+
42+
// Ci assicuriamo che l'ultimo carattere contenga il terminatore nullo
43+
if(line)
44+
line[read] = 0;
45+
46+
// Se non abbiamo letto nulla perché si è subito verificato un errore,
47+
// liberiamo la memoria e restituiamo NULL. Altrimenti restituiamo la linea
48+
// lo stesso perché qualcosa è stato comunque letto.
49+
if(read == 0 && ferror(file)) {
50+
free(line);
51+
return NULL;
52+
}
53+
54+
return line;
55+
}

c/lezione15/es2/freadline.h

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* freadline.h
3+
*
4+
* File contenente funzioni varie utili per l'implementazione di file_exec.c
5+
*/
6+
7+
#ifndef FREADLINE_H
8+
#define FREADLINE_H
9+
10+
#include <stdio.h>
11+
12+
/*
13+
* Legge caratteri in input da 'file' fino ad EOF, o fino al newline '\n',
14+
* e ritorna una stringa allocata dinamicamente con il contenuto.
15+
* Se 'line' non è NULL, sovrascrive la stringa puntata da 'line', che deve
16+
* essere stata precedentemente allocata dinamicamente, che verrà realocata in
17+
* caso di necessità.
18+
*
19+
* Se la funzione viene chiamata su un file già finito (feof(file) restituisce
20+
* true), la funzione libera la memoria di 'line' e restituisce NULL.
21+
*/
22+
char *freadline(FILE *file, char *line);
23+
24+
#endif
25+

0 commit comments

Comments
 (0)