Version: 0.3.0

* Preliminary autoconf support
* Switched to getopt()
* New option: -C (demangle C++ names)
* New options: --help, --version
* Display "format" (printf-like) argument types
* Updated manual page
* New option: -e
diff --git a/options.c b/options.c
index 0b556d8..fcec2a8 100644
--- a/options.c
+++ b/options.c
@@ -1,13 +1,22 @@
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
 #include <string.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <errno.h>
 #include <limits.h>
 
+#if HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
 #include "ltrace.h"
 #include "options.h"
 #include "defs.h"
 
+static char *progname;		/* Program name (`ltrace') */
 FILE * output;
 int opt_a = DEFAULT_ACOLUMN;	/* default alignment column for results */
 int opt_d = 0;			/* debug */
@@ -18,14 +27,70 @@
 int opt_f = 0;			/* trace child processes as they are created */
 char * opt_u = NULL;		/* username to run command as */
 int opt_t = 0;			/* print absolute timestamp */
+#if HAVE_LIBIBERTY
+int opt_C = 0;			/* Demangle low-level symbol names into user-level names */
+#endif
 
 /* List of pids given to option -p: */
 struct opt_p_t * opt_p = NULL;	/* attach to process with a given pid */
 
+/* List of function names given to option -e: */
+struct opt_e_t * opt_e = NULL;
+int opt_e_enable=1;
+
 static void usage(void)
 {
-	fprintf(stderr, "Usage: ltrace [-dfiLSttt] [-a column] [-s strlen] [-o filename]\n"
-			"              [-u username] [-p pid] ... [command [arg ...]]\n\n");
+#if !(HAVE_GETOPT || HAVE_GETOPT_LONG)
+	fprintf(stdout, "Usage: %s [command [arg ...]]\n"
+"Trace library calls of a given program.\n\n", progname);
+#else
+	fprintf(stdout, "Usage: %s [option ...] [command [arg ...]]\n"
+"Trace library calls of a given program.\n\n"
+
+# if HAVE_GETOPT_LONG
+"  -d, --debug         print debugging info.\n"
+# else
+"  -d                  print debugging info.\n"
+# endif
+"  -f                  follow forks.\n"
+"  -i                  print instruction pointer at time of library call.\n"
+"  -L                  do NOT display library calls.\n"
+"  -S                  display system calls.\n"
+"  -t, -tt, -ttt       print absolute timestamps.\n"
+# if HAVE_LIBIBERTY
+#  if HAVE_GETOPT_LONG
+"  -C, --demangle      decode low-level symbol names into user-level names.\n"
+#  else
+"  -C                  decode low-level symbol names into user-level names.\n"
+#  endif
+# endif
+# if HAVE_GETOPT_LONG
+"  -a, --align=COLUMN  align return values in a secific column.\n"
+# else
+"  -a COLUMN           align return values in a secific column.\n"
+# endif
+"  -s STRLEN           specify the maximum string size to print.\n"
+# if HAVE_GETOPT_LONG
+"  -o, --output=FILE   write the trace output to that file.\n"
+# else
+"  -o FILE             write the trace output to that file.\n"
+# endif
+"  -u USERNAME         run command with the userid, groupid of username.\n"
+"  -p PID              attach to the process with the process ID pid.\n"
+"  -e expr             modify which events to trace.\n"
+# if HAVE_GETOPT_LONG
+"  -h, --help          display this help and exit.\n"
+# else
+"  -h                  display this help and exit.\n"
+# endif
+# if HAVE_GETOPT_LONG
+"  -V, --version       output version information and exit.\n"
+# else
+"  -V                  output version information and exit.\n"
+# endif
+"\nReport bugs to Juan Cespedes <cespedes@debian.org>\n"
+		, progname);
+#endif
 }
 
 static char * search_for_command(char * filename)
