Difference between revisions of "Prova Pratica 2014.06.17"
Jump to navigation
Jump to search
(3 intermediate revisions by one other user not shown) | |||
Line 1: | Line 1: | ||
− | == | + | [http://www.cs.unibo.it/~renzo/so/pratiche/2014.06,17.pdf Link al testo] |
+ | ==Esercizio 1== | ||
+ | <source lang="text"> | ||
+ | Occorre scrivere due programmi: mytar myuntar. | ||
+ | Mytar prende come parametro il nome di una directory e il nome di un file: | ||
+ | mytar ddd ddd.mytar | ||
+ | mytar crea il file indicato come secondo parametro e registra in esso tutti i file regolari presenti nella directory (ddd | ||
+ | nell'esempio). Ogni file e' registrato nel secondo il seguente formato: | ||
+ | nome del file (stringa ASCII terminata da un byte 0) | ||
+ | lunghezza del file (stringa ASCII terminata da 0, la lunghezza e' registrata come stringa in rappresentazione in base 10 | ||
+ | per non avere problemi di endianess e di ampiezza dei campi) | ||
+ | contenuto del file (un numero di byte corrispondente alla lunghezza indicata sopra). | ||
+ | Myuntar fa l'operazione inversa: | ||
+ | myuntar ddd.mytar newddd | ||
+ | crea la directory indicata come secondo parametro e, in essa, tutti i file registrati in ddd.mytar. | ||
+ | Per provare i due programmi, al termine dell'esecuzione di due comandi simili a quelli degli esempi mostrati qui sopra per | ||
+ | mytar e myuntar, tutti i file regolari presenti in ddd devono esistere in newddd e devono avere tutti lo stesso contenuto. | ||
+ | Se create una directory ddd contenente solo file regolare l'output di “diff -R ddd newddd” deve essere vuoto. | ||
+ | </source> | ||
+ | |||
+ | ===Soluzione di Dado=== | ||
+ | mytar e myuntar entrambi funzionanti | ||
+ | |||
+ | |||
+ | mytar.c | ||
+ | <source lang="c"> | ||
+ | #include <stdio.h> | ||
+ | #include <stdlib.h> | ||
+ | #include <string.h> | ||
+ | #include <unistd.h> | ||
+ | #include <sys/types.h> | ||
+ | #include <dirent.h> | ||
+ | #include <sys/stat.h> | ||
+ | |||
+ | #define MAX 20 | ||
+ | #define MAXI 1024 | ||
+ | |||
+ | /*codice copiato da internet che ipotizzo funzioni :) */ | ||
+ | |||
+ | void reverse(char s[]) | ||
+ | { | ||
+ | int i, j; | ||
+ | char c; | ||
+ | |||
+ | for (i = 0, j = strlen(s)-1; i<j; i++, j--) { | ||
+ | c = s[i]; | ||
+ | s[i] = s[j]; | ||
+ | s[j] = c; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | void itoa(int n, char s[]) | ||
+ | { | ||
+ | int i, sign; | ||
+ | |||
+ | if ((sign = n) < 0) /* record sign */ | ||
+ | n = -n; /* make n positive */ | ||
+ | i = 0; | ||
+ | do { /* generate digits in reverse order */ | ||
+ | s[i++] = n % 10 + '0'; /* get next digit */ | ||
+ | } while ((n /= 10) > 0); /* delete it */ | ||
+ | if (sign < 0) | ||
+ | s[i++] = '-'; | ||
+ | s[i] = '\0'; | ||
+ | reverse(s); | ||
+ | } | ||
+ | |||
+ | |||
+ | /*mytar*/ | ||
+ | int main(int argc, char * argv[]){ | ||
+ | if(argc!=3){ | ||
+ | fprintf(stderr, "Wrong arguments number\n"); | ||
+ | return -1; | ||
+ | } | ||
+ | else{ | ||
+ | FILE *dest; | ||
+ | FILE *temp; | ||
+ | DIR *dir; | ||
+ | char length[MAX]; | ||
+ | char *buf_read; | ||
+ | char zero='\0'; | ||
+ | size_t n_readed; | ||
+ | struct stat buf; | ||
+ | struct dirent *entry; | ||
+ | if((dir=opendir(argv[1]))==NULL){ | ||
+ | fprintf(stderr, "Error opendir\n"); | ||
+ | exit(-1); | ||
+ | } | ||
+ | if((dest=fopen(argv[2],"w"))==NULL){ | ||
+ | fprintf(stderr, "Error fopen\n"); | ||
+ | exit(-1); | ||
+ | } | ||
+ | while((entry=readdir(dir))!=NULL){ | ||
+ | buf_read=NULL; | ||
+ | chdir(argv[1]); | ||
+ | if(entry->d_type==DT_REG){ | ||
+ | if(stat(entry->d_name,&buf)==-1){ | ||
+ | fprintf(stderr, "Error stat\n"); | ||
+ | exit(-1); | ||
+ | } | ||
+ | if((temp=fopen(entry->d_name,"r"))==NULL){ | ||
+ | fprintf(stderr, "Error fopen_temp\n"); | ||
+ | exit(-1); | ||
+ | } | ||
+ | write(fileno(dest),entry->d_name,strlen(entry->d_name)+1); | ||
+ | itoa(buf.st_size-1,length); | ||
+ | write(fileno(dest),length,strlen(length)+1); | ||
+ | /*scrivere dati*/ | ||
+ | while(getdelim(&buf_read,&n_readed,EOF,temp)>0){ | ||
+ | write(fileno(dest),buf_read,strlen(buf_read)-1); | ||
+ | } | ||
+ | free(buf_read); | ||
+ | } | ||
+ | } | ||
+ | printf("File mytar creato con successo!\n"); | ||
+ | return 0; | ||
+ | } | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | |||
+ | myuntar.c | ||
+ | <source lang="c"> | ||
+ | #include <stdio.h> | ||
+ | #include <stdlib.h> | ||
+ | #include <string.h> | ||
+ | #include <unistd.h> | ||
+ | #include <sys/types.h> | ||
+ | #include <dirent.h> | ||
+ | #include <sys/stat.h> | ||
+ | |||
+ | |||
+ | int main(int argc, char * argv[]){ | ||
+ | if(argc!=3){ | ||
+ | fprintf(stderr, "Wrong arguments number\n"); | ||
+ | exit(-1); | ||
+ | }else{ | ||
+ | FILE *mytar; | ||
+ | FILE *tmp; | ||
+ | char nome[256]; | ||
+ | int dim, i; | ||
+ | char readed[2],length[20]; | ||
+ | nome[0]=length[0]=0; | ||
+ | readed[1]=0; | ||
+ | if(mkdir(argv[2],(mode_t)0777)==-1){ | ||
+ | fprintf(stderr, "Error mkdir\n"); | ||
+ | exit(-1); | ||
+ | } | ||
+ | if((mytar=fopen(argv[1],"r"))==NULL){ | ||
+ | fprintf(stderr, "Error fopen\n"); | ||
+ | exit(-1); | ||
+ | } | ||
+ | if(chdir(argv[2])==-1){ | ||
+ | fprintf(stderr, "Errore chdir\n"); | ||
+ | exit(-1); | ||
+ | } | ||
+ | while((fread(&readed,1,1,mytar))){ | ||
+ | strcat(nome,readed); | ||
+ | while((fread(&readed,1,1,mytar))){ | ||
+ | if(readed[0]=='\0') break; | ||
+ | strcat(nome,readed); | ||
+ | } | ||
+ | printf("Nome trovato: %s\n",nome); | ||
+ | if((tmp=fopen(nome,"w"))==NULL){ | ||
+ | fprintf(stderr, "Error fopen files\n"); | ||
+ | exit(-1); | ||
+ | } | ||
+ | while((fread(&readed,1,1,mytar))){ | ||
+ | if(readed[0]=='\0') break; | ||
+ | strcat(length,readed); | ||
+ | } | ||
+ | dim=atoi(length); | ||
+ | printf("Lunghezza trovata: %s\n",length); | ||
+ | for(i=0; i<dim; i++){ | ||
+ | fread(&readed,1,1,mytar); | ||
+ | write(fileno(tmp),&readed,1); | ||
+ | } | ||
+ | fclose(tmp); | ||
+ | nome[0]=0; | ||
+ | length[0]=0; | ||
+ | } | ||
+ | fclose(mytar); | ||
+ | printf("File myuntar scompattato correttamente, credo\n"); | ||
+ | return 0; | ||
+ | } | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | |||
+ | === Soluzione di MV === | ||
+ | <source lang="text"> | ||
+ | Per ora ho fatto solo la prima parte, cioè mytar. | ||
+ | L'unico problema che non riesco a capire è che entra in un loop infinito (scrivendo all'infinito sul file che crea!) se viene usato nella cartella dell'eseguibile stesso... | ||
+ | </source> | ||
+ | |||
+ | <source lang="c"> | ||
+ | /*-------------------------------------MYTAR.C--------------------------------------------*/ | ||
+ | |||
+ | #include <stdlib.h> | ||
+ | #include <stdio.h> | ||
+ | #include <string.h> | ||
+ | #include <errno.h> | ||
+ | #include <sys/types.h> | ||
+ | #include <sys/stat.h> | ||
+ | #include <dirent.h> | ||
+ | #include <fcntl.h> | ||
+ | #include <unistd.h> | ||
+ | |||
+ | #define BUF_DIM 512 | ||
+ | |||
+ | /* scrive nome, dimensione e contenuto del file indicato da src nel file dest (già aperto in scrittura) */ | ||
+ | int filecpy(const char *src, const int dest, off_t size); | ||
+ | |||
+ | /* ---------------------------------- MAIN ------------------------------- */ | ||
+ | int main(int argc, char* argv[]) | ||
+ | { | ||
+ | DIR *ddd; | ||
+ | int f; | ||
+ | struct dirent *entry; | ||
+ | struct stat dest_st; | ||
+ | int e,i,len; | ||
+ | char buf[BUF_DIM]; | ||
+ | |||
+ | if(argc != 3) | ||
+ | { | ||
+ | printf("Error: needed 2 parameters\n"); | ||
+ | return 1; | ||
+ | } | ||
+ | |||
+ | umask(0001); | ||
+ | /* Creo il file passato come secondo parametro */ | ||
+ | if((f = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC, 0666)) == -1) | ||
+ | { | ||
+ | printf("Error in open(): %s (%i)\n",strerror(errno),errno); | ||
+ | return errno; | ||
+ | } | ||
+ | |||
+ | /* Apro la directory passata come primo parametro, se c'è */ | ||
+ | if((ddd = opendir(argv[1])) == NULL) | ||
+ | { | ||
+ | printf("Error in opendir(%s): %s (%i)\n",argv[1],strerror(errno),errno); | ||
+ | return errno; | ||
+ | } | ||
+ | /* mi sposto in quella directory */ | ||
+ | if(chdir(argv[1]) == -1) | ||
+ | { | ||
+ | printf("Error in chdir(%s): %s (%i)\n",argv[1],strerror(errno),errno); | ||
+ | return errno; | ||
+ | } | ||
+ | |||
+ | e = errno; | ||
+ | i = 0; /* in i mantengo il numero totale di file copiati */ | ||
+ | /* leggo lo stat del file che ho creato */ | ||
+ | if(fstat(f, &dest_st) == -1) | ||
+ | { | ||
+ | printf("Error in stat(%s): %s (%i)\n",buf,strerror(errno),errno); | ||
+ | return errno; | ||
+ | } | ||
+ | |||
+ | /* leggo le entry della directory finchè ce ne sono */ | ||
+ | while((entry = readdir(ddd)) != NULL) | ||
+ | { | ||
+ | struct stat st; | ||
+ | |||
+ | strcpy(buf, entry->d_name); | ||
+ | |||
+ | if(stat(buf, &st) == -1) | ||
+ | { | ||
+ | printf("Error in stat(%s): %s (%i)\n",buf,strerror(errno),errno); | ||
+ | return errno; | ||
+ | } | ||
+ | else if(st.st_mode & S_IFREG) /* è un file */ | ||
+ | { | ||
+ | /* verifico che il file in questione sia diverso da quello aperto in scrittura, per evitare che scriva su se stesso all'infinito */ | ||
+ | if((st.st_ino == dest_st.st_ino) && (st.st_rdev == dest_st.st_rdev)) | ||
+ | continue; | ||
+ | |||
+ | if(filecpy(buf, f, st.st_size) == -1) | ||
+ | { | ||
+ | printf("Error in filecpy(%s, %i)\n",buf,f); | ||
+ | return -1; | ||
+ | } | ||
+ | printf("%s inserito.\n", buf); | ||
+ | i++; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | if(e != errno) /* sono uscito dal ciclo a causa di un errore */ | ||
+ | { | ||
+ | printf("Error in readdir(): %s (%i)\n",strerror(errno),errno); | ||
+ | return errno; | ||
+ | } | ||
+ | else /* perchè ho visitato tutte le entrate della directory */ | ||
+ | printf("end of directory, %i entry found.\n", i); | ||
+ | |||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | int filecpy(const char *src, const int dest, off_t size) | ||
+ | { | ||
+ | /* NB: dest è già aperto in scrittura */ | ||
+ | int s, len, tot; | ||
+ | char buf[BUF_DIM]; | ||
+ | |||
+ | if((s = open(src,O_RDONLY,0)) == -1) /* apro src in lettura */ | ||
+ | return -1; | ||
+ | |||
+ | tot = write(dest, src, strlen(src)+1); /* per prima cosa copio il titolo del file src */ | ||
+ | /* NB: faccio tot+1 per copiare anche lo 0 terminatore */ | ||
+ | sprintf(buf, "%i", (int)size); /* poi copio la dimensione */ | ||
+ | tot += write(dest, buf, strlen(buf)+1); | ||
+ | |||
+ | /* infine copio tutto il contenuto */ | ||
+ | while( (len = read(s,buf,BUF_DIM)) != 0) | ||
+ | { | ||
+ | if(len == -1) | ||
+ | { | ||
+ | printf("Error in read(): %s (%i)\n",strerror(errno),errno); | ||
+ | return -1; | ||
+ | } | ||
+ | /*else printf("%i\n",len);*/ | ||
+ | tot += write(dest, buf, len); | ||
+ | } | ||
+ | |||
+ | return tot; /* restituisce il numero totale di byte scritti */ | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | |||
+ | ==Esercizio 3== | ||
<source lang="text"> | <source lang="text"> | ||
Il comando che dovrete implementare come script shell o programma python e' maxfreq. | Il comando che dovrete implementare come script shell o programma python e' maxfreq. | ||
Line 8: | Line 337: | ||
questo caso la maggior frequenza di 'q'). Fornisce in output il nome del file e la frequenza in percentuale. | questo caso la maggior frequenza di 'q'). Fornisce in output il nome del file e la frequenza in percentuale. | ||
</source> | </source> | ||
− | + | ===Bash=== | |
− | ===Soluzione di Davide Quadrelli=== | + | ====Soluzione di Davide Quadrelli==== |
<source lang="bash"> | <source lang="bash"> | ||
#! /bin/bash | #! /bin/bash | ||
Line 41: | Line 370: | ||
Ho sfruttato il comando bc per calcolare la percentuale. Utilizzo il parametro -q per impedire che stampi il "saluto" del programma e metto tutto il codice da eseguire nel file tmp. Oltre al comando, inserisco un "quit" per terminare il comando bc, che avrà restituito alla variabile soltanto il risultato del calcolo. Elimino poi ovviamente il file tmp. | Ho sfruttato il comando bc per calcolare la percentuale. Utilizzo il parametro -q per impedire che stampi il "saluto" del programma e metto tutto il codice da eseguire nel file tmp. Oltre al comando, inserisco un "quit" per terminare il comando bc, che avrà restituito alla variabile soltanto il risultato del calcolo. Elimino poi ovviamente il file tmp. | ||
− | + | =====Nota di Maldus===== | |
− | |||
grep -c $1 conta il numero di righe in cui si trovano le occorrenze; questo significa che se in una riga abbiamo 2 ( o più ) occorrenze viene comunque contata come 1. | grep -c $1 conta il numero di righe in cui si trovano le occorrenze; questo significa che se in una riga abbiamo 2 ( o più ) occorrenze viene comunque contata come 1. | ||
Per contare tutte le occorrenze ( anche nella stessa riga ) si potrebbe sostituire la riga | Per contare tutte le occorrenze ( anche nella stessa riga ) si potrebbe sostituire la riga | ||
Line 51: | Line 379: | ||
<source lang="bash"> | <source lang="bash"> | ||
tmp=`cat $var 2> /dev/null | grep -o $1 2> /dev/null | wc -l` | tmp=`cat $var 2> /dev/null | grep -o $1 2> /dev/null | wc -l` | ||
+ | </source> | ||
+ | |||
+ | ====Soluzione di G.C. ==== | ||
+ | <source lang="bash"> | ||
+ | #!/bin/bash | ||
+ | |||
+ | #input check | ||
+ | |||
+ | if [ $# -lt 2 ] ; then | ||
+ | echo "Arguments Error. Usage ./maxfreq character directory" | ||
+ | exit | ||
+ | fi | ||
+ | if [[ "$1" =~ [^a-zA-Z0-9] ]]; then | ||
+ | echo "invalid character" | ||
+ | exit | ||
+ | fi | ||
+ | if ! [ -d $2 ] ; then | ||
+ | echo "invalid directory as second argument" | ||
+ | exit | ||
+ | fi | ||
+ | |||
+ | tmp_file=/tmp/maxfreq$$ | ||
+ | |||
+ | #recursively find of $2 directory | ||
+ | find $2 -type f | while read line | ||
+ | do | ||
+ | num=$(cat $line | grep -o $1 | wc -l) | ||
+ | echo "$num:$line" >> $tmp_file | ||
+ | done | ||
+ | |||
+ | #file of "numOccurency:FileName" | ||
+ | |||
+ | ord_tmp_file=/tmp/ord_tmp_file$$ | ||
+ | |||
+ | #reverse ordering of the file and rewriting | ||
+ | cat $tmp_file | sort -r > $ord_tmp_file | ||
+ | rm $tmp_file | ||
+ | |||
+ | #take first line (major file occurency of char $1) | ||
+ | num=$(head -1 $ord_tmp_file | awk -F: '{print $1}') | ||
+ | file=$(head -1 $ord_tmp_file | awk -F: '{print $2}') | ||
+ | |||
+ | #count all char in $file of the first line | ||
+ | max=$(cat $file | wc -c) | ||
+ | |||
+ | #basename of file name (this is not mandatory) | ||
+ | base=$(basename $file) | ||
+ | |||
+ | #math to calculate % num/max | ||
+ | tmp_math_file=/tmp/math$$ | ||
+ | echo "( ${num} *100) / ${max}" > $tmp_math_file | ||
+ | echo "quit" >> $tmp_math_file | ||
+ | freq=$(bc -q $tmp_math_file) | ||
+ | rm $tmp_math_file | ||
+ | |||
+ | |||
+ | echo "File: $base Freq '$1' of $freq %" | ||
+ | |||
+ | rm $ord_tmp_file | ||
+ | </source> | ||
+ | |||
+ | ===Python3=== | ||
+ | ====Soluzione di G.C.==== | ||
+ | <source lang="python"> | ||
+ | import sys | ||
+ | import os | ||
+ | |||
+ | def checkFile(char, d): | ||
+ | e = [] | ||
+ | for x in os.listdir(d): | ||
+ | if os.path.isdir(os.path.join(d,x)): | ||
+ | e.append(checkFile(char,os.path.join(d,x))) | ||
+ | else: | ||
+ | f = open(os.path.join(d,x),"r") | ||
+ | e.append((os.path.join(d,x),f.read().count(char))) | ||
+ | f.close() | ||
+ | return e | ||
+ | |||
+ | def sortAndPrint(d): | ||
+ | d.sort(key=lambda tup: tup[1], reverse=True) | ||
+ | fileName= d[0][0] | ||
+ | num = d[0][1] | ||
+ | f = open(fileName,"r") | ||
+ | max_c = len(f.read()) | ||
+ | f.close() | ||
+ | return fileName, num/max_c*100 | ||
+ | |||
+ | if __name__=='__main__': | ||
+ | try: | ||
+ | if len(sys.argv) < 3: | ||
+ | raise Exception("Too few arguments. Usage ./maxfreq char dir") | ||
+ | if not sys.argv[1].isalnum(): | ||
+ | raise Exception("Char not alphanumeric passed") | ||
+ | if not os.path.isdir(sys.argv[2]): | ||
+ | raise Exception("%s is not a directory" % (sys.argv[2])) | ||
+ | d = checkFile(sys.argv[1],sys.argv[2]) | ||
+ | f,p = sortAndPrint(d) | ||
+ | print("Maxfreq occurency of %s was in %s with a percentage of %f %%" % (sys.argv[1],f,p)) | ||
+ | except Exception as inst: | ||
+ | print(inst.args) | ||
</source> | </source> |
Latest revision as of 15:35, 18 May 2017
Esercizio 1
Occorre scrivere due programmi: mytar myuntar.
Mytar prende come parametro il nome di una directory e il nome di un file:
mytar ddd ddd.mytar
mytar crea il file indicato come secondo parametro e registra in esso tutti i file regolari presenti nella directory (ddd
nell'esempio). Ogni file e' registrato nel secondo il seguente formato:
nome del file (stringa ASCII terminata da un byte 0)
lunghezza del file (stringa ASCII terminata da 0, la lunghezza e' registrata come stringa in rappresentazione in base 10
per non avere problemi di endianess e di ampiezza dei campi)
contenuto del file (un numero di byte corrispondente alla lunghezza indicata sopra).
Myuntar fa l'operazione inversa:
myuntar ddd.mytar newddd
crea la directory indicata come secondo parametro e, in essa, tutti i file registrati in ddd.mytar.
Per provare i due programmi, al termine dell'esecuzione di due comandi simili a quelli degli esempi mostrati qui sopra per
mytar e myuntar, tutti i file regolari presenti in ddd devono esistere in newddd e devono avere tutti lo stesso contenuto.
Se create una directory ddd contenente solo file regolare l'output di “diff -R ddd newddd” deve essere vuoto.
Soluzione di Dado
mytar e myuntar entrambi funzionanti
mytar.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#define MAX 20
#define MAXI 1024
/*codice copiato da internet che ipotizzo funzioni :) */
void reverse(char s[])
{
int i, j;
char c;
for (i = 0, j = strlen(s)-1; i<j; i++, j--) {
c = s[i];
s[i] = s[j];
s[j] = c;
}
}
void itoa(int n, char s[])
{
int i, sign;
if ((sign = n) < 0) /* record sign */
n = -n; /* make n positive */
i = 0;
do { /* generate digits in reverse order */
s[i++] = n % 10 + '0'; /* get next digit */
} while ((n /= 10) > 0); /* delete it */
if (sign < 0)
s[i++] = '-';
s[i] = '\0';
reverse(s);
}
/*mytar*/
int main(int argc, char * argv[]){
if(argc!=3){
fprintf(stderr, "Wrong arguments number\n");
return -1;
}
else{
FILE *dest;
FILE *temp;
DIR *dir;
char length[MAX];
char *buf_read;
char zero='\0';
size_t n_readed;
struct stat buf;
struct dirent *entry;
if((dir=opendir(argv[1]))==NULL){
fprintf(stderr, "Error opendir\n");
exit(-1);
}
if((dest=fopen(argv[2],"w"))==NULL){
fprintf(stderr, "Error fopen\n");
exit(-1);
}
while((entry=readdir(dir))!=NULL){
buf_read=NULL;
chdir(argv[1]);
if(entry->d_type==DT_REG){
if(stat(entry->d_name,&buf)==-1){
fprintf(stderr, "Error stat\n");
exit(-1);
}
if((temp=fopen(entry->d_name,"r"))==NULL){
fprintf(stderr, "Error fopen_temp\n");
exit(-1);
}
write(fileno(dest),entry->d_name,strlen(entry->d_name)+1);
itoa(buf.st_size-1,length);
write(fileno(dest),length,strlen(length)+1);
/*scrivere dati*/
while(getdelim(&buf_read,&n_readed,EOF,temp)>0){
write(fileno(dest),buf_read,strlen(buf_read)-1);
}
free(buf_read);
}
}
printf("File mytar creato con successo!\n");
return 0;
}
}
myuntar.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
int main(int argc, char * argv[]){
if(argc!=3){
fprintf(stderr, "Wrong arguments number\n");
exit(-1);
}else{
FILE *mytar;
FILE *tmp;
char nome[256];
int dim, i;
char readed[2],length[20];
nome[0]=length[0]=0;
readed[1]=0;
if(mkdir(argv[2],(mode_t)0777)==-1){
fprintf(stderr, "Error mkdir\n");
exit(-1);
}
if((mytar=fopen(argv[1],"r"))==NULL){
fprintf(stderr, "Error fopen\n");
exit(-1);
}
if(chdir(argv[2])==-1){
fprintf(stderr, "Errore chdir\n");
exit(-1);
}
while((fread(&readed,1,1,mytar))){
strcat(nome,readed);
while((fread(&readed,1,1,mytar))){
if(readed[0]=='\0') break;
strcat(nome,readed);
}
printf("Nome trovato: %s\n",nome);
if((tmp=fopen(nome,"w"))==NULL){
fprintf(stderr, "Error fopen files\n");
exit(-1);
}
while((fread(&readed,1,1,mytar))){
if(readed[0]=='\0') break;
strcat(length,readed);
}
dim=atoi(length);
printf("Lunghezza trovata: %s\n",length);
for(i=0; i<dim; i++){
fread(&readed,1,1,mytar);
write(fileno(tmp),&readed,1);
}
fclose(tmp);
nome[0]=0;
length[0]=0;
}
fclose(mytar);
printf("File myuntar scompattato correttamente, credo\n");
return 0;
}
}
Soluzione di MV
Per ora ho fatto solo la prima parte, cioè mytar.
L'unico problema che non riesco a capire è che entra in un loop infinito (scrivendo all'infinito sul file che crea!) se viene usato nella cartella dell'eseguibile stesso...
/*-------------------------------------MYTAR.C--------------------------------------------*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#define BUF_DIM 512
/* scrive nome, dimensione e contenuto del file indicato da src nel file dest (già aperto in scrittura) */
int filecpy(const char *src, const int dest, off_t size);
/* ---------------------------------- MAIN ------------------------------- */
int main(int argc, char* argv[])
{
DIR *ddd;
int f;
struct dirent *entry;
struct stat dest_st;
int e,i,len;
char buf[BUF_DIM];
if(argc != 3)
{
printf("Error: needed 2 parameters\n");
return 1;
}
umask(0001);
/* Creo il file passato come secondo parametro */
if((f = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC, 0666)) == -1)
{
printf("Error in open(): %s (%i)\n",strerror(errno),errno);
return errno;
}
/* Apro la directory passata come primo parametro, se c'è */
if((ddd = opendir(argv[1])) == NULL)
{
printf("Error in opendir(%s): %s (%i)\n",argv[1],strerror(errno),errno);
return errno;
}
/* mi sposto in quella directory */
if(chdir(argv[1]) == -1)
{
printf("Error in chdir(%s): %s (%i)\n",argv[1],strerror(errno),errno);
return errno;
}
e = errno;
i = 0; /* in i mantengo il numero totale di file copiati */
/* leggo lo stat del file che ho creato */
if(fstat(f, &dest_st) == -1)
{
printf("Error in stat(%s): %s (%i)\n",buf,strerror(errno),errno);
return errno;
}
/* leggo le entry della directory finchè ce ne sono */
while((entry = readdir(ddd)) != NULL)
{
struct stat st;
strcpy(buf, entry->d_name);
if(stat(buf, &st) == -1)
{
printf("Error in stat(%s): %s (%i)\n",buf,strerror(errno),errno);
return errno;
}
else if(st.st_mode & S_IFREG) /* è un file */
{
/* verifico che il file in questione sia diverso da quello aperto in scrittura, per evitare che scriva su se stesso all'infinito */
if((st.st_ino == dest_st.st_ino) && (st.st_rdev == dest_st.st_rdev))
continue;
if(filecpy(buf, f, st.st_size) == -1)
{
printf("Error in filecpy(%s, %i)\n",buf,f);
return -1;
}
printf("%s inserito.\n", buf);
i++;
}
}
if(e != errno) /* sono uscito dal ciclo a causa di un errore */
{
printf("Error in readdir(): %s (%i)\n",strerror(errno),errno);
return errno;
}
else /* perchè ho visitato tutte le entrate della directory */
printf("end of directory, %i entry found.\n", i);
return 0;
}
int filecpy(const char *src, const int dest, off_t size)
{
/* NB: dest è già aperto in scrittura */
int s, len, tot;
char buf[BUF_DIM];
if((s = open(src,O_RDONLY,0)) == -1) /* apro src in lettura */
return -1;
tot = write(dest, src, strlen(src)+1); /* per prima cosa copio il titolo del file src */
/* NB: faccio tot+1 per copiare anche lo 0 terminatore */
sprintf(buf, "%i", (int)size); /* poi copio la dimensione */
tot += write(dest, buf, strlen(buf)+1);
/* infine copio tutto il contenuto */
while( (len = read(s,buf,BUF_DIM)) != 0)
{
if(len == -1)
{
printf("Error in read(): %s (%i)\n",strerror(errno),errno);
return -1;
}
/*else printf("%i\n",len);*/
tot += write(dest, buf, len);
}
return tot; /* restituisce il numero totale di byte scritti */
}
Esercizio 3
Il comando che dovrete implementare come script shell o programma python e' maxfreq.
Maxfreq ha come parametro un carattere alfanumerico e una directory.
Es:
maxfreq q mydir
Cerca in tutto il sottoalbero del file system originato da mydir il file che ha la maggior frequenza della lettera indicata (in
questo caso la maggior frequenza di 'q'). Fornisce in output il nome del file e la frequenza in percentuale.
Bash
Soluzione di Davide Quadrelli
#! /bin/bash
if [[ -z $1 ]] ; then
echo "maxfreq [char da contare] [directory]"
exit
fi
if [[ -n $2 ]] ; then
files=`find -L $2`
else
echo if2
echo "maxfreq [char da contare] [directory]"
exit
fi
max=0
file=""
for var in $files; do
tmp=`cat $var 2> /dev/null | grep -c $1 2> /dev/null`
if [[ max -le tmp ]]; then
max=$tmp
file=$var
fi
done
dim=`ls -l $file | cut -d " " -f 5`
echo "( ${max} * 100 ) / ${dim}" > tmp
echo "quit" >> tmp
perc=`bc -q tmp`
rm tmp
echo "Il file $file contiene ${perc}% di $1 ($max su $dim caratteri)"
Ho sfruttato il comando bc per calcolare la percentuale. Utilizzo il parametro -q per impedire che stampi il "saluto" del programma e metto tutto il codice da eseguire nel file tmp. Oltre al comando, inserisco un "quit" per terminare il comando bc, che avrà restituito alla variabile soltanto il risultato del calcolo. Elimino poi ovviamente il file tmp.
Nota di Maldus
grep -c $1 conta il numero di righe in cui si trovano le occorrenze; questo significa che se in una riga abbiamo 2 ( o più ) occorrenze viene comunque contata come 1. Per contare tutte le occorrenze ( anche nella stessa riga ) si potrebbe sostituire la riga
tmp=`cat $var 2> /dev/null | grep -c $1 2> /dev/null`
con
tmp=`cat $var 2> /dev/null | grep -o $1 2> /dev/null | wc -l`
Soluzione di G.C.
#!/bin/bash
#input check
if [ $# -lt 2 ] ; then
echo "Arguments Error. Usage ./maxfreq character directory"
exit
fi
if [[ "$1" =~ [^a-zA-Z0-9] ]]; then
echo "invalid character"
exit
fi
if ! [ -d $2 ] ; then
echo "invalid directory as second argument"
exit
fi
tmp_file=/tmp/maxfreq$$
#recursively find of $2 directory
find $2 -type f | while read line
do
num=$(cat $line | grep -o $1 | wc -l)
echo "$num:$line" >> $tmp_file
done
#file of "numOccurency:FileName"
ord_tmp_file=/tmp/ord_tmp_file$$
#reverse ordering of the file and rewriting
cat $tmp_file | sort -r > $ord_tmp_file
rm $tmp_file
#take first line (major file occurency of char $1)
num=$(head -1 $ord_tmp_file | awk -F: '{print $1}')
file=$(head -1 $ord_tmp_file | awk -F: '{print $2}')
#count all char in $file of the first line
max=$(cat $file | wc -c)
#basename of file name (this is not mandatory)
base=$(basename $file)
#math to calculate % num/max
tmp_math_file=/tmp/math$$
echo "( ${num} *100) / ${max}" > $tmp_math_file
echo "quit" >> $tmp_math_file
freq=$(bc -q $tmp_math_file)
rm $tmp_math_file
echo "File: $base Freq '$1' of $freq %"
rm $ord_tmp_file
Python3
Soluzione di G.C.
import sys
import os
def checkFile(char, d):
e = []
for x in os.listdir(d):
if os.path.isdir(os.path.join(d,x)):
e.append(checkFile(char,os.path.join(d,x)))
else:
f = open(os.path.join(d,x),"r")
e.append((os.path.join(d,x),f.read().count(char)))
f.close()
return e
def sortAndPrint(d):
d.sort(key=lambda tup: tup[1], reverse=True)
fileName= d[0][0]
num = d[0][1]
f = open(fileName,"r")
max_c = len(f.read())
f.close()
return fileName, num/max_c*100
if __name__=='__main__':
try:
if len(sys.argv) < 3:
raise Exception("Too few arguments. Usage ./maxfreq char dir")
if not sys.argv[1].isalnum():
raise Exception("Char not alphanumeric passed")
if not os.path.isdir(sys.argv[2]):
raise Exception("%s is not a directory" % (sys.argv[2]))
d = checkFile(sys.argv[1],sys.argv[2])
f,p = sortAndPrint(d)
print("Maxfreq occurency of %s was in %s with a percentage of %f %%" % (sys.argv[1],f,p))
except Exception as inst:
print(inst.args)