Index: src/include/port.h
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/include/port.h,v
retrieving revision 1.108
diff -c -p -r1.108 port.h
*** src/include/port.h	11 Jan 2007 02:39:52 -0000	1.108
--- src/include/port.h	18 Jan 2007 17:12:47 -0000
*************** extern void get_man_path(const char *my_
*** 46,51 ****
--- 46,55 ----
  extern bool get_home_path(char *ret_path);
  extern void get_parent_directory(char *path);
  
+ /* port/dirmod.c */
+ extern char **pgfnames(char *path);
+ extern void pgfnames_cleanup(char **filenames);
+ 
  /*
   *	is_absolute_path
   *
Index: src/port/dirmod.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/port/dirmod.c,v
retrieving revision 1.46
diff -c -p -r1.46 dirmod.c
*** src/port/dirmod.c	5 Jan 2007 22:20:02 -0000	1.46
--- src/port/dirmod.c	18 Jan 2007 21:35:11 -0000
*************** pgsymlink(const char *oldpath, const cha
*** 287,298 ****
  
  
  /*
!  * fnames
   *
!  * return a list of the names of objects in the argument directory
   */
! static char **
! fnames(char *path)
  {
  	DIR		   *dir;
  	struct dirent *file;
--- 287,300 ----
  
  
  /*
!  * pgfnames
   *
!  * return a list of the names of objects in the argument directory.  Caller
!  * must call pgfnames_cleanup later to free the memory allocated by this
!  * function.
   */
! char **
! pgfnames(char *path)
  {
  	DIR		   *dir;
  	struct dirent *file;
*************** fnames(char *path)
*** 357,368 ****
  
  
  /*
!  *	fnames_cleanup
   *
   *	deallocate memory used for filenames
   */
! static void
! fnames_cleanup(char **filenames)
  {
  	char	  **fn;
  
--- 359,370 ----
  
  
  /*
!  *	pgfnames_cleanup
   *
   *	deallocate memory used for filenames
   */
! void
! pgfnames_cleanup(char **filenames)
  {
  	char	  **fn;
  
*************** rmtree(char *path, bool rmtopdir)
*** 394,400 ****
  	 * we copy all the names out of the directory before we start modifying
  	 * it.
  	 */
! 	filenames = fnames(path);
  
  	if (filenames == NULL)
  		return false;
--- 396,402 ----
  	 * we copy all the names out of the directory before we start modifying
  	 * it.
  	 */
! 	filenames = pgfnames(path);
  
  	if (filenames == NULL)
  		return false;
*************** rmtree(char *path, bool rmtopdir)
*** 415,421 ****
  			if (!rmtree(filepath, true))
  			{
  				/* we already reported the error */
! 				fnames_cleanup(filenames);
  				return false;
  			}
  		}
--- 417,423 ----
  			if (!rmtree(filepath, true))
  			{
  				/* we already reported the error */
! 				pgfnames_cleanup(filenames);
  				return false;
  			}
  		}
*************** rmtree(char *path, bool rmtopdir)
*** 433,439 ****
  			goto report_and_fail;
  	}
  
! 	fnames_cleanup(filenames);
  	return true;
  
  report_and_fail:
--- 435,441 ----
  			goto report_and_fail;
  	}
  
! 	pgfnames_cleanup(filenames);
  	return true;
  
  report_and_fail:
*************** report_and_fail:
*** 444,449 ****
  	fprintf(stderr, _("could not remove file or directory \"%s\": %s\n"),
  			filepath, strerror(errno));
  #endif
! 	fnames_cleanup(filenames);
  	return false;
  }
--- 446,451 ----
  	fprintf(stderr, _("could not remove file or directory \"%s\": %s\n"),
  			filepath, strerror(errno));
  #endif
! 	pgfnames_cleanup(filenames);
  	return false;
  }
