Command line patch

James LewisMoss dres@phoenixdsl.com
11 Dec 2000 01:09:47 -0500


--=-=-=

This is a patch and two files.  Both files go in src/guile.  Someone
please look over this patch and see if everything looks ok.  Basically
the patch
1) Renames gnucash:*command-line-files* to
   gnucash:*command-line-remaining*
2) changes to the gnome top-level to parse the command line arguments
   that the gnucash scheme code didn't recognize.  Also placing the
   unused arguments from the gnome side back to the scheme side (so a
   filename on the command line still works).
3) changes to command-line.scm to not error on an unknown argument and
   to save everything unused.  There is some commented out code in
   this file to use the guile getopt-long functionality, but it
   doesn't work currently.  Maybe should be removed.  What's the
   normal practice here?
4) changes to main.scm to not load the file here, but wait for the
   gnome side to request it.

Two files to do the scm list to argv list changes.  These functions
are not generalized to any foo** list, but only char** lists.

Jim

Index: src/gnome/top-level.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/gnome/top-level.c,v
retrieving revision 1.54
diff -u -b -r1.54 top-level.c
--- src/gnome/top-level.c	2000/12/05 10:36:18	1.54
+++ src/gnome/top-level.c	2000/12/11 05:39:33
@@ -28,6 +28,7 @@
 #include <guile/gh.h>
 #include <gnome.h>
 #include <gtkhtml/gtkhtml.h>
+#include <popt.h>
 
 #include "g-wrap.h"
 #include "gnc.h"
@@ -60,8 +61,8 @@
 #include "splitreg.h"
 #include "combocell.h"
 #include "recncell.h"
+#include "argv-list-converters.h"
 
-
 /** PROTOTYPES ******************************************************/
 static void gnc_configure_date_format_cb(void *);
 static void gnc_configure_date_format(void);
@@ -133,6 +134,23 @@
   return app;
 }
 
+static const char* gnc_scheme_remaining_var = "gnc:*command-line-remaining*";
+
+static char**
+gnc_get_remaining_argv(int prelen, const char **prependargv)
+{
+    SCM rem = gh_lookup(gnc_scheme_remaining_var);
+    return gnc_scheme_list_to_nulltermcharpp(prelen, prependargv, rem);
+}
+
+static void
+gnc_set_remaining_argv(int len, const char **rest)
+{
+    SCM toput = gnc_argvarr_to_scheme_list(len, rest);
+    gh_define(gnc_scheme_remaining_var, toput);
+}
+
+             
 /* ============================================================== */
 
 /* These gnucash_ui_init and gnucash_ui functions are just hacks to get
@@ -140,17 +158,43 @@
    what they should do soon, and expect that the open/select functions
    will be merged with the code in FMB_OPEN in MainWindow.c */
 
