--- src/main.c.orig	Tue Dec  6 11:08:37 2005
+++ src/main.c	Tue Dec  6 12:30:23 2005
@@ -25,6 +25,7 @@
 #include <glib.h>
 #include <time.h>
 #include <stdio.h>
+#include <errno.h>
 #include <string.h>
 #include <unistd.h>
 #include <stdlib.h>
@@ -54,6 +55,9 @@
 
 char *filebase;
 char *fullfilebase;
+static char *outfilebase;
+static char *outfilehbase;
+static char *outfilephbase;
 static char *funcbase;
 static char *pfuncbase;
 static char *macrobase;
@@ -99,6 +103,7 @@
 FILE *outph = NULL;
 FILE *devnull = NULL;
 
+gboolean no_touch = FALSE;
 gboolean no_touch_headers = FALSE;
 gboolean for_cpp = FALSE;
 gboolean no_gnu = FALSE;
@@ -3045,14 +3050,11 @@
 {
 	char *outfile, *outfileh, *outfileph;
 
-	if ( ! for_cpp)
-		outfile = g_strconcat (fullfilebase, ".c", NULL);
-	else
-		outfile = g_strconcat (fullfilebase, ".cc", NULL);
-	if (no_touch_headers)
-		outfileh = g_strconcat (fullfilebase, ".h#gob#", NULL);
-	else
-		outfileh = g_strconcat (fullfilebase, ".h", NULL);
+	outfilebase = g_strconcat (fullfilebase, for_cpp ? ".cc" : ".c", NULL);
+	outfile = g_strconcat(outfilebase, no_touch ? "#gob#" : "", NULL);
+
+	outfilehbase = g_strconcat (fullfilebase, ".h");
+	outfileh = g_strconcat(outfilehbase, no_touch_headers ? "#gob#" : "", NULL);
 
 	if ((privates > 0 || protecteds > 0 ||
 	     private_header == PRIVATE_HEADER_ALWAYS) &&
@@ -3060,8 +3062,10 @@
 		char sep[2] = {0,0};
 		if (file_sep != 0)
 			sep[0] = file_sep;
-		outfileph = g_strconcat (fullfilebase, sep, "private.h", NULL);
+		outfilephbase = g_strconcat (fullfilebase, sep, "private.h", NULL);
+		outfileph = g_strconcat (outfilephbase, no_touch ? "#gob#" : "", NULL);
 	} else {
+		outfilephbase = NULL;
 		outfileph = NULL;
 	}
 
@@ -3675,16 +3679,13 @@
 static void
 print_file_comments(void)
 {
-	time_t curtime;
-	time(&curtime);
 	out_printf(outh, "/* Generated by GOB (v%s)"
 		   "   (do not edit directly) */\n\n", VERSION);
 	if(outph)
 		out_printf(outph, "/* Generated by GOB (v%s)"
 			   "   (do not edit directly) */\n\n", VERSION);
-	out_printf(out, "/* Generated by GOB (v%s) on %s"
-		   "   (do not edit directly) */\n\n",
-		   VERSION, ctime(&curtime));
+	out_printf(out, "/* Generated by GOB (v%s)"
+		   "   (do not edit directly) */\n\n", VERSION);
 
 	out_printf(out, "/* End world hunger, donate to the World Food Programme, http://www.wfp.org */\n\n");
 }
@@ -4075,6 +4076,9 @@
 		"\t--no-extern-c           Never print extern \"C\" into the "
 	       				  "header\n"
 		"\t--no-gnu                Never use GNU extentions\n"
+		"\t--no-touch              Don't touch output files unless they "
+		                          "really\n"
+		"\t                        changed (implies --no-touch-headers)\n"
 		"\t--no-touch-headers      Don't touch headers unless they "
 		                          "really changed\n"
 		"\t--always-private-header Always create a private header "
@@ -4172,6 +4176,9 @@
 			exit_on_warn = FALSE;
 		} else if(strcmp(argv[i], "--for-cpp")==0) {
 			for_cpp = TRUE;
+		} else if(strcmp(argv[i], "--no-touch")==0) {
+			no_touch = TRUE;
+			no_touch_headers = TRUE;
 		} else if(strcmp(argv[i], "--no-touch-headers")==0) {
 			no_touch_headers = TRUE;
 		} else if(strcmp(argv[i], "--ondemand-private-header")==0) {
@@ -4283,35 +4290,79 @@
 #endif
 }
 
