Prova pratica 17 07 14

From Sistemi Operativi
Jump to navigation Jump to search

Esercizio 1

Scrivere un programma che per ogni file .c nella directory corrente chiami il compilatore gcc per generare il file oggetto (.o) a
meno che esista gia' nella directory un file oggetto relativo allo stesso sorgente che sia piu' nuovo (ultima modifica) del
sorgente.
Tutti I parametri devono essere passati al compilatore.
Es:
genobj -I . -ggdb
se nella directory corrente esistono I file uno.c e due.c e il file due.o deve richiamare
gcc -I. -ggdb -c uno.c
e, solo se due.o ha ultima modifica precedente a due.c, deve chiamare
gcc -I. -ggdb -c due.c

Soluzione di Davide Quadrelli

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <stdlib.h>
#include <string.h>

#define MAX 256
#define DIM_MAX 1000
#define dim_last_data 4

int main (int argc, char *argv[]){
	int i,len,com_size,bol=0;	
	struct stat o_data,f_data;
	struct dirent *cur_file;
	char name[MAX];
	char prefix[DIM_MAX]="gcc ";
	char *comm;
	FILE *o;
	FILE *obj=NULL;
	DIR *dir=opendir("./");
	/*store in prefix the common part of every command to launch*/
    for (i=1;i<argc;i++){
        strcat(prefix,argv[i]);
        strcat(prefix," ");
    }
    com_size=strlen(prefix);
    /*search in the current directory C files*/
    while(cur_file=readdir(dir)){
        if(cur_file->d_type==DT_REG){
            /*it's a file*/
            bol=0;
            strcpy(name,cur_file->d_name);
            printf("file found: %s ",name);
            len=strlen(name);
            if(strcmp(&(name[len-2]),".c")==0){
                /*C file found*/
                printf("... source code found ...");
                /*check if the file has already an uptaded object file*/
                name[len-1]='o';
                if ((o=fopen(name,"r"))==NULL){
                    /*the corrispondent object file doesn't exists*/
                    bol=1;
                    name[len-1]='c';
                }else{
                    fclose(o);
                    /*get the stat data of the object file*/
                    if(stat(name,&o_data)){
                        write(STDERR_FILENO,"ERRORE STAT",11);
                        exit(-1);
                    }
                    /*get the stat data of the C file*/
                    name[len-1]='c';
                    if(stat(name,&f_data)){
                        write(STDERR_FILENO,"ERRORE STAT",11);
                        exit(-1);
                    }
                    /*check if the object file must be re-created*/
                    if(o_data.st_mtime<f_data.st_mtime){
                        bol=1;
                    }
                }
            }
            if(bol){
                /*prepare and exec the command*/
                comm=(char *)malloc(com_size+len+dim_last_data);
                strcpy(comm,prefix);
                strcat(comm,"-c ");
                strcat(comm,name);
                system(comm);
                printf("object file created.\n%s",comm);
            }
            printf("\n\n");
        }
    }
return 0;
}

Nota del Prof: Nel testo dell'esercizio, in grassetto, c'e' scritto: Non usare system o popen o simili!. System e' una funzione non sicura. Se si vogliono comporre stringhe c'e' anche la asprintf (al posto di malloc+strcpy+strcat). Se si vuole usare la malloc si puo' usare la snprintf che' piu' comoda di tutte del strcpy/cat Renzo (talk) 16:09, 7 April 2015 (CEST)

Soluzione di Stefano Mazza

#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdlib.h>
#include <dirent.h>
#include <unistd.h>
#include <string.h>
#include "s2argv/s2argv.h"

/*funzione per sapere l'estensione del file: ritorna vero se quello considerato è un file .x (dove x è il carattere passato come input)*/
int formato(const char *name, const char x){
	char *point = strrchr(name, '.'); //cerco l'ultima occorrenza del punto della stringa data (nel nome del file)
	if (point==NULL || point==name) return 0;	
	else 
	{
		point++;
		if (x==(*point)) return 1;
		else return 0; 
	}
}