+static const char *default_argv[] = {"gnucash", 0};
+
+static const struct poptOption nullPoptTable[] = {
+    { NULL, 0, 0, NULL, 0 }
+};
+
 int
 gnucash_ui_init(void)
 {
+  int restargc;
+  char **restargv;
+  poptContext returnedPoptContext;
+  
   ENTER ("\n");
 
   /* We're going to have to have other ways to handle X and GUI
      specific args... */
   if (!gnome_is_initialized)
   {
-    gnome_init("GnuCash", NULL, gnc_get_global_argc(), gnc_get_global_argv());
+    restargv = gnc_get_remaining_argv(1, default_argv);
+    if(restargv == 0)
+    {
+        restargv = g_new(char*, 2);
+        restargv[0] = g_strdup(default_argv[0]);
+        restargv[1] = 0;
+    }
+    
+    restargc = argv_length(restargv);
+
+    gnome_init_with_popt_table("GnuCash", NULL, restargc, restargv,
+                               nullPoptTable, 0, &returnedPoptContext);
     gnome_is_initialized = TRUE;
+
+    gnc_free_argv(restargv);
+    restargv = (char**)poptGetArgs(returnedPoptContext);
+    gnc_set_remaining_argv(argv_length(restargv), (const char**)restargv);
+    gh_eval_str("(gnc:load-account-file)");
     
     /* initialization required for gtkhtml */
     gdk_rgb_init ();    
Index: src/guile/Makefile.am
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/guile/Makefile.am,v
retrieving revision 1.9
diff -u -b -r1.9 Makefile.am
--- src/guile/Makefile.am	2000/10/23 22:39:19	1.9
+++ src/guile/Makefile.am	2000/12/11 05:39:34
@@ -10,6 +10,7 @@
   option-util.c \
   global-options.c \
   tip-of-the-day.c \
+  argv-list-converters.c \
   File.c
 
 docdir = ${GNC_DOC_INSTALL_DIR}
@@ -28,6 +29,7 @@
   gnucash.h \
   guile-util.h \
   tip-of-the-day.h \
+  argv-list-converters.h \
   option-util.h
 
 EXTRA_DIST = \
Index: src/guile/gnucash.c.in
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/guile/gnucash.c.in,v
retrieving revision 1.22
diff -u -b -r1.22 gnucash.c.in
--- src/guile/gnucash.c.in	2000/12/08 01:12:41	1.22
+++ src/guile/gnucash.c.in	2000/12/11 05:39:34
@@ -147,7 +147,7 @@
   printf ("\n\n");
 
   /* We need to initialize the UI early ... */
-  gnucash_ui_init();
+  /* gnucash_ui_init(); */
   return 0;
 }
 
Index: src/scm/command-line.scm
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/scm/command-line.scm,v
retrieving revision 1.15
diff -u -b -r1.15 command-line.scm
--- src/scm/command-line.scm	2000/12/04 21:26:02	1.15
+++ src/scm/command-line.scm	2000/12/11 05:39:34
@@ -17,8 +17,71 @@
 
 ;; also "-c"
 
-(define gnc:*command-line-files* #f)
+(define gnc:*command-line-remaining* #f)
 
+;;(use-modules (ice-9 getopt-long))
+
+;;(define (gnc:is-boolean-arg? arg)
+;;  (if (or (string=? arg "true") (string=? arg "false")) #t #f))
+
+;;(define (gnc:is-integer-arg? arg)
+;;  (if (string->number arg) #t #f))
+
+;;(define (gnc:convert-arg-to-boolean arg)
+;;  (if (string=? arg "true")
+;;      #t
+;;      (if (string=? arg "false")
+;;          #f
+;;          'abort)))
+
+;;(define (gnc:convert-arg-to-integer arg)
+;;  (let ((value (string->number arg)))
+;;    (if (and (not value) (not (exact? value)))
+;;        'abort
+;;        value)))
+
+;;(define (gnc:convert-arg-defs-to-opt-args arg-defs)
+;;  (letrec ((return '())
+;;           (decide-single-char
+;;            (let ((single-char-cache '()))
+;;              (lambda (name)
+;;                (let ((possible (string-ref name 0)))
+;;                  (if (eq? (assv possible single-char-cache) #f)
+;;                      (begin
+;;                       (set! single-char-cache (acons possible #t
+;;                                                      single-char-cache))
+;;                       possible)
+;;                      #f)))))
+;;           (create-arg-list
+;;            (lambda (name-sym value pred sc)
+;;              (let ((ret `(,name-sym (value ,value))))
+;;                (if (not (eq? pred #f))
+;;                    (set! ret (append ret (cons 'predicate pred))))
+;;                (if (not (eq? sc #f))
+;;                    (set! ret (append ret (cons 'single-char sc))))
+;;                ret)))
+;;           (helper
+;;            (lambda (arg-defs ret)
+;;              (if (not (pair? arg-defs))
+;;                  ret
+;;                  (helper
+;;                   (cdr arg-defs)
+;;                   (cons
+;;                    (let* ((one-arg (car arg-defs))
+;;                           (arg-name (car one-arg))
+;;                           (arg-sym (string->symbol arg-name))
+;;                           (arg-oc (decide-single-char arg-name)))
+;;                      (case (cadr one-arg)
+;;                        ((boolean) (create-arg-list arg-sym 'optional
+;;                                                    gnc:is-boolean-arg?
+;;                                                    arg-oc))
+;;                        ((integer) (create-arg-list arg-sym #t
+;;                                                    gnc:is-integer-arg?
+;;                                                    arg-oc))
+;;                        ((string) (create-arg-list arg-sym #t #f arg-oc))))
+;;                    ret))))))
+;;    (helper arg-defs return)))
+  
 (define gnc:*arg-defs*
   (list
    
@@ -150,11 +213,41 @@
 (define (gnc:prefs-show-usage)
   (display "usage: gnucash [ option ... ] [ datafile ]") (newline))
 
+;;(define (gnc:handle-command-line-args)
+;;  (letrec ((internal
+;;            (lambda ()
+;;              (getopt-long (program-arguments)
+;;                           (gnc:convert-arg-defs-to-opt-args gnc:*arg-defs*))))
+;;           (arg-handler
+;;            (lambda (args)
+;;              (if (pair? args)
+;;                  (begin
+;;                   (let ((one-arg (car args)))
+;;                     (if (eq? (car one-arg) '())
+;;                         (set! gnc:*command-line-remaining* (cdr one-arg))
+;;                         (let* ((arg-name (symbol->string (car one-arg)))
+;;                                (arg-stuff (assoc-ref gnc:*arg-defs* arg-name)))
+;;                           (case (car arg-stuff)
+;;                             ((string)
+;;                              ((cdr arg-stuff) (cdr one-arg)))
+;;                             ((integer)
+;;                              ((cdr arg-stuff) (gnc:convert-arg-to-integer
+;;                                                (cdr one-arg))))
+;;                             ((boolean)
+;;                              ((cdr arg-stuff) (gnc:convert-arg-to-boolean
+;;                                                (cdr one-arg))))))))
+;;                   (arg-handler (cdr args)))))))
+;;    (display "Converted") (newline)
+;;    (display (gnc:convert-arg-defs-to-opt-args gnc:*arg-defs*)) (newline)
+;;    (flush-all-ports)
+;;    (arg-handler (internal)))
+;;  #t)
+    
 
 (define (gnc:handle-command-line-args)
   (gnc:debug "handling command line arguments" (program-arguments))
   
-  (let ((files-to-open '())
+  (let ((remaining-arguments '())
         (result #t))
     
     (do ((rest (cdr (program-arguments))) ; initial cdr skips argv[0]
@@ -172,7 +265,7 @@
           (begin
             (gnc:debug "non-option " item ", assuming file")
             (set! rest (cdr rest))
-            (set! files-to-open (cons item files-to-open)))
+            (set! remaining-arguments (cons item remaining-arguments)))
           
           (if (string=? "--" item)
               ;; ignore --
@@ -188,6 +281,8 @@
                       ;;(set! quit? #t))
                       (display "Ignoring unused option ")(display arg-string)
                       (newline)
+                      (set! remaining-arguments
+                            (cons item remaining-arguments))
 		      (set! rest (cdr rest)))
                     
                     (let* ((arg-type (car arg-def))
@@ -210,8 +305,8 @@
                             ((cdr arg-def) parsed-value) 
                             (set! rest remaining-args)))))))))
     (if result
-        (gnc:debug "files to open: " files-to-open))
+        (gnc:debug "files to open: " remaining-arguments))
     
-    (set! gnc:*command-line-files* files-to-open)
+    (set! gnc:*command-line-remaining* remaining-arguments)
     
     result))
Index: src/scm/main.scm
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/scm/main.scm,v
retrieving revision 1.28
diff -u -b -r1.28 main.scm
--- src/scm/main.scm	2000/11/29 19:00:33	1.28
+++ src/scm/main.scm	2000/12/11 05:39:34
@@ -99,6 +99,14 @@
   (gnc:debug "UI Shutdown hook.")
   (gnc:file-quit))
 
+(define (gnc:load-account-file)
+  (let ((ok (not (gnc:config-var-value-get gnc:*arg-no-file*)))
+        (file (if (pair? gnc:*command-line-remaining*)
+                  (car gnc:*command-line-remaining*)
+                  (gnc:history-get-last))))
+    (if (and ok (string? file))
+        (gnc:ui-open-file file))))
+
 (define (gnc:main)
 
   ;; Now the fun begins.
@@ -118,12 +126,8 @@
 
   (if (null? gnc:*batch-mode-things-to-do*)
       ;; We're not in batch mode; we can go ahead and do the normal thing.
-      (let ((ok (not (gnc:config-var-value-get gnc:*arg-no-file*)))
-            (file (if (pair? gnc:*command-line-files*)
-                      (car gnc:*command-line-files*)
-                      (gnc:history-get-last))))
-        (if (and ok (string? file))
-            (gnc:ui-open-file file))
+      (begin
+        ;; (gnc:load-account-file)
         (gnc:hook-add-dangler gnc:*ui-shutdown-hook* gnc:ui-finish)
         (gnc:ui-main)
         (gnc:hook-remove-dangler gnc:*ui-shutdown-hook* gnc:ui-finish))
Index: src/guile/design.txt
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/guile/design.txt,v
retrieving revision 1.2
diff -u -b -r1.2 design.txt
--- src/guile/design.txt	1998/10/15 03:58:45	1.2
+++ src/guile/design.txt	2000/12/11 05:39:34
@@ -26,8 +26,8 @@
 >         /* Enter Guile */ --- prefs/startup.scm
 >         ;; Process arguments
 >         (gnucash:lowlev-app-init)
->         (if (pair? gnucash:*command-line-files*)
->           (gnucash:ui-open-file (car gnucash:*command-line-files*))
+>         (if (pair? gnucash:*command-line-remaining*)
+>           (gnucash:ui-open-file (car gnucash:*command-line-remaining*))
 >           (gnucash:ui-select-file))
 >         (gnucash:lowlev-app-main)
 >



--=-=-=
Content-Type: application/octet-stream
Content-Disposition: attachment; filename=argv-list-converters.c
Content-Description: argv to scm list converters

/********************************************************************\
 * argv-list-converters.c                                           *
 * Copyright (C) 2000 Gnumatic, Inc                                 *
 * Copyright (C) 2000 James LewisMoss                               *
 *                                                                  *
 * This program is free software; you can redistribute it and/or    *
 * modify it under the terms of the GNU General Public License as   *
 * published by the Free Software Foundation; either version 2 of   *
 * the License, or (at your option) any later version.              *
 *                                                                  *
 * This program is distributed in the hope that it will be useful,  *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
 * GNU General Public License for more details.                     *
 *                                                                  *
 * You should have received a copy of the GNU General Public License*
 * along with this program; if not, contact:                        *
 *                                                                  *
 * Free Software Foundation           Voice:  +1-617-542-5942       *
 * 59 Temple Place - Suite 330        Fax:    +1-617-542-2652       *
 * Boston, MA  02111-1307,  USA       gnu@gnu.org                   *
\********************************************************************/

#include <guile/gh.h>
#include <glib.h>
#include "argv-list-converters.h"

char**
gnc_scheme_list_to_nulltermcharpp(int prelen, const char **prepend, SCM list)
{
    SCM next = list;
    char **ret;
    int len = 0;
    int loc;

    if(gh_pair_p(list))
    {
        int i;
        len = gh_length(list) + prelen;
        ret = g_new(char *, len + 1);
        ret[len] = 0;
        for(i = 0; i < prelen; i++)
        {
            ret[i] = g_strdup(prepend[i]);
        }
    }
    else 
    {
        return 0;
    }

    loc = prelen;
    while(gh_pair_p(next)) 
    {
        SCM scm_string = gh_car(next);
        next = gh_cdr(next);
        if(gh_string_p(scm_string))
        {
            char *onestr = gh_scm2newstr(scm_string, 0);
            fprintf(stderr, "Schemestring: ");
            gh_display(scm_string);
            fprintf(stderr, "\n");
            fprintf(stderr, "Cstring: %s\n", onestr);
            ret[loc] = onestr;
        }
        else 
        {
            g_free(ret);
            return 0;
        }
        loc++;
    }

    print_argv(ret);
    
    return ret;
}

SCM
gnc_argvarr_to_scheme_list(int argc, const char** argv)
{
    int i;
    SCM ret = SCM_EOL;

    for(i = 0; i < argc; i++)
    {
        ret = gh_cons(gh_str02scm(argv[i]), ret);
    }

    return gh_reverse(ret);
}

void
gnc_free_argv(char** argv)
{
    char **now = argv;

    if(!argv)
    {
        return;
    }
    
    while(*now != 0)
    {
        g_free(*now);
        now++;
    }
    g_free(argv);
}

void
print_argv(char **argv)
{
    char **foo = argv;
    printf("#(");
    while(*foo != 0)
    {
        printf("%s, ", *foo);
        foo++;
    }
    printf(")\n");
}

int
argv_length(char** nulltermlist)
{
    int ret = 0;

    if(!nulltermlist)
    {
        return 0;
    }
    
    while(nulltermlist[ret] != 0)
        ret++;
    return ret;
}


--=-=-=
Content-Type: application/octet-stream
Content-Disposition: attachment; filename=argv-list-converters.h
Content-Description: header for argv to scm list converters

/********************************************************************\
 * argv-list-converters.h                                           *
 * Copyright (C) 2000 Gnumatic, Inc                                 *
 * Copyright (C) 2000 James LewisMoss                               *
 *                                                                  *
 * This program is free software; you can redistribute it and/or    *
 * modify it under the terms of the GNU General Public License as   *
 * published by the Free Software Foundation; either version 2 of   *
 * the License, or (at your option) any later version.              *
 *                                                                  *
 * This program is distributed in the hope that it will be useful,  *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
 * GNU General Public License for more details.                     *
 *                                                                  *
 * You should have received a copy of the GNU General Public License*
 * along with this program; if not, contact:                        *
 *                                                                  *
 * Free Software Foundation           Voice:  +1-617-542-5942       *
 * 59 Temple Place - Suite 330        Fax:    +1-617-542-2652       *
 * Boston, MA  02111-1307,  USA       gnu@gnu.org                   *
\********************************************************************/



/*
 * This function takes a SCM value.  Determines whether it is a list
 * and whether that list contains only strings and returns a null
 * terminated array of strings (char*'s)
 */
char** gnc_scheme_list_to_nulltermcharpp(int prelen, const char **prepend,
                                         SCM list);


/*
 * This function takes a length and char** and makes a scheme list
 * with similar contents
 */
SCM gnc_argvarr_to_scheme_list(int argc, const char** argv);

/*
 * Frees the strings and the argv array
 */
void gnc_free_argv(char** argv);

/*
 * print out the argv array in a nice manner
 */
void print_argv(char **argv);

/*
 * get the length of null terminated char* array
 */
int argv_length(char** nulltermlist);

--=-=-=


-- 
@James LewisMoss <dres@debian.org>      |  Blessed Be!
@    http://jimdres.home.mindspring.com |  Linux is kewl!
@"Argue for your limitations and sure enough, they're yours." Bach

--=-=-=--