-/* this is a somewhat ugly hack, but it appears to work */
 static void
-compare_and_move_header(void)
+compare_and_move (const char *old_filename)
 {
-	char *hfnew = g_strconcat(fullfilebase, ".h#gob#", NULL);
-	char *hf = g_strconcat(fullfilebase, ".h", NULL);
-	struct stat s;
-	if(stat(hf, &s) == 0) {
-		char *s;
-		s = g_strdup_printf("cmp '%s' '%s' > /dev/null", hf, hfnew);
-		if(system(s) == 0) {
-			if(unlink(hfnew) != 0)
-				error_printf(GOB_ERROR, 0,
-					     "Can't remove new header file");
-			g_free(hfnew);
-			g_free(hf);
-			g_free(s);
-			return;
+	char *new_filename = g_strconcat (old_filename, "#gob#", NULL);
+	FILE *old_f;
+	gboolean equal = FALSE;
+
+	old_f = fopen (old_filename, "r");
+	if (old_f) {
+		FILE *new_f;
+		gboolean error = FALSE;
+
+		new_f = fopen (new_filename, "r");
+		if (new_f) {
+			char new_buf[1024];
+			char old_buf[1024];
+
+			while (TRUE) {
+				size_t new_n;
+				size_t old_n;
+
+				new_n = fread (new_buf, 1, sizeof (new_buf), new_f);
+				if (ferror (new_f)) {
+					error = TRUE;
+					error_printf (GOB_ERROR, 0,
+						      "Can't read %s: %s",
+						      new_filename,
+						      g_strerror (errno));
+					break;
+				}
+
+				old_n = fread (old_buf, 1, sizeof (old_buf), old_f);
+				if (ferror (old_f)
+				    || feof (new_f) != feof (old_f)
+				    || new_n != old_n
+				    || memcmp (new_buf, old_buf, new_n) != 0)
+					break;
+
+				if (feof (new_f)) {
+					equal = TRUE;
+					break;
+				}
+			}
+		} else
+			error_printf (GOB_ERROR, 0, "Can't open %s: %s",
+				      new_filename, g_strerror (errno));
+
+		fclose (old_f);
+		fclose (new_f);
+
+		if (error)
+			goto end;
+
+		if (! equal && unlink (old_filename) != 0) {
+			error_printf (GOB_ERROR, 0, "Can't remove %s: %s",
+				      old_filename, g_strerror (errno));
+			goto end;
 		}
-		g_free(s);
-		if(unlink(hf) != 0)
-			error_printf(GOB_ERROR, 0,
-				     "Can't remove old header file");
-	}
-	if(rename(hfnew, hf) != 0)
-		error_printf(GOB_ERROR, 0,
-			     "Can't rename new header file");
-	g_free(hfnew);
-	g_free(hf);
+	}
+
+	if (equal) {
+		if (unlink (new_filename) != 0)
+			error_printf (GOB_ERROR, 0, "Can't remove %s: %s",
+				      new_filename, g_strerror (errno));
+	} else {
+		if (rename (new_filename, old_filename) != 0)
+			error_printf (GOB_ERROR, 0, "Can't rename %s to %s: %s",
+				      new_filename, old_filename,
+				      g_strerror (errno));
+	}
+
+ end:
+	g_free (new_filename);
 }
 
 int
@@ -4413,9 +4464,15 @@
 			fclose (outph);
 	}
 
-	if (no_touch_headers &&
-	    ! no_write)
-		compare_and_move_header ();
+	if (! no_write) {
+		if (no_touch) {
+			compare_and_move (outfilebase);
+			if (outfilephbase)
+				compare_and_move (outfilephbase);
+		}
+		if (no_touch_headers)
+			compare_and_move (outfilehbase);
+	}
 	
 	return 0;
 }