Index: src/test/regress/GNUmakefile
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/test/regress/GNUmakefile,v
retrieving revision 1.63
diff -c -p -r1.63 GNUmakefile
*** src/test/regress/GNUmakefile	5 Jan 2007 22:20:03 -0000	1.63
--- src/test/regress/GNUmakefile	18 Jan 2007 21:37:01 -0000
*************** endif
*** 40,46 ****
  # stuff to pass into build of pg_regress
  EXTRADEFS = '-DHOST_TUPLE="$(host_tuple)"' \
  	'-DMAKEPROG="$(MAKE)"' \
! 	'-DSHELLPROG="$(SHELL)"'
  
  ##
  ## Prepare for tests
--- 40,47 ----
  # stuff to pass into build of pg_regress
  EXTRADEFS = '-DHOST_TUPLE="$(host_tuple)"' \
  	'-DMAKEPROG="$(MAKE)"' \
! 	'-DSHELLPROG="$(SHELL)"' \
! 	'-DDLSUFFIX="$(DLSUFFIX)"'
  
  ##
  ## Prepare for tests
*************** $(NAME)$(DLSUFFIX): $(shlib)
*** 83,96 ****
  	rm -f $(NAME)$(DLSUFFIX)
  	$(LN_S) $(shlib) $(NAME)$(DLSUFFIX)
  
! # Build test input and expected files
! 
! file_list := copy create_function_1 create_function_2 misc constraints tablespace
  input_files  := $(foreach file, $(file_list), sql/$(file).sql)
  output_files := $(foreach file, $(file_list), expected/$(file).out)
  
- all: $(input_files) $(output_files)
- 
  ifneq ($(PORTNAME),win32)
  abs_srcdir := $(shell cd $(srcdir) && pwd)
  abs_builddir := $(shell pwd)
--- 84,95 ----
  	rm -f $(NAME)$(DLSUFFIX)
  	$(LN_S) $(shlib) $(NAME)$(DLSUFFIX)
  
