Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

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
@chkoreff authored
View
44 build
@@ -211,46 +211,6 @@ do
fi
done
-# Now create a couple of small C files which specify the base path name both
-# for the local and installed versions. We create the C files in the obj
-# directory to avoid modifying the src directory in any way.
-
-# We always create a fresh base_install.c because we don't want to use an old
-# one if you're installing in a different place now.
-
-rm -f obj/base_install.c
-
-for version in local install
-do
- base_dir=
- if [ "$version" = "install" ]; then
- base_dir=$current_place
- else
- base_dir=$pwd
- fi
-
- file_c=obj/base_$version.c
- file_o=obj/base_$version.o
-
- if [ ! -e $file_c ]; then
- echo "char *base = \"$base_dir\";" >$file_c
- run "gcc $cflags $file_c -o $file_o"
- fi
-done
-
-# Now we choose the version of base to link into the library depending on
-# whether we're doing a final install or just building locally.
-if [ $install -eq 1 ]; then
- base_o=obj/base_install.o
-else
- base_o=obj/base_local.o
-fi
-
-objects="$objects $base_o"
-if [ $update -eq 0 ]; then
- update=`newer_than $base_o $dir_lib/libfexl.so`
-fi
-
# Build the shared library. We use -ldl (libdl) for dlopen and dlsym.
# LATER jturner says he had to remove -ldl when building on OpenBSD.
# I should auto-detect that.
@@ -295,6 +255,10 @@ do
fi
if [ $update -eq 1 ]; then
+ # LATER 20120926 Possibly make it so we don't have to link directly
+ # with the library. We should be able to do this using get_base_path
+ # in conjunction with explicit dlopen, instead of passing 0 to dlsym in
+ # src/dynamic.c.
run "gcc $file_o -o $file_x $dir_lib/libfexl.so"
fi
done
View
6 src/base.h
@@ -1,6 +0,0 @@
-/*
-This is the base path of the Fexl executable program. Its actual value is not
-specified anywhere in the src directory, but is created by special logic in
-the build script, depending on whether we're doing a local or install build.
-*/
-extern char *base;
View
2  src/buf.c
@@ -45,7 +45,7 @@ void buf_add(struct buf **top, char ch)
}
/* Add a NUL-terminated string. */
-void buf_add_string(struct buf **top, char *str)
+void buf_add_string(struct buf **top, const char *str)
{
while (*str)
buf_add(top, *str++);
View
2  src/buf.h
@@ -7,6 +7,6 @@ struct buf
};
extern void buf_add(struct buf **top, char ch);
-extern void buf_add_string(struct buf **top, char *str);
+extern void buf_add_string(struct buf **top, const char *str);
extern char *buf_clear(struct buf **top, long *len);
extern void buf_discard(struct buf **top);
View
26 src/fexl.c
@@ -1,10 +1,7 @@
-#include "base.h"
-#include "buf.h"
#include "die.h"
-#include "memory.h"
-
#include "value.h"
#include "basic.h"
+#include "file.h"
#include "long.h"
#include "parse_file.h"
#include "resolve.h"
@@ -13,8 +10,7 @@
/*
Parse the top Fexl configuration file "base/share/fexl/main.fxl", where "base"
-is the base directory set by the build script: either `pwd` when building
-locally, or "/usr" when doing a final install.
+is the base directory of the running program.
Check the result of the parse, resolving all open symbols with the standard
"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.
*/
static value parse_top(void)
{
- char *top = "share/fexl/main.fxl";
+ value full_path = get_full_path("share/fexl/main.fxl");
+ hold(full_path);
- struct buf *buf = 0;
- buf_add_string(&buf, base);
- buf_add(&buf,'/');
- buf_add_string(&buf, top);
- long len;
- char *name = buf_clear(&buf,&len);
+ if (string_len(full_path) == 0)
+ {
+ warn("Can't locate the base path for the top level program.");
+ drop(full_path);
+ return 0;
+ }
+ char *name = string_data(full_path);
value result = parse_file(name);
hold(result);
@@ -67,7 +65,7 @@ static value parse_top(void)
symbols = symbols->R;
}
- free_memory(name, len+1);
+ drop(full_path);
drop(result);
if (!ok)
View
105 src/file.c
@@ -171,61 +171,42 @@ value const_stdin(void) { return Qfile_const(stdin); }
value const_stdout(void) { return Qfile_const(stdout); }
value const_stderr(void) { return Qfile_const(stderr); }
-/*
-Safely call readlink, returning a NUL-terminated result in a dynamically
-allocated buffer.
-
-Note that the size of the buffer is always a power of two. It doesn't have to
-be that way, but it feels right.
-*/
-void safe_readlink(const char *path,
- char **result, long *result_len, long *result_size)
+/* Call readlink, returning a Fexl string. */
+value safe_readlink(const char *path)
{
+ char *buf;
+ long len;
long size = 256;
+
while (1)
{
- char *link = new_memory(size);
- ssize_t len = readlink(path, link, size - 1);
- if (len == -1)
- {
- free_memory(link, size);
- *result = 0;
- *result_len = 0;
- *result_size = 0;
- return;
- }
- else if (len == size - 1)
+ buf = new_memory(size);
+ len = readlink(path, buf, size - 1);
+
+ if (len == size - 1)
{
- /* Assume the worst: the result might be truncated. */
- free_memory(link, size);
+ /* Used all available space, so the result might be truncated. */
+ free_memory(buf, size);
size = 2 * size;
}
else
{
- link[len] = 0;
- *result = link;
- *result_len = len;
- *result_size = size;
- return;
+ /* Used less than available space, so the result fits just fine.
+ A system error yields len == -1, but that works robustly. */
+ value result = Qcopy_chars(buf,len);
+ free_memory(buf, size);
+ return result;
}
}
}
-/* readlink path next = (next link), where link is the result of calling
+/* (readlink path next) = (next link), where link is the result of calling
readlink(2) on the path. */
static void reduce2_readlink(value f)
{
value x = arg(type_string,f->L->R);
char *path = string_data(x);
-
- char *buf;
- long len;
- long size;
- safe_readlink(path, &buf, &len, &size);
-
- value result = Qcopy_chars(buf,len);
- if (buf) free_memory(buf, size);
-
+ value result = safe_readlink(path);
replace_apply(f,f->R,result);
}
@@ -233,3 +214,53 @@ void reduce_readlink(value f)
{
f->T = reduce2_readlink;
}
+
+/*
+Get the base path of the currently running program, ending in "/". If we could
+not get the path due to a system error, return "".
+
+First we get the full path of the program, for example "/PATH/bin/fexl". This
+is equivalent to the $0 variable in the /bin/sh program. Then we strip off the
+last two legs of that path, returning "/PATH/".
+*/
+value get_base_path(void)
+ {
+ value full_path = safe_readlink("/proc/self/exe");
+ hold(full_path);
+
+ char *buf = string_data(full_path);
+ long len = string_len(full_path);
+
+ int i;
+ for (i = 0; i < 2; i++)
+ while (len > 0 && buf[--len] != '/')
+ ;
+
+ if (buf[len] == '/') len++; /* keep the slash */
+ value base_path = Qcopy_chars(buf,len);
+ drop(full_path);
+ return base_path;
+ }
+
+/* (base_path next) = (next path) where path is the base path of the current
+Fexl executable. */
+void reduce_base_path(value f)
+ {
+ replace_apply(f, f->R, get_base_path());
+ }
+
+/* Concatenate the base path and the name. */
+value get_full_path(const char *name)
+ {
+ value base_path = get_base_path();
+
+ if (string_len(base_path) == 0)
+ return base_path;
+ else
+ {
+ value full_path = Qstrcat(string_data(base_path),name);
+ hold(base_path);
+ drop(base_path);
+ return full_path;
+ }
+ }
View
5 src/file.h
@@ -1,2 +1,3 @@
-extern void safe_readlink(const char *path,
- char **result, long *result_len, long *result_size);
+extern value safe_readlink(const char *path);
+extern value get_base_path(void);
+extern value get_full_path(const char *name);
View
8 src/meta.c
@@ -4,7 +4,6 @@
#include <sys/types.h> /* pid_t */
#include <sys/wait.h> /* wait */
#include <unistd.h> /* fork */
-#include "base.h"
#include "memory.h"
#include "value.h"
#include "long.h"
@@ -54,13 +53,6 @@ void reduce_exit(value f)
exit(status);
}
-/* (base_path next) = (next path) where path is the base path of the current
-Fexl executable. */
-void reduce_base_path(value f)
- {
- replace_apply(f, f->R, Qstring(base));
- }
-
/* (fork next) = (next pid), where pid is the result of calling fork(2). */
void reduce_fork(value f)
{
View
12 src/string.c
@@ -1,5 +1,6 @@
#include <string.h>
#include <stdlib.h> /* strtol, strtod */
+#include "buf.h"
#include "die.h"
#include "memory.h"
#include "value.h"
@@ -75,6 +76,17 @@ value Qstring(const char *data)
return str;
}
+/* Concatenate two null-terminated strings. */
+value Qstrcat(const char *x, const char *y)
+ {
+ struct buf *buf = 0;
+ buf_add_string(&buf, x);
+ buf_add_string(&buf, y);
+ long len;
+ char *string = buf_clear(&buf,&len);
+ return Qchars(string,len);
+ }
+
/* Compare strings x and y, returning negative if x < y, zero if x == y, or
positive if x > y. */
static int string_cmp(value x, value y)
View
1  src/string.h
@@ -3,6 +3,7 @@ extern value Qchars(const char *data, long len);
extern value Qcopy_chars(const char *data, long len);
extern value Qcopy_string(const char *data);
extern value Qstring(const char *data);
+extern value Qstrcat(const char *x, const char *y);
extern char *string_data(value);
extern long string_len(value);
extern int string_eq(value, value);
Please sign in to comment.
Something went wrong with that request. Please try again.