@@ -58,19 +123,39 @@
 
 char ** process_options(int argc, char **argv)
 {
-	char *nextchar = NULL;
-
+	progname = argv[0];
 	output = stderr;
 
+#if HAVE_GETOPT || HAVE_GETOPT_LONG
 	while(1) {
-		if (!nextchar || !(*nextchar)) {
-			if (!argv[1] || argv[1][0] != '-' || !argv[1][1]) {
-				break;
-			}
-			nextchar = &argv[1][1];
-			argc--; argv++;
+		int c;
+#if HAVE_GETOPT_LONG
+		int option_index = 0;
+		static struct option long_options[] = {
+			{ "align", 1, 0, 'a'},
+			{ "debug", 0, 0, 'd'},
+			{ "demangle", 0, 0, 'C'},
+			{ "help", 0, 0, 'h'},
+			{ "output", 1, 0, 'o'},
+			{ "version", 0, 0, 'V'},
+			{ 0, 0, 0, 0}
+		};
+		c = getopt_long(argc, argv, "+dfiLSthV"
+# if HAVE_LIBIBERTY
+			"C"
+# endif
+			"a:s:o:u:p:e:", long_options, &option_index);
+#else
+		c = getopt(argc, argv, "+dfiLSth"
+# if HAVE_LIBIBERTY
+			"C"
+# endif
+			"a:s:o:u:p:e:");
+#endif
+		if (c==-1) {
+			break;
 		}
-		switch (*nextchar++) {
+		switch(c) {
 			case 'd':	opt_d++;
 					break;
 			case 'f':	opt_f = 1;
@@ -83,51 +168,104 @@
 					break;
 			case 't':	opt_t++;
 					break;
-			case 'a':	if (!argv[1]) { usage(); exit(1); }
-					opt_a = atoi(argv[1]);
-					argc--; argv++;
+#if HAVE_LIBIBERTY
+			case 'C':	opt_C++;
 					break;
-			case 's':	if (!argv[1]) { usage(); exit(1); }
-					opt_s = atoi(argv[1]);
-					argc--; argv++;
+#endif
+			case 'a':	opt_a = atoi(optarg);
 					break;
-			case 'o':	if (!argv[1]) { usage(); exit(1); }
-					output = fopen(argv[1], "w");
+			case 's':	opt_s = atoi(optarg);
+					break;
+			case 'h':	usage();
+					exit(0);
+			case 'o':	output = fopen(optarg, "w");
 					if (!output) {
-						fprintf(stderr, "Can't open %s for output: %s\n", argv[1], strerror(errno));
+						fprintf(stderr, "Can't open %s for output: %s\n", optarg, strerror(errno));
 						exit(1);
 					}
-					argc--; argv++;
 					break;
-			case 'u':	if (!argv[1]) { usage(); exit(1); }
-					opt_u = argv[1];
-					argc--; argv++;
+			case 'u':	opt_u = optarg;
 					break;
-			case 'p':	if (!argv[1]) { usage(); exit(1); }
+			case 'p':	
 				{
 					struct opt_p_t * tmp = malloc(sizeof(struct opt_p_t));
 					if (!tmp) {
 						perror("malloc");
 						exit(1);
 					}
-					tmp->pid = atoi(argv[1]);
+					tmp->pid = atoi(optarg);
 					tmp->next = opt_p;
 					opt_p = tmp;
-					argc--; argv++;
 					break;
 				}
-			default:	fprintf(stderr, "Unknown option '%c'\n", *(nextchar-1));
-					usage();
+			case 'e':
+				{
+					char * str_e = strdup(optarg);
+					if (!str_e) {
+						perror("strdup");
+						exit(1);
+					}
+					if (str_e[0]=='!') {
+						opt_e_enable=0;
+						str_e++;
+					}
+					while(*str_e) {
+						struct opt_e_t * tmp;
+						char *str2 = strchr(str_e,',');
+						if (str2) {
+							*str2 = '\0';
+						}
+						tmp = malloc(sizeof(struct opt_e_t));
+						if (!tmp) {
+							perror("malloc");
+							exit(1);
+						}
+						tmp->name = str_e;
+						tmp->next = opt_e;
+						opt_e = tmp;
+						if (str2) {
+							str_e = str2+1;
+						} else {
+							break;
+						}
+					}
+					break;
+				}
+			case 'V':	printf("ltrace version "
+#ifdef VERSION
+					VERSION
+#else
+					"???"
+#endif
+					".\n"
+"Copyright (C) 1997-1998 Juan Cespedes <cespedes@debian.org>.\n"
+"This is free software; see the GNU General Public Licence\n"
+"version 2 or later for copying conditions.  There is NO warranty.\n");
+					exit(0);
+
+			default:
+#if HAVE_GETOPT_LONG
+				fprintf(stderr, "Try `%s --help' for more information\n", progname);
+#else
+				fprintf(stderr, "Try `%s -h' for more information\n", progname);
+#endif
 					exit(1);
 		}
 	}
+	argc -= optind; argv += optind;
+#endif
 
-	if (!opt_p && argc<2) {
-		usage();
+	if (!opt_p && argc<1) {
+		fprintf(stderr, "%s: too few arguments\n", progname);
+#if HAVE_GETOPT_LONG
+		fprintf(stderr, "Try `%s --help' for more information\n", progname);
+#elif HAVE_GETOPT
+		fprintf(stderr, "Try `%s -h' for more information\n", progname);
+#endif
 		exit(1);
 	}
-	if (argc>1) {
-		command = search_for_command(argv[1]);
+	if (argc>0) {
+		command = search_for_command(argv[0]);
 	}
-	return &argv[1];
+	return &argv[0];
 }