! # Test input and expected files.  These are created by pg_regress itself, so we
! # don't have a rule to create them.  We do need rules to clean them however.
! file_list := $(subst .source,, $(notdir $(wildcard $(top_srcdir)/$(subdir)/input/*.source)))
  input_files  := $(foreach file, $(file_list), sql/$(file).sql)
  output_files := $(foreach file, $(file_list), expected/$(file).out)
  
  ifneq ($(PORTNAME),win32)
  abs_srcdir := $(shell cd $(srcdir) && pwd)
  abs_builddir := $(shell pwd)
*************** abs_srcdir := $(shell cd $(srcdir) && pw
*** 99,120 ****
  abs_builddir := $(shell pwd -W)
  endif
  
- testtablespace := $(abs_builddir)/testtablespace
- 
- 
- define sed-command
- sed -e 's,@abs_srcdir@,$(abs_srcdir),g' \
-     -e 's,@abs_builddir@,$(abs_builddir),g' \
-     -e 's,@testtablespace@,$(testtablespace),g' \
-     -e 's/@DLSUFFIX@/$(DLSUFFIX)/g' $< >$@
- endef
- 
- $(input_files): sql/%.sql: input/%.source
- 	$(sed-command)
- 
- $(output_files): expected/%.out: output/%.source
- 	$(sed-command)
- 
  # When doing a VPATH build, copy over the remaining .sql and .out
  # files so that the driver script can find them.  We have to use an
  # absolute path for the targets, because otherwise make will try to
--- 98,103 ----
*************** all-spi:
*** 148,154 ****
  check: all
  	-rm -rf ./testtablespace
  	mkdir ./testtablespace
! 	./pg_regress --temp-install=./tmp_check --top-builddir=$(top_builddir) --temp-port=$(TEMP_PORT) --schedule=$(srcdir)/parallel_schedule --multibyte=$(MULTIBYTE) --load-language=plpgsql $(MAXCONNOPT) $(NOLOCALE)
  
  installcheck: all
  	-rm -rf ./testtablespace
--- 131,137 ----
  check: all
  	-rm -rf ./testtablespace
  	mkdir ./testtablespace
! 	./pg_regress --temp-install=./tmp_check --top-builddir=$(top_builddir) --srcdir=$(abs_srcdir) --temp-port=$(TEMP_PORT) --schedule=$(srcdir)/parallel_schedule --multibyte=$(MULTIBYTE) --load-language=plpgsql $(MAXCONNOPT) $(NOLOCALE)
  
  installcheck: all
  	-rm -rf ./testtablespace
Index: src/test/regress/pg_regress.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/test/regress/pg_regress.c,v
retrieving revision 1.25
diff -c -p -r1.25 pg_regress.c
*** src/test/regress/pg_regress.c	5 Jan 2007 22:20:03 -0000	1.25
--- src/test/regress/pg_regress.c	18 Jan 2007 20:43:14 -0000
*************** static char *psqldir = NULL;
*** 95,100 ****
--- 95,101 ----
  static char *hostname = NULL;
  static int	port = -1;
  static char *user = NULL;
+ static char *srcdir = NULL;
  
  /* internal variables */
  static const char *progname;
*************** static int	success_count = 0;
*** 111,116 ****
--- 112,122 ----
  static int	fail_count = 0;
  static int	fail_ignore_count = 0;
  
+ static bool
+ directory_exists(const char *dir);
+ static void
+ make_directory(const char *dir);
+ 
  static void
  header(const char *fmt,...)
  /* This extension allows gcc to check the format string for consistency with
*************** string_matches_pattern(const char *str, 
*** 331,336 ****
--- 337,477 ----
  }
  
  /*
+  * Replace all occurances of a string in a string with a different string.
+  * NOTE: Assumes there is enough room in the target buffer!
+  */
+ static void
+ replace_string(char *string, char *replace, char *replacement)
+ {
+ 	char *ptr;
+ 
+ 	while ((ptr = strstr(string, replace)) != NULL) 
+ 	{
+ 		char *dup = strdup(string);
+ 
+ 		strncpy(string, dup, ptr - string);
+ 		string[ptr - string] = 0;
+ 		strcat(string, replacement);
+ 		strcat(string, dup + (ptr - string) + strlen(replace));
+ 		free(dup);
+ 	}
+ }
+ 
+ /*
+  * Convert *.source found in the "source" directory, replacing certain tokens
+  * in the file contents with their intended values, and put the resulting files
+  * in the "dest" directory, replacing the ".source" prefix in their names with
+  * the given suffix.
+  */
+ static void
+ convert_sourcefiles_in(char *source, char *dest, char *suffix)
+ {
+ 	char abs_srcdir[MAXPGPATH];
+ 	char abs_builddir[MAXPGPATH];
+ 	char testtablespace[MAXPGPATH];
+ 	char indir[MAXPGPATH];
+ 	char **name;
+ 	char **names;
+ #ifdef WIN32
+ 	char *c;
+ #endif
+ 
+ 	if (!getcwd(abs_builddir, sizeof(abs_builddir)))
+ 	{
+ 		fprintf(stderr, _("%s: could not get current directory: %s\n"),
+ 			progname, strerror(errno));
+ 		exit_nicely(2);
+ 	}
+ 
+ 	/*
+ 	 * in a VPATH build, use the provided source directory; otherwise, use
+ 	 * the current directory.
+ 	 */
+ 	if (srcdir)
+ 		strcpy(abs_srcdir, srcdir);
+ 	else
+ 		strcpy(abs_srcdir, abs_builddir);
+ 
+ 	snprintf(indir, MAXPGPATH, "%s/%s", abs_srcdir, source);
+ 	names = pgfnames(indir);
+ 	if (!names)
+ 		/* Error logged in pgfnames */
+ 		exit_nicely(2);
+ 
+ #ifdef WIN32
+ 	/* in Win32, replace backslashes with forward slashes */
+ 	for (c = abs_builddir; *c; c++)
+ 		if (*c == '\\')
+ 			*c = '/';
+ 	for (c = abs_srcdir; *c; c++)
+ 		if (*c == '\\')
+ 			*c = '/';
+ #endif
+ 
+ 	/* try to create the test tablespace dir if it doesn't exist */
+ 	snprintf(testtablespace, MAXPGPATH, "%s/testtablespace", abs_builddir);
+ 	if (directory_exists(testtablespace))
+ 		rmtree(testtablespace, true);
+ 	make_directory(testtablespace);
+ 
+ 	/* finally loop on each file and do the replacement */
+ 	for (name = names; *name; name++)
+ 	{
+ 		char	srcfile[MAXPGPATH];
+ 		char	destfile[MAXPGPATH];
+ 		char	prefix[MAXPGPATH];
+ 		FILE   *infile,
+ 			   *outfile;
+ 		char	line[1024];
+ 
+ 		/* reject filenames not finishing in ".source" */
+ 		if (strlen(*name) < 8)
+ 			continue;
+ 		if (strcmp(*name + strlen(*name) - 7, ".source") != 0)
+ 			continue;
+ 
+ 		/* build the full actual paths to open */
+ 		snprintf(prefix, strlen(*name) - 6, "%s", *name);
+ 		snprintf(srcfile, MAXPGPATH, "%s/%s", indir, *name);
+ 		snprintf(destfile, MAXPGPATH, "%s/%s.%s", dest, prefix, suffix);
+ 
+ 		infile = fopen(srcfile, "r");
+ 		if (!infile)
+ 		{
+ 			fprintf(stderr, _("%s: could not open file \"%s\" for reading: %s\n"),
+ 					progname, srcfile, strerror(errno));
+ 			exit_nicely(2);
+ 		}
+ 		outfile = fopen(destfile, "w");
+ 		if (!outfile)
+ 		{
+ 			fprintf(stderr, _("%s: could not open file \"%s\" for writing: %s\n"),
+ 				progname, destfile, strerror(errno));
+ 			exit_nicely(2);
+ 		}
+ 		while (fgets(line, sizeof(line), infile))
+ 		{
+ 			replace_string(line, "@abs_srcdir@", abs_srcdir);
+ 			replace_string(line, "@abs_builddir@", abs_builddir);
+ 			replace_string(line, "@testtablespace@", testtablespace);
+ 			replace_string(line, "@DLSUFFIX@", DLSUFFIX);
+ 			fputs(line, outfile);
+ 		}
+ 		fclose(infile);
+ 		fclose(outfile);
+ 	}
+ 	
+     pgfnames_cleanup(names);
+ }
+ 
+ static void
+ convert_sourcefiles(void)
+ {
+ 	convert_sourcefiles_in("input", "sql", "sql");
+ 	convert_sourcefiles_in("output", "expected", "out");
+ }
+ 
+ /*
   * Scan resultmap file to find which platform-specific expected files to use.
   *
   * The format of each line of the file is
*************** initialize_environment(void)
*** 593,598 ****
--- 734,740 ----
  			printf(_("(using postmaster on Unix socket, default port)\n"));
  	}
  
+ 	convert_sourcefiles();
  	load_resultmap();
  }
  
*************** help(void)
*** 1322,1327 ****
--- 1464,1470 ----
  	printf(_("  --outputdir=DIR           place output files in DIR (default \".\")\n"));
  	printf(_("  --schedule=FILE           use test ordering schedule from FILE\n"));
  	printf(_("                            (may be used multiple times to concatenate)\n"));
+ 	printf(_("  --srcdir=DIR              absolute path to source directory (for VPATH builds)\n"));
  	printf(_("  --temp-install=DIR        create a temporary installation in DIR\n"));
  	printf(_("  --no-locale               use C locale\n"));
  	printf(_("\n"));
*************** main(int argc, char *argv[])
*** 1369,1374 ****
--- 1512,1518 ----
  		{"port", required_argument, NULL, 14},
  		{"user", required_argument, NULL, 15},
  		{"psqldir", required_argument, NULL, 16},
+ 		{"srcdir", required_argument, NULL, 17},
  		{NULL, 0, NULL, 0}
  	};
  
*************** main(int argc, char *argv[])
*** 1461,1466 ****
--- 1605,1613 ----
  				if (strlen(optarg))
  					psqldir = strdup(optarg);
  				break;
+ 			case 17:
+ 				srcdir = strdup(optarg);
+ 				break;
  			default:
  				/* getopt_long already emitted a complaint */
  				fprintf(stderr, _("\nTry \"%s -h\" for more information.\n"),
