Task: Globally replace text in several files

C: #include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <err.h>
#include <string.h>

char * find_match(const char *buf, const char * buf_end, const char *pat, size_t len)
{
	ptrdiff_t i;
	char *start = buf;
	while (start + len < buf_end) {
		for (i = 0; i < len; i++)
			if (start[i] != pat[i]) break;

		if (i == len) return (char *)start;
		start++;
	}
	return 0;
}

int replace(const char *from, const char *to, const char *fname)
{
#define bail(msg) { warn(msg" '%s'", fname); goto done; }
	struct stat st;
	int ret = 0;
	char *buf = 0, *start, *end;
	size_t len = strlen(from), nlen = strlen(to);
	int fd = open(fname, O_RDWR);

	if (fd == -1) bail("Can't open");
	if (fstat(fd, &st) == -1) bail("Can't stat");
	if (!(buf = malloc(st.st_size))) bail("Can't alloc");
	if (read(fd, buf, st.st_size) != st.st_size) bail("Bad read");

	start = buf;
	end = find_match(start, buf + st.st_size, from, len);
	if (!end) goto done; 

	ftruncate(fd, 0);
	lseek(fd, 0, 0);
	do {
		write(fd, start, end - start);	
		write(fd, to, nlen);		
		start = end + len;		
						
		end = find_match(start, buf + st.st_size, from, len);
	} while (end);

	
	if (start < buf + st.st_size)
		write(fd, start, buf + st.st_size - start);

done:
	if (fd != -1) close(fd);
	if (buf) free(buf);
	return ret;
}

int main()
{
	const char *from = "Goodbye, London!";
	const char *to   = "Hello, New York!";
	const char * files[] = { "test1.txt", "test2.txt", "test3.txt" };
	int i;

	for (i = 0; i < sizeof(files)/sizeof(char*); i++)
		replace(from, to, files[i]);

	return 0;
}











Ada: with Ada.Strings.Unbounded, Ada.Text_IO, Ada.Command_Line, Ada.Directories;

procedure Global_Replace is

   subtype U_String is Ada.Strings.Unbounded.Unbounded_String;
   function "+"(S: String) return U_String renames
     Ada.Strings.Unbounded.To_Unbounded_String;
   function "-"(U: U_String) return String renames
     Ada.Strings.Unbounded.To_String;

   procedure String_Replace(S: in out U_String; Pattern, Replacement: String) is
      
      
      

      Index : Natural;
   begin
      loop
         Index := Ada.Strings.Unbounded.Index(Source => S, Pattern => Pattern);
         exit when Index = 0;
         Ada.Strings.Unbounded.Replace_Slice
           (Source => S, Low => Index, High => Index+Pattern'Length-1,
            By => Replacement);
      end loop;
   end String_Replace;

   procedure File_Replace(Filename: String; Pattern, Replacement: String) is
      
      

      I_File, O_File: Ada.Text_IO.File_Type;
      Line: U_String;
      Tmp_Name: String := Filename & ".tmp"; 
         
   begin
      Ada.Text_IO.Open(I_File, Ada.Text_IO.In_File, Filename);
      Ada.Text_IO.Create(O_File, Ada.Text_IO.Out_File, Tmp_Name);
      while not Ada.Text_IO.End_Of_File(I_File) loop
         Line := +Ada.Text_IO.Get_Line(I_File);
         String_Replace(Line, Pattern, Replacement);
         Ada.Text_IO.Put_Line(O_File, -Line);
      end loop;
      Ada.Text_IO.Close(I_File);
      Ada.Text_IO.Close(O_File);
      Ada.Directories.Delete_File(Filename);
      Ada.Directories.Rename(Old_Name => Tmp_Name, New_Name => Filename);
   end File_Replace;

   Pattern:     String := Ada.Command_Line.Argument(1);
   Replacement: String :=  Ada.Command_Line.Argument(2);

begin
   Ada.Text_IO.Put_Line("Replacing """ & Pattern
                          & """ by """ & Replacement & """ in"
                          & Integer'Image(Ada.Command_Line.Argument_Count - 2)
                          & " files.");
   for I in 3 .. Ada.Command_Line.Argument_Count loop
      File_Replace(Ada.Command_Line.Argument(I), Pattern, Replacement);
   end loop;
end Global_Replace;