Sostituzione di stringhe

Esercizio: scrivere un programma che prende tre argomenti, i cui primi due sono stringhe e il terzo e il nome di un file. Questo programma deve controllare se nel file appare la prima stringa. Se appare, al suo posto deve mettere la seconda stringa. Occorre controllare che le due stringhe siano uguali.

L'esercizio si risolve in questo modo: si legge una stringa da file (ossia un array di caratteri) e lo si confronta con quello da sostituire. Se sono uguali, si riporta la posizione all'interno del file al punto in cui inizia la stringa letta, e si scrive la nuova stringa. Si passa poi a leggere la stringa che inizia alla posizione successiva del file.

Il ciclo di lettura delle stringhe si può riassumere nel seguente modo:

while(1) {
  memorizza posizione;
  leggi stringa;
  se non ci sono abbastanza caratteri su file, esci dal ciclo

  confronta stringa con la stringa da cercare;
  passa alla posizione +1;
}

Il punto fondamentale è che occorre controllare sia la stringa che parte dalla posizione 0 che quella che parte dalla posizione 1, 2, ecc. Se ci limitiamo a leggere senza riposizionare, avremmo solo la stringa che parte da 0, poi quella che segue, ecc. Per esempio, se la stringa da cercare è lunga 10 caratteri, avremmo fatto il controllo solo sulla stringa che parte dalla posizione 0, poi dalla posizione 10, poi 20, ecc, e quindi non ci saremmo accorti se la stringa era presente ma partiva per esempio dalla posizione 4.

Una volta letta la stringa, possiamo usare la funzione memcmp. Questa funzione verifica che due array siano uguali fino all'n-esimo elemento, dove n è il terzo parametro della funzione. Nel caso in cui le due zone siano uguali, ritorniamo alla posizione nel file prima della lettura, e scriviamo la nuova stringa.

Per controllare il corretto funzionamento del programma subst.c si può verificare cosa succede quando la stringa non viene trovata, oppure viene trovato solo un frammento iniziale, oppure viene trovata tutta, e quindi sostituita.

/*
  Sostituisce una stringa con un'altra,
in un file binario.
*/

#include<stdlib.h>
#include<stdio.h>

int main(int argn, char *argv[]) {
  FILE *fd;
  int res;
  char *letto;
  int len;
  int i, j;
  int trovato;
  int pos, temp;


  		/* controllo argomenti */
  if( argn-1!=3 ) {
    printf("Uso: subst stringa stringa file\n");
    printf("Sostituisce la prima stringa con la seconda\n");
    exit(1);
  }

  if( strlen(argv[1]) != strlen(argv[2]) ) {
    printf("Le due stringhe devono avere la stessa lunghezza\n");
    exit(1);
  }

  len=strlen(argv[1]);

  letto=malloc(len);

  printf("Sostituzione %s --> %s in %s\n", argv[1], argv[2], argv[3]);


		/* apre il file */
  fd=fopen(argv[3], "r+");
  if( fd==NULL ) {
    perror("Opening file");
    exit(1);
  }


		/* ciclo di lettura */
  while(1) {

		/* memorizza la posizione */
    pos=ftell(fd);


		/* legge una stringa */
    res=fread(letto, sizeof(char), len, fd);
    if( res<len )
      break;


		/* confronto ed eventuale sostituzione */
    if( ! memcmp(argv[1], letto, len) ) {
      fseek(fd, pos, SEEK_SET);
      fwrite(argv[2], sizeof(char), len, fd);
    }


		/* posizione avanzata di uno */ 
    fseek(fd, pos+1, SEEK_SET);
  }


		/* chiude il file */
  fclose(fd);
  return 0;
}