chiark / gitweb /
Updates for mLib/mgLib. Support history files for recalling past 1.1.0
authormdw <mdw>
Fri, 11 Dec 1998 09:53:02 +0000 (09:53 +0000)
committermdw <mdw>
Fri, 11 Dec 1998 09:53:02 +0000 (09:53 +0000)
entries, using a drop-down list.

xgetline.c

index efdbb7fabfa6ac88ee63f778da8cafc37aa87551..96c9e465e8aafd3ba02fa6c91871bf800804cb52 100644 (file)
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: xgetline.c,v 1.6 1998/12/03 00:56:29 mdw Exp $
+ * $Id: xgetline.c,v 1.7 1998/12/11 09:53:02 mdw Exp $
  *
  * Fetch a line of text from the user
  *
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: xgetline.c,v $
+ * Revision 1.7  1998/12/11 09:53:02  mdw
+ * Updates for mLib/mgLib.  Support history files for recalling past
+ * entries, using a drop-down list.
+ *
  * Revision 1.6  1998/12/03 00:56:29  mdw
  * Set focus on the entry field, rather than leaving things to luck.
  *
 #include <stdlib.h>
 #include <string.h>
 
+#include <fcntl.h>
+#include <unistd.h>
+
 #include <gtk/gtk.h>
 #include <gdk/gdkkeysyms.h>
 
-#include "mdwfocus.h"
-#include "mdwopt.h"
-#include "quis.h"
+#include <mLib/alloc.h>
+#include <mLib/dstr.h>
+#include <mLib/mdwopt.h>
+#include <mLib/report.h>
+#include <mLib/quis.h>
+
+#include <mgLib/cancel.h>
+#include <mgLib/mdwfocus.h>
 
 /*----- Main code ---------------------------------------------------------*/
 
-/* --- @cancel@ --- *
+/* --- @quit@ --- *
  *
  * Arguments:  @GtkWidget *w@ = widget raising the signal
  *             @gpointer *p@ = pointer to integer result code
@@ -75,7 +87,7 @@
  * Use:                Sets the result code to zero (failure) and ends the loop.
  */
 
-static void cancel(GtkWidget *w, gpointer *p)
+static void quit(GtkWidget *w, gpointer *p)
 {
   int *ip = (int *)p;
   *ip = 0;
@@ -99,29 +111,6 @@ static void done(GtkWidget *w, gpointer *p)
   gtk_main_quit();
 }
 
-/* --- @check_escape@ --- *
- *
- * Arguments:  @GtkWidget *w@ = widget raising the signal
- *             @GdkEventKey *ev@ = pointer to event data
- *             @gpointer *p@ = widget to activate in response
- *
- * Returns:    ---
- *
- * Use:                Activates a widget when an escape keypress is detected.
- */
-
-static gboolean check_escape(GtkWidget *w, GdkEventKey *ev, gpointer *p)
-{
-  if (ev->keyval == GDK_Escape) {
-    if (p)
-      gtk_widget_activate(GTK_WIDGET(p));
-    else
-      gtk_object_destroy(GTK_OBJECT(w));
-    return (1);
-  }
-  return (0);
-}
-
 /* --- @version@ --- *
  *
  * Arguments:  @FILE *fp@ = output stream to print the message on
@@ -147,7 +136,10 @@ static void version(FILE *fp)
 
 static void usage(FILE *fp)
 {
-  fprintf(fp, "Usage: %s [-i] [-t title] [-p prompt] [-d default]\n", QUIS);
+  fprintf(fp,
+         "Usage: %s [-in] [-t title] [-p prompt] [-d default]\n"
+         "\t[-l|-H file] [-m max]\n",
+         QUIS);
 }
 
 /* --- @main@ --- *
@@ -173,9 +165,15 @@ int main(int argc, char *argv[])
   unsigned f = 0;
   int ok = 0;
 
+  const char *list = 0;
+  int histmax = 20;
+  GList *hist;
+
   enum {
     f_invis = 1,
-    f_duff = 2
+    f_duff = 2,
+    f_history = 4,
+    f_nochoice = 8
   };
 
   /* --- User interface bits --- */
