Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Getting base path dynamically so I don't need to build into the program.

Formerly I had logic in the build script to create stub .c files (in the obj
directory) containing the base path of the program.  Now I get it dynamically
using /proc/self/exe.  This is equivalent to the $0 in the /bin/sh program.
See get_base_path in file.c.  This is good preparation for possibly removing
the direct linkage with the libfexl.so library, instead treating it like any
other independent library such as openssl.

I moved reduce_base_path from meta.c to file.c so it's closer to other things
related to readlink.

Note also how in fexl.c I'm using Fexl strings when building the full path
instead of calling buf operations directly.  Using Fexl strings avoids much of
the tedium of string manipulation, and makes things more clearly correct.

For another example of this, look how much simpler the safe_readlink routine is
in file.c, now that it returns a Fexl string instead of setting complicated
pointers passed in as arguments.  This also made reduce2_readlink far simpler.
  • Loading branch information...
commit 855ce18a94673e60acea7efda0e2b348cf49b149 1 parent 943d69e
Patrick Chkoreff authored
44  build
@@ -211,46 +211,6 @@ do
211 211
 	fi
212 212
 done
213 213
 
214  
-# Now create a couple of small C files which specify the base path name both
215  
-# for the local and installed versions.  We create the C files in the obj
216  
-# directory to avoid modifying the src directory in any way.
217  
-
218  
-# We always create a fresh base_install.c because we don't want to use an old
219  
-# one if you're installing in a different place now.
220  
-
221  
-rm -f obj/base_install.c
222  
-
223  
-for version in local install
224  
-do
225  
-	base_dir=
226  
-	if [ "$version" = "install" ]; then
227  
-		base_dir=$current_place
228  
-	else
229  
-		base_dir=$pwd
230  
-	fi
231  
-
232  
-	file_c=obj/base_$version.c
233  
-	file_o=obj/base_$version.o
234  
-
235  
-	if [ ! -e $file_c ]; then
236  
-		echo "char *base = \"$base_dir\";" >$file_c
237  
-		run "gcc $cflags $file_c -o $file_o"
238  
-	fi
239  
-done
240  
-
241  
-# Now we choose the version of base to link into the library depending on
242  
-# whether we're doing a final install or just building locally.
243  
-if [ $install -eq 1 ]; then
244  
-	base_o=obj/base_install.o
245  
-else
246  
-	base_o=obj/base_local.o
247  
-fi
248  
-
249  
-objects="$objects $base_o"
250  
-if [ $update -eq 0 ]; then
251  
-	update=`newer_than $base_o $dir_lib/libfexl.so`
252  
-fi
253  
-
254 214
 # Build the shared library.  We use -ldl (libdl) for dlopen and dlsym.
255 215
 # LATER jturner says he had to remove -ldl when building on OpenBSD.
256 216
 # I should auto-detect that.
@@ -295,6 +255,10 @@ do
295 255
 	fi
296 256
 
297 257
 	if [ $update -eq 1 ]; then
  258
+		# LATER 20120926 Possibly make it so we don't have to link directly
  259
+		# with the library.  We should be able to do this using get_base_path
  260
+		# in conjunction with explicit dlopen, instead of passing 0 to dlsym in
  261
+		# src/dynamic.c.
298 262
 		run "gcc $file_o -o $file_x $dir_lib/libfexl.so"
299 263
 	fi
300 264
 done
6  src/base.h
... ...
@@ -1,6 +0,0 @@
1  
-/*
2  
-This is the base path of the Fexl executable program.  Its actual value is not
3  
-specified anywhere in the src directory, but is created by special logic in
4  
-the build script, depending on whether we're doing a local or install build.
5  
-*/
6  
-extern char *base;
2  src/buf.c
@@ -45,7 +45,7 @@ void buf_add(struct buf **top, char ch)
45 45
 	}
46 46
 
47 47
 /* Add a NUL-terminated string. */
48  
-void buf_add_string(struct buf **top, char *str)
  48
+void buf_add_string(struct buf **top, const char *str)
49 49
 	{
50 50
 	while (*str)
51 51
 		buf_add(top, *str++);
2  src/buf.h
@@ -7,6 +7,6 @@ struct buf
7 7
 	};
8 8
 
9 9
 extern void buf_add(struct buf **top, char ch);
10  
-extern void buf_add_string(struct buf **top, char *str);
  10
+extern void buf_add_string(struct buf **top, const char *str);
11 11
 extern char *buf_clear(struct buf **top, long *len);
12 12
 extern void buf_discard(struct buf **top);
26  src/fexl.c
... ...
@@ -1,10 +1,7 @@
1  
-#include "base.h"
2  
-#include "buf.h"
3 1
 #include "die.h"
4  
-#include "memory.h"
5  
-
6 2
 #include "value.h"
7 3
 #include "basic.h"
  4