/*funzione per modificare l'estensione del file di nome name.c*/
char *modify_format(char *name, const char x){
	char *newname, *ext; 	
	strcpy(newname, name);	
	ext = strrchr(newname, 'c');
	*ext = x;	//cambio il formato con quello passato per parametro (nel nostro caso cambio .c con .o) 
	return newname;
}

int main(int argc, char *argv[]){
	if (argc!=4)
	{
		fprintf(stderr, "Usage: %s [-I] [directory] [-ggdb]", argv[0]);
		exit(EXIT_FAILURE);
	}
	char *cmd = NULL;
	int n, i; 
	struct stat info_c, info_o;
	struct dirent **entry_list; 
	if( (n=scandir(argv[2], &entry_list, NULL, alphasort)) <0)	
	{
		perror("Scandir: error while scanning directory\n");
		exit(1);
	} 
	chdir(argv[2]);
	for (i=0; i<n; i++)
	{
		stat(entry_list[i]->d_name, &info_c); 
		if( S_ISREG(info_c.st_mode) && formato(entry_list[i]->d_name, 'c')) 
		{	//controllo se per ogni file .c esiste il relativo file .o
			if ( access( modify_format(entry_list[i]->d_name, 'o'), F_OK) < 0 ) 	//caso non esiste ==> lo creo
			{						
				printf("Non esiste il .o di %s\n", entry_list[i]->d_name);
				asprintf(&cmd, "gcc %s %s %s -c %s", argv[1], argv[2], argv[3], entry_list[i]->d_name);
				printf("%s\n", cmd);
				system_noshell(cmd);				
				free(cmd);
				cmd = NULL;
			}
			else	//caso esiste
			{
				stat(modify_format(entry_list[i]->d_name, 'o'), &info_o);
				if (info_c.st_mtime > info_o.st_mtime)		//non è ancora stato aggiornato
				{
					printf("Esiste il .o di %s, ma da aggiornare\n", entry_list[i]->d_name);
					unlink(modify_format(entry_list[i]->d_name, 'o')); //elimino il file per aggiornarlo(ne creo uno nuovo)
					asprintf(&cmd, "gcc %s %s %s -c %s", argv[1], argv[2], argv[3], entry_list[i]->d_name);
					printf("%s\n", cmd);
					system_noshell(cmd);				
					free(cmd);
					cmd = NULL;
				}
			}
		}
	}	
	return 0;
}

Esercizio 3

Il comando che dovrete implementare come script shell o programma python e' mytx.
Tale comando elenca tutti i file di una directory.
mytx ddd ddd.tx
Ogni riga del file di output (secondo parametro) deve contenere la lunghezza, uno spazio e il nume del file. Dopo l'ultima riga
deve inserire una riga bianca.
ddd.t2 deve contenere l'elenco dei file regolari. Il primo campo e' un numero intero seguito da uno spazio, tutto cio' che segue
fino alla fine riga e' il nome del file.
es.
12 file1
235 file di prova

Soluzione di Davide Quadrelli

#!/bin/bash
#Interpreto la richiesta del testo come segue:
#implementare mytx ddd ddd.tx ove ddd è una directory, ddd.tx è un file
#mytx deve elencare i file della directory ddd scrivere nel file ddd.tx di output una riga per file contenente
#la lunghezza del file, uno spazio e il nome del file. ddd.tx deve terminare con una riga bianca.

if [[ -d $1 ]] ; then
	ls $1
	old=`pwd`
	cd $1
	files=`ls`
	for var in $files ; do
		if [[ -f $var ]]; then
			wc -c ${var} 1>> ${old}/${2}
		fi
	done
	echo >> ${old}/${2}

else
	echo "inserire come primo parametro la directory e come secondo il file da scrivere"
fi