@@ -209,13 +207,17 @@ int main(int argc, char *argv[])
       { "default",     required_argument,      0,      'd' },
       { "password",    0,                      0,      'i' },
       { "invisible",   0,                      0,      'i' },
+      { "history",     required_argument,      0,      'H' },
+      { "list",                required_argument,      0,      'l' },
+      { "histmax",     required_argument,      0,      'm' },
+      { "no-choice",   0,                      0,      'n' },
       { 0,             0,                      0,      0 }
     };
     int i;
 
     /* --- Fetch an option --- */
 
-    i = getopt_long(argc, argv, "huv t:p:d:i", opt, 0);
+    i = getopt_long(argc, argv, "huv t:p:d:i H:l:m:n", opt, 0);
     if (i < 0)
       break;
 
@@ -240,7 +242,12 @@ int main(int argc, char *argv[])
 "-i, --invisible\t     Don't show the user's string as it's typed\n"
 "-t, --title=TITLE     Set the window's title string\n"
 "-p, --prompt=PROMPT   Set the window's prompt string\n"
-"-d, --default=DEFAULT Set the default string already in the window\n",
+"-d, --default=DEFAULT Set the default string already in the window\n"
+"\n"
+"-l, --list=FILE       Read FILE into a drop-down list\n"
+"-n, --no-choice       No free text input: must choose item from list\n"
+"-H, --history=FILE    As for `--list', but update with new string\n"
+"-m, --histmax=MAX     Maximum number of items written back to file\n",
           stdout);
        exit(0);
        break;
@@ -252,7 +259,7 @@ int main(int argc, char *argv[])
        version(stdout);
        exit(0);
        break;
-       
+
       case 't':
        title = optarg;
        break;
@@ -265,6 +272,21 @@ int main(int argc, char *argv[])
       case 'i':
        f |= f_invis;
        break;
+
+      case 'l':
+       list = optarg;
+       break;
+      case 'n':
+       f |= f_nochoice;
+       break;
+      case 'H':
+       f |= f_history;
+       list = optarg;
+       break;
+      case 'm':
+       histmax = atoi(optarg);
+       break;
+
       default:
        f |= f_duff;
        break;
@@ -276,13 +298,21 @@ int main(int argc, char *argv[])
     exit(EXIT_FAILURE);
   }
 
+  if ((f & f_invis) && list) {
+    die(EXIT_FAILURE,
+       "invisible entry is dumb if you provide a list of alternatives!");
+  }
+
+  if ((f & f_nochoice) && !list)
+    die(EXIT_FAILURE, "nothing to restrict choice to!");
+
   /* --- Create the main window --- */
 
   win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
   gtk_window_set_title(GTK_WINDOW(win), title);
   gtk_window_position(GTK_WINDOW(win), GTK_WIN_POS_MOUSE);
   gtk_signal_connect(GTK_OBJECT(win), "destroy",
-                    GTK_SIGNAL_FUNC(cancel), &ok);
+                    GTK_SIGNAL_FUNC(quit), &ok);
 
   /* --- Create the box for laying out the widgets inside --- */
 
@@ -300,14 +330,63 @@ int main(int argc, char *argv[])
 
   /* --- Create the entry widget --- */
 