+#include "file.h"
8 5
 #include "long.h"
9 6
 #include "parse_file.h"
10 7
 #include "resolve.h"
@@ -13,8 +10,7 @@
13 10
 
14 11
 /*
15 12
 Parse the top Fexl configuration file "base/share/fexl/main.fxl", where "base"
16  
-is the base directory set by the build script:  either `pwd` when building
17  
-locally, or "/usr" when doing a final install.
  13
+is the base directory of the running program.
18 14
 
19 15
 Check the result of the parse, resolving all open symbols with the standard
20 16
 "resolve" function.  Report any errors, including syntax errors and undefined
@@ -22,15 +18,17 @@ symbols.  Return an evaluable function if all went well, or 0 otherwise.
22 18
 */
23 19
 static value parse_top(void)
24 20
 	{
25  
-	char *top = "share/fexl/main.fxl";
  21
+	value full_path = get_full_path("share/fexl/main.fxl");
  22
+	hold(full_path);
26 23
 
27  
-	struct buf *buf = 0;
28  
-	buf_add_string(&buf, base);
29  
-	buf_add(&buf,'/');
30  
-	buf_add_string(&buf, top);
31  
-	long len;
32  
-	char *name = buf_clear(&buf,&len);
  24
+	if (string_len(full_path) == 0)
  25
+		{
  26
+		warn("Can't locate the base path for the top level program.");
  27
+		drop(full_path);
  28
+		return 0;
  29
+		}
33 30
 
  31
+	char *name = string_data(full_path);
34 32
 	value result = parse_file(name);
35 33
 	hold(result);
36 34
 
@@ -67,7 +65,7 @@ static value parse_top(void)
67 65
 		symbols = symbols->R;
68 66
 		}
69 67
 
70  
-	free_memory(name, len+1);
  68
+	drop(full_path);
71 69
 	drop(result);
72 70
 
73 71
 	if (!ok)
105  src/file.c
@@ -171,61 +171,42 @@ value const_stdin(void)  { return Qfile_const(stdin); }
171 171
 value const_stdout(void) { return Qfile_const(stdout); }
172 172
 value const_stderr(void) { return Qfile_const(stderr); }
173 173
 
174  
-/*
175  
-Safely call readlink, returning a NUL-terminated result in a dynamically
176  
-allocated buffer.
177  
-
178  
-Note that the size of the buffer is always a power of two.  It doesn't have to
179  
-be that way, but it feels right.
180  
-*/
181  
-void safe_readlink(const char *path,
182  
-	char **result, long *result_len, long *result_size)
  174
+/* Call readlink, returning a Fexl string. */
  175
+value safe_readlink(const char *path)
183 176
 	{
  177
+	char *buf;
  178
+	long len;
184 179
 	long size = 256;
  180
+
185 181
 	while (1)
186 182
 		{
187  
-		char *link = new_memory(size);
188  
-		ssize_t len = readlink(path, link, size - 1);
189  
-		if (len == -1)
190  
-			{
191  
-			free_memory(link, size);
192  
-			*result = 0;
193  
-			*result_len = 0;
194  
-			*result_size = 0;
195  
-			return;
196  
-			}
197  
-		else if (len == size - 1)
  183
+		buf = new_memory(size);
  184
+		len = readlink(path, buf, size - 1);
  185
+
  186
+		if (len == size - 1)
198 187
 			{
199  
-			/* Assume the worst:  the result might be truncated. */
200  
-			free_memory(link, size);
  188
+			/* Used all available space, so the result might be truncated. */
  189
+			free_memory(buf, size);
201 190
 			size = 2 * size;
202 191
 			}
203 192
 		else
204 193
 			{
205  
-			link[len] = 0;
206  
-			*result = link;
207  
-			*result_len = len;
208  
-			*result_size = size;
209  
-			return;
  194
+			/* Used less than available space, so the result fits just fine.
  195
+			A system error yields len == -1, but that works robustly. */
  196
+			value result = Qcopy_chars(buf,len);
  197
+			free_memory(buf, size);
  198
+			return result;
210 199
 			}
211 200
 		}
212 201
 	}
213 202
 
214  
-/* readlink path next = (next link), where link is the result of calling
  203
+/* (readlink path next) = (next link), where link is the result of calling
215 204
 readlink(2) on the path. */
216 205
 static void reduce2_readlink(value f)
217 206
 	{
218 207
 	value x = arg(type_string,f->L->R);
219 208
 	char *path = string_data(x);
220  
-
221  
-	char *buf;
222  
-	long len;
223  
-	long size;
224  
-	safe_readlink(path, &buf, &len, &size);
225  
-
226  
-	value result = Qcopy_chars(buf,len);
227  
-	if (buf) free_memory(buf, size);
228  
-
  209
+	value result = safe_readlink(path);
229 210
 	replace_apply(f,f->R,result);
230 211
 	}