-  entry = gtk_entry_new();
-  gtk_entry_set_text(GTK_ENTRY(entry), dfl);
-  gtk_table_attach(GTK_TABLE(box), entry,
-                  left, left + 1, 0, 1,
-                  GTK_EXPAND | GTK_FILL, GTK_EXPAND, 4, 2);
-  if (f & f_invis)
-    gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
-  gtk_widget_show(entry);
+  if (list) {
+    FILE *fp = fopen(list, "r");
+    GtkWidget *combo;
+
+    /* --- Read the items in from the file --- *
+     *
+     * Inability to open the file is not a disaster.
+     */
+
+    hist = 0;
+    if (fp) {
+      dstr d;
+
+      dstr_create(&d);
+      while (dstr_putline(&d, fp) != EOF) {
+       hist = g_list_append(hist, xstrdup(d.buf));
+       dstr_destroy(&d);
+      }
+      fclose(fp);
+    }
+
+    /* --- Now create a combo box --- */
+
+    combo = gtk_combo_new();
+    entry = GTK_COMBO(combo)->entry;
+    if (hist)
+      gtk_combo_set_popdown_strings(GTK_COMBO(combo), hist);
+
+    /* --- Do other configuring --- */
+
+    if (f & f_nochoice) {
+      gtk_combo_set_value_in_list(GTK_COMBO(combo), 1, 0);
+      gtk_entry_set_editable(GTK_ENTRY(entry), 0);
+    }
+    gtk_combo_set_case_sensitive(GTK_COMBO(combo), 1);
+    gtk_combo_set_use_arrows_always(GTK_COMBO(combo), 1);
+    if (strcmp(dfl, "@") == 0)
+      gtk_entry_set_text(GTK_ENTRY(entry), hist ? (char *)hist->data : "");
+    else
+      gtk_entry_set_text(GTK_ENTRY(entry), dfl);
+
+    /* --- Set the widget in the right place and show it --- */
+
+    gtk_table_attach(GTK_TABLE(box), combo,
+                    left, left + 1, 0, 1,
+                    GTK_EXPAND | GTK_FILL, GTK_EXPAND, 4, 2);
+    gtk_widget_show(combo);
+  } else {
+    entry = gtk_entry_new();
+    gtk_entry_set_text(GTK_ENTRY(entry), dfl);
+    if (f & f_invis)
+      gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
+    gtk_table_attach(GTK_TABLE(box), entry,
+                    left, left + 1, 0, 1,
+                    GTK_EXPAND | GTK_FILL, GTK_EXPAND, 4, 2);
+    gtk_widget_show(entry);
+  }
 
   /* --- Create the default action widget --- */
 
@@ -330,8 +409,7 @@ int main(int argc, char *argv[])
   gtk_signal_connect_object(GTK_OBJECT(entry), "activate",
                            GTK_SIGNAL_FUNC(gtk_widget_activate),
                            GTK_OBJECT(btn));
-  gtk_signal_connect(GTK_OBJECT(win), "key_press_event",
-                    GTK_SIGNAL_FUNC(check_escape), 0);
+  cancel(GTK_WINDOW(win), 0);
 
   /* --- Go go go --- */
 
@@ -345,6 +423,41 @@ int main(int argc, char *argv[])
 
   if (ok) {
     char *p = gtk_entry_get_text(GTK_ENTRY(entry));
+
+    /* --- If history is enabled, output a new history file --- *
+     *
+     * If the first entry was accepted verbatim, don't bother.
+     */
+
+    if (f & f_history && !(hist && strcmp(p, hist->data) == 0)) {
+      int fd;
+      FILE *fp;
+      int i;
+      GList *g;
+
+      if ((fd = open(list, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0)
+       goto fail;
+      if ((fp = fdopen(fd, "w")) == 0) {
+       close(fd);
+       goto fail;
+      }
+
+      fputs(p, fp);
+      fputc('\n', fp);
+
+      for (i = 1, g = hist; (histmax < 1 || i < histmax) && g; g = g->next) {
+       if (strcmp(g->data, p) != 0) {
+         fputs(g->data, fp);
+         fputc('\n', fp);
+         i++;
+       }
+      }
+      fclose(fp);
+    fail:;
+    }
+
+    /* --- Print the result and go away --- */
+      
     puts(p);
   }