231 212
 
@@ -233,3 +214,53 @@ void reduce_readlink(value f)
233 214
 	{
234 215
 	f->T = reduce2_readlink;
235 216
 	}
  217
+
  218
+/*
  219
+Get the base path of the currently running program, ending in "/".  If we could
  220
+not get the path due to a system error, return "".
  221
+
  222
+First we get the full path of the program, for example "/PATH/bin/fexl".  This
  223
+is equivalent to the $0 variable in the /bin/sh program.  Then we strip off the
  224
+last two legs of that path, returning "/PATH/".
  225
+*/
  226
+value get_base_path(void)
  227
+	{
  228
+	value full_path = safe_readlink("/proc/self/exe");
  229
+	hold(full_path);
  230
+
  231
+	char *buf = string_data(full_path);
  232
+	long len = string_len(full_path);
  233
+
  234
+	int i;
  235
+	for (i = 0; i < 2; i++)
  236
+		while (len > 0 && buf[--len] != '/')
  237
+			;
  238
+
  239
+	if (buf[len] == '/') len++;  /* keep the slash */
  240
+	value base_path = Qcopy_chars(buf,len);
  241
+	drop(full_path);
  242
+	return base_path;
  243
+	}
  244
+
  245
+/* (base_path next) = (next path) where path is the base path of the current
  246
+Fexl executable. */
  247
+void reduce_base_path(value f)
  248
+	{
  249
+	replace_apply(f, f->R, get_base_path());
  250
+	}
  251
+
  252
+/* Concatenate the base path and the name. */
  253
+value get_full_path(const char *name)
  254
+	{
  255
+	value base_path = get_base_path();
  256
+
  257
+	if (string_len(base_path) == 0)
  258
+		return base_path;
  259
+	else
  260
+		{
  261
+		value full_path = Qstrcat(string_data(base_path),name);
  262
+		hold(base_path);
  263
+		drop(base_path);
  264
+		return full_path;
  265
+		}
  266
+	}
5  src/file.h
... ...
@@ -1,2 +1,3 @@
1  
-extern void safe_readlink(const char *path,
2  
-	char **result, long *result_len, long *result_size);
  1
+extern value safe_readlink(const char *path);
  2
+extern value get_base_path(void);
  3
+extern value get_full_path(const char *name);
8  src/meta.c
@@ -4,7 +4,6 @@
4 4
 #include <sys/types.h> /* pid_t */
5 5
 #include <sys/wait.h> /* wait */
6 6
 #include <unistd.h> /* fork */
7  
-#include "base.h"
8 7
 #include "memory.h"
9 8
 #include "value.h"
10 9
 #include "long.h"
@@ -54,13 +53,6 @@ void reduce_exit(value f)
54 53
 	exit(status);
55 54
 	}
56 55
 
57  
-/* (base_path next) = (next path) where path is the base path of the current
58  
-Fexl executable. */
59  
-void reduce_base_path(value f)
60  
-	{
61  
-	replace_apply(f, f->R, Qstring(base));
62  
-	}
63  
-
64 56
 /* (fork next) = (next pid), where pid is the result of calling fork(2). */
65 57
 void reduce_fork(value f)
66 58
 	{
12  src/string.c
... ...
@@ -1,5 +1,6 @@
1 1
 #include <string.h>
2 2
 #include <stdlib.h> /* strtol, strtod */
  3
+#include "buf.h"
3 4
 #include "die.h"
4 5
 #include "memory.h"
5 6
 #include "value.h"
@@ -75,6 +76,17 @@ value Qstring(const char *data)
75 76
 	return str;
76 77
 	}
77 78
 
  79
+/* Concatenate two null-terminated strings. */
  80
+value Qstrcat(const char *x, const char *y)
  81
+	{
  82
+	struct buf *buf = 0;
  83
+	buf_add_string(&buf, x);
  84
+	buf_add_string(&buf, y);
  85
+	long len;
  86
+	char *string = buf_clear(&buf,&len);
  87
+	return Qchars(string,len);
  88
+	}
  89
+
78 90
 /* Compare strings x and y, returning negative if x < y, zero if x == y, or
79 91
 positive if x > y. */
80 92
 static int string_cmp(value x, value y)
1  src/string.h
@@ -3,6 +3,7 @@ extern value Qchars(const char *data, long len);
3 3
 extern value Qcopy_chars(const char *data, long len);
4 4
 extern value Qcopy_string(const char *data);
5 5
 extern value Qstring(const char *data);
  6
+extern value Qstrcat(const char *x, const char *y);
6 7
 extern char *string_data(value);
7 8
 extern long string_len(value);
8 9
 extern int string_eq(value, value);

0 notes on commit 855ce18

Please sign in to comment.
Something went wrong with that request. Please try again.