]> andersk Git - moira.git/blobdiff - clients/moira/utils.c
make sure QueryLoop uses the whole queue
[moira.git] / clients / moira / utils.c
index a3ab665a7a4a4266e4a6d7c573c14f02231fe76f..bad1587eeb0a45d7d16fa142cd0c28ffa024b272 100644 (file)
@@ -1,10 +1,10 @@
-#ifndef lint
+#if (!defined(lint) && !defined(SABER))
   static char rcsid_module_c[] = "$Header$";
 #endif lint
 
-/*     This is the file utils.c for allmaint, the SMS client that allows
- *      a user to maintaint most important parts of the SMS database.
- *     It Contains: Many utilities used by allmaint.
+/*     This is the file utils.c for the SMS Client, which allows a nieve
+ *      user to quickly and easily maintain most parts of the SMS database.
+ *     It Contains:  Many useful utility functions.
  *     
  *     Created:        4/25/88
  *     By:             Chris D. Peterson
  *      $Author$
  *      $Header$
  *     
- *     Copyright 1987, 1988 by the Massachusetts Institute of Technology.
+ *     Copyright 1988 by the Massachusetts Institute of Technology.
  *
  *     For further information on copyright and distribution 
  *     see the file mit-copyright.h
  */
 
-
 #include <stdio.h>
 #include <strings.h>
 #include <sms.h>
+#include <sms_app.h>
 #include <menu.h>
+#include <ctype.h>
 
 #include "mit-copyright.h"
-#include "allmaint.h"
+#include "defs.h"
+#include "f_defs.h"
 #include "globals.h"
-#include "infodefs.h"
 
 #include <netdb.h>             /* for gethostbyname. */
-/* #include <ctype.h> */
-/* #include <varargs.h> */
-/* #include <sys/types.h> */
+
+/*     Function Name: AddQueue
+ *     Description: Adds an element to a queue
+ *     Arguments: elem, pred - element and its predecessor.
+ *     Returns: none.
+ */
+
+static void
+AddQueue(elem, pred)
+struct qelem * elem, *pred;
+{
+    if (pred == NULL) {
+       elem->q_forw = NULL;
+       elem->q_back = NULL;
+       return;
+    }
+    elem->q_back = pred;
+    elem->q_forw = pred->q_forw;
+    pred->q_forw = elem;
+}
+
+/*     Function Name: RemoveQueue
+ *     Description: removes an element from a queue.
+ *     Arguments: elem.
+ *     Returns: none.
+ */
+
+static void
+RemoveQueue(elem)
+struct qelem *elem;
+{
+    if (elem->q_forw != NULL) 
+       (elem->q_forw)->q_back = elem->q_back;
+    if (elem->q_back != NULL)
+       (elem->q_back)->q_forw = elem->q_forw;
+}
 
 /*     Function Name: FreeInfo
  *     Description: Frees all elements of a NULL terminated arrary of char*'s
@@ -45,9 +79,45 @@ void
 FreeInfo(info)
 char ** info;
 {
-    char *pointer = *info;
-    while (pointer != NULL) 
-       free(pointer++);
+    while (*info != NULL)
+       FreeAndClear(info++, TRUE);
+}
+
+/*     Function Name: FreeAndClear        - I couldn't resist the name.
+ *     Description: Clears pointer and optionially frees it.
+ *     Arguments: pointer - pointer to work with.
+ *                 free_it - if TRUE then free pointer.
+ *     Returns: none.
+ */
+
+void
+FreeAndClear(pointer, free_it)
+char ** pointer;
+Bool free_it;
+{
+    if (*pointer == NULL)
+       return;
+    else if (free_it)
+       free(*pointer);
+    *pointer = NULL;
+}
+
+/*     Function Name: QueueTop
+ *     Description: returns a qelem pointer that points to the top of
+ *                   a queue.
+ *     Arguments: elem - any element of a queue.
+ *     Returns: top element of a queue.
+ */
+    
+struct qelem * 
+QueueTop(elem)
+struct qelem * elem;
+{
+    if (elem == NULL)          /* NULL returns NULL.  */
+       return(NULL);
+    while (elem->q_back != NULL) 
+       elem = elem->q_back;
+    return(elem);
 }
 
 /*     Function Name: FreeQueueElem
@@ -56,15 +126,17 @@ char ** info;
  *     Returns: none
  */
 
-void
+static void
 FreeQueueElem(elem)
-struct queue * elem;
+struct qelem * elem;
 {
-    if (elem->q_data != (char *) NULL) {
-       FreeInfo( (char **) elem->q_data); /* free info fields */
+    char ** info = (char **) elem->q_data;
+
+    if (info != (char **) NULL) {
+       FreeInfo( info ); /* free info fields */
        free(elem->q_data);             /* free info array itself. */
     }
-    rmqueue(elem);             /* remove this element from the queue */
+    RemoveQueue(elem);         /* remove this element from the queue */
     free(elem);                        /* free its space. */
 }
 
@@ -76,9 +148,9 @@ struct queue * elem;
 
 void
 FreeQueue(elem)
-struct queue * elem;
+struct qelem * elem;
 {
-    struct queue *temp, *local = QueueTop(elem); 
+    struct qelem *temp, *local = QueueTop(elem); 
 
     while(local != NULL) {
        temp = local->q_forw;
@@ -106,48 +178,42 @@ struct qelem * elem;
     return(count);
 }
 
-/*     Function Name: QueueTop
- *     Description: returns a qelem pointer that points to the top of
- *                   a queue.
- *     Arguments: elem - any element of a queue.
- *     Returns: top element of a queue.
+/*     Function Name: StoreInfo
+ *     Description: Stores information from an sms query into a queue.
+ *     Arguments: argc, argv, - information returned from the query returned
+ *                               in argv.
+ *                 data - the previous element on the queue, this data will be
+ *                        stored in a qelem struct immediatly after this elem.
+ *                        If NULL then a new queue will be created.  This value
+ *                        is updated to the current element at the end off the
+ *                        call.
+ *     Returns: SMS_CONT, or SMS_ABORT if it has problems.
  */
-    
-struct qelem * 
-QueueTop(elem)
-struct qelem * elem;
-{
-    if (elem == NULL)          /* NULL returns NULL.  */
-       return(NULL);
-    while (elem->q_back != NULL) 
-       elem = elem->q_back;
-    return(elem);
-}
 
-/* ARGSUSED */
 int
 StoreInfo(argc, argv, data)
 int argc;
 char ** argv;
-caddr_t data;
+char * data;
 {
-    char ** info = (char **) malloc( MAX_ARGS_SIZE * sizeof(char *) );
+    char ** info = (char **) malloc( MAX_ARGS_SIZE * sizeof(char *));
     struct qelem ** old_elem = (struct qelem **) data;
     struct qelem * new_elem = (struct qelem *) malloc (sizeof (struct qelem));
     int count;
 
+    if ( (new_elem == (struct qelem *) NULL) || (info == (char **) NULL) ) {
+       Put_message("Could Not allocate more memory.");
+       FreeQueue(*old_elem);
+       *old_elem = (struct qelem *) NULL;
+       return(SMS_ABORT);
+    }
+
     for (count = 0; count < argc; count++)
        info[count] = Strsave(argv[count]);
     info[count] = NULL;                /* NULL terminate this sucker. */
 
-    if (* old_elem == (struct qelem **) NULL) {         /* first elem. */
-       new_elem->q_data = (char *) info;
-       new_elem->q_forw = new_elem->q_back = (struct qelem *) NULL;
-    }
-    else {                     /* all other elements. */
-       new_elem->q_data = (char *) info;
-       insque(new_elem, *old_elem);
-    }
+    new_elem->q_data = (char *) info;
+    AddQueue(new_elem, *old_elem);
 
     *old_elem = new_elem;
     return(SMS_CONT);
@@ -161,13 +227,15 @@ caddr_t data;
  */
 
 int
-CountArgs(info);
+CountArgs(info)
 char ** info;
 {
     int number = 0;
     
-    while (*info != NULL)
+    while (*info != NULL) {
        number++;
+       info++;
+    }
 
     return(number);
 }    
@@ -179,57 +247,15 @@ char ** info;
  *     Returns: doesn't exit.
  */
 
-static int
+int
 Scream()
 {
-    com_err(whoami, status,
+    com_err(program_name, 0,
            "\nAn SMS update returned a value -- programmer botch\n");
     sms_disconnect();
     exit(1);
 }
 
-/*     Function Name: BoolAnswer
- *     Description: returns TRUE or FALSE in arg, depending upon
- *                   the value of the string in argv[0].
- *     Arguments: argc, argv - argv[0] contains "true" or "false".
- *     Returns: SMS_CONT.
- */
-
-/*ARGSUSED*/
-static int 
-BoolAnswer(argc, argv, arg)
-int argc;
-char *argv[];
-caddr_t arg;
-
-{
-    int *result = (int *) arg;
-
-    if (strcmp(argv[0], "true") == 0)
-       *result = TRUE;
-    else 
-       *result = FALSE;
-    return(SMS_CONT);
-}
-
-/*     Function Name: BoolQuery
- *     Description: This function makes the query, but returns TRUE or FALSE
- *                   instead of SMS_CONT or SMS_QUIT.
- *     Arguments: name - name of query
- *                 argc, argv - args to pass to query.
- *     Returns: TRUE or FALSE.
- */
-
-Bool
-BoolQuery(name, argc, argv)
-char *name;
-int argc;
-char *argv[];
-{
-    sms_query(name, argc, argv, BoolAnswer, (caddr_t) & result);
-    return(result);
-}
-
 /*     Function Name: PromptWithDefault
  *     Description: allows a user to be prompted for input, and given a 
  *                   default choice.
@@ -250,8 +276,18 @@ char *def;
 
     (void) sprintf(tmp, "%s [%s]: ", prompt, def ? def : "");
     ans = Prompt_input(tmp, buf, buflen);
+    if (ans == 0) {
+       if (YesNoQuestion("Are you sure you want to exit", 1)) {
+           Cleanup_menu();
+           exit(0);
+       }
+       Put_message("Continuing input...");
+       return(PromptWithDefault(prompt, buf, buflen, def));
+    }
     if (IS_EMPTY(buf))
        (void) strcpy(buf, def);
+    else if (!strcmp(buf, "\"\""))
+       *buf = 0;
     return(ans);
 }
 
@@ -268,20 +304,18 @@ YesNoQuestion(prompt, bool_def)
 char *prompt;
 int bool_def;
 {
-    char ans;
+    char ans[2];
 
     while (TRUE) {
-       if (!PromptWithDefault(prompt, &ans, 1, bool_def ? "y" : "n"))
+       if (!PromptWithDefault(prompt, ans, 2, bool_def ? "y" : "n"))
            return(-1);
-       switch (ans) {
+       switch (ans[0]) {
        case 'n':
        case 'N':
            return(FALSE);
-           break;
        case 'y':
        case 'Y':
            return(TRUE);
-           break;
        default:
            Put_message("Please answer 'y' or 'n'.");
            break;
@@ -299,28 +333,25 @@ int bool_def;
  */
 
 Bool
-YesNoQuestion(prompt, bool_def)
+YesNoQuitQuestion(prompt, bool_def)
 char *prompt;
 int bool_def;
 {
-    char ans;
+    char ans[2];
 
     while (TRUE) {
-       if (!PromptWithDefault(prompt, &ans, 1, bool_def ? "y" : "n"))
+       if (!PromptWithDefault(prompt, ans, 2, bool_def ? "y" : "n"))
            return(-1);
-       switch (ans) {
+       switch (ans[0]) {
        case 'n':
        case 'N':
            return(FALSE);
-           break;
        case 'y':
        case 'Y':
            return(TRUE);
-           break;
        case 'q':
        case 'Q':
            return(-1);
-           break;
        default:
            Put_message("Please answer 'y', 'n' or 'q'.");
            break;
@@ -335,11 +366,11 @@ int bool_def;
  *     Returns:   TRUE/FALSE - wether or not the confirmation occured.
  */
 
-static int
+Bool
 Confirm(prompt)
 char * prompt;
 {
-  return( ~verbose || YesNoQuestion(prompt,FALSE) );
+  return( !verbose || (YesNoQuestion(prompt,FALSE) == TRUE) );
 }
 
 /*     Function Name: ValidName
@@ -350,12 +381,14 @@ char * prompt;
 
 Bool
 ValidName(s)
-    char *s;
+char *s;
 {
     if (IS_EMPTY(s))
        Put_message("Please use a non-empty name.");
     else if (index(s, ' '))
        Put_message("You cannot use space (' ') in this name.");
+    else if (index(s, WILDCARD))
+       Put_message("Wildcards not accepted here.");
     else
        return TRUE;
     return FALSE;
@@ -371,13 +404,13 @@ int
 ToggleVerboseMode()
 {
 
-  if(verbose)
-    Put_message("Delete functions will be silent\n");
-  else {
-    Put_message("Delete functions will first confirm\n");
-
-  verbose ~= verbose;
+  verbose = !verbose;
 
+  if (verbose)
+    Put_message("Delete functions will first confirm\n");
+  else
+    Put_message("Delete functions will be silent\n");
+    
   return(DM_NORMAL);
 }
 
@@ -399,86 +432,156 @@ NullFunc()
  *     Arguments: info - list that needs this name slipped into it.
  *                 name - the name to slip into the list.
  *     Returns: a pointer to the new list.
- *      NOTE:  This screws up the numbers if the elements of the array in a
+ *      NOTE:  This screws up the numbers of the elements of the array in a
  *             big way.
  */
 
-SlipInNewName(info, name);
+void
+SlipInNewName(info, name)
 char ** info;
-
 char * name;
 {
     register int i;
 
     /* This also pushes the NULL down. */
     for (i = CountArgs(info); i > 1; i--) { 
-       info[i+i] = info[i];
+       info[i] = info[i-1];
     }
-    info[1] = Strsave(name);   /* now slip in the name. */
+    info[1] = name;    /* now slip in the name. */
 }
 
-/*     Function Name: FreeAndClear        - I couldn't resist the name.
- *     Description: Clears pointer and optionially frees it.
- *     Arguments: pointer - pointer to work with.
- *                 free - if TRUE then free pointer.
- *     Returns: none.
+/*     Function Name: GetValueFromUser
+ *     Description: This function gets a value from a user for the field
+ *                   specified.
+ *     Arguments: prompt - prompt for user.
+ *                 pointer - pointer to default value, will be returned
+ *                          as new value.
+ *     Returns: SUB_ERROR if break hit (^C).
  */
 
-FreeAndClear(pointer, free)
-caddr_t pointer;
-Bool free;
+int
+GetValueFromUser(prompt, pointer)
+char * prompt, ** pointer;
 {
-    if (pointer == NULL)
-       return();
-    else if (free)
-       free(pointer);
+    char buf[BUFSIZ];
+
+    if (PromptWithDefault(prompt, buf, BUFSIZ, *pointer) == -1)
+       return(SUB_ERROR);
+
+/* 
+ * If these are the same then there is no need to allocate a new string.
+ *
+ * a difference that makes no difference, IS no difference.
+ */
 
-    pointer = NULL;
+    if (strcmp(buf, *pointer) != 0) { 
+       if (*pointer != NULL)
+           free(*pointer);
+       *pointer = Strsave(buf);
+    }
+    return(SUB_NORMAL);
 }
 
-/*     Function Name: GetValueFromUser
+/*     Function Name: GetYesNoValueFromUser
  *     Description: This function gets a value from a user for the field
  *                   specified.
  *     Arguments: prompt - prompt for user.
  *                 pointer - pointer to default value, will be returned
  *                          as new value.
- *     Returns: none.
+ *     Returns: SUB_ERROR if break hit (^C).
  */
 
-void
-GetValueFromUser(prompt, pointer)
-char * prompt, * pointer;
+int
+GetYesNoValueFromUser(prompt, pointer)
+char * prompt, ** pointer;
 {
-    char buf[BUFSIZ];
+    char user_prompt[BUFSIZ];
+    Bool default_val;
 
-    PromptWithDefault(prompt, buf, BUFSIZ, pointer);
-    if ( pointer != NULL)
-       free(pointer);
-    pointer = Strsave(buf);
+    if ( strcmp (*pointer, DEFAULT_YES) == 0 )
+       default_val = TRUE;
+    else
+       default_val = FALSE;
+    
+    sprintf(user_prompt, "%s (y/n)", prompt);
+
+    switch (YesNoQuestion(user_prompt, default_val)) {
+    case TRUE:
+       if (*pointer != NULL)
+           free(*pointer);
+       *pointer = Strsave(DEFAULT_YES);
+       break;
+    case FALSE:
+       if (*pointer != NULL)
+           free(*pointer);
+       *pointer = Strsave(DEFAULT_NO);
+       break;
+    case -1:
+    default:
+       return(SUB_ERROR);
+    }
+    return(SUB_NORMAL);
 }
 
-/*     Function Name: CanonicalizeHostname
- *     Description: This function takes a machine name and canonicalize's it.
- *     Arguments: machine - name of the machine to work on.
- *     Returns: new name or NULL if nameserver returns error
+/*     Function Name: GetFSVal
+ *     Description: asks about a specific filesystem value.
+ *     Arguments: name - string for this type of filesystem.
+ *                 mask - mask for this type of filesystem.
+ *                 current - current filesystem state. (for defaults).
+ *                 new - new filesystem state.
+ *     Returns: TRUE if successful.
  */
 
-char *
-CanonicalizeHostname(machine)
-char *machine;
+static Bool
+GetFSVal(name, mask, current, new)
+char * name;
+int mask, current, *new;
 {
-    struct hostent *hostinfo;
+    char temp_buf[BUFSIZ];
+    sprintf(temp_buf, "Is this a %s filsystem", name);
+    switch (YesNoQuestion(temp_buf, ( (mask & current) == mask) )) {
+    case TRUE:
+       *new |= mask;
+       break;
+    case FALSE:
+       break;                  /* zero by default. */
+    default:
+       return(FALSE);
+    }
+    return(TRUE);
+}
 
-    hostinfo = gethostbyname(machine);
-    if (hostinfo != (struct hostent *) NULL)
-       machine = hostinfo->h_name;
-    else                       
-/*
- *  gethostbyname failed.  This should be very rare, since we're
- *  dealing with local hosts, so no fancy error recovery. 
+/*     Function Name: GetFSTypes
+ *     Description: Allows user to specify filsystem types.
+ *     Arguments: current - current value of filsystem, freed here.
+ *     Returns: SUB_ERROR on ^C.
  */
-       machine = (char *) NULL;
-    return (machine);
+
+int
+GetFSTypes(current)
+char **  current;
+{
+    int c_value, new_val = 0;  /* current value of filesys type (int). */
+    char ret_value[BUFSIZ];
+
+    if (*current == NULL)
+       c_value = 0;
+    else 
+       c_value = atoi(*current);
+
+    if (GetFSVal("student", SMS_FS_STUDENT, c_value, &new_val) == FALSE)
+       return(SUB_ERROR);
+    if (GetFSVal("faculty", SMS_FS_FACULTY, c_value, &new_val) == FALSE)
+       return(SUB_ERROR);
+    if (GetFSVal("staff", SMS_FS_STAFF, c_value, &new_val) == FALSE)
+       return(SUB_ERROR);
+    if (GetFSVal("miscellaneous", SMS_FS_MISC, c_value, &new_val) == FALSE)
+       return(SUB_ERROR);
+
+    FreeAndClear(current, TRUE);
+    sprintf(ret_value, "%d", new_val);
+    *current = Strsave(ret_value);
+    return(SUB_NORMAL);
 }
 
 /*     Function Name: Strsave
@@ -499,46 +602,6 @@ char *str;
        return (strcpy(newstr, str));
 }
 
-/*     Function Name: EncryptMITID
- *     Description: Encrypts an mit ID number. 
- *     Arguments: sbuf - the buffer to return the encrypted number in.
- *                 idnumber - the id number (string).
- *                 first, last - name of the person.
- *     Returns: none.
- */
-
-void
-EncryptMITID(sbuf, idnumber, first, last)
-char *sbuf, *idnumber, *first, *last;
-{
-    char salt[3];
-    extern char *crypt();
-
-#define _tolower(c) ((c)|0x60)
-
-    salt[0] = _tolower(last[0]);
-    salt[1] = _tolower(first[0]);
-    salt[2] = 0;
-
-    (void) strcpy(sbuf, crypt(&idnumber[2], salt));
-}
-
-/*     Function Name: RemoveHyphens
- *     Description: Removes all hyphens from the string passed to it.
- *     Arguments: str - the string to remove the hyphes from
- *     Returns: none
- */
-
-void
-RemoveHyphens(str)
-char *str;
-{
-    char *hyphen;
-
-    while ((hyphen = index(str, '-')) != NULL)
-       (void) strcpy(hyphen, hyphen + 1);
-}
-
 /*     Function Name: Print
  *     Description: prints out all the arguments on a single line.
  *     Arguments: argc, argv - the standard SMS arguments.
@@ -553,6 +616,7 @@ int argc;
 char **argv, *callback;
 {
     char buf[BUFSIZ];
+    register int i;
 
     found_some = TRUE;
     (void) strcpy(buf,argv[0]);        /* no newline 'cause Put_message adds one */
@@ -581,7 +645,7 @@ char **argv, *callback;
     if (callback == NULL)
        return( Print(argc, argv, callback) );
     if (strcmp(argv[0], callback) == 0) 
-       return( Print(1, argv + 1, callback) );
+       return( Print(argc, argv, callback) );
     return(SMS_CONT);
 }
 
@@ -593,20 +657,256 @@ char **argv, *callback;
  */
 
 int
-PrintHelp(message);
+PrintHelp(message)
 char ** message;
 {
-    Print(CountArgs(message), message, (char *) NULL);
+    register int i;
+
+    for (i = 0; i < CountArgs(message); i++)
+      Put_message(message[i]);
+
     return(DM_NORMAL);
 }
 
-/*
- * Local Variables:
- * mode: c
- * c-indent-level: 4
- * c-continued-statement-offset: 4
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * End:
+/*     Function Name: Loop
+ *     Description: This function goes through the entire queue, and
+ *                   and executes the given function on each element.
+ *     Arguments: elem - top element of the queue.
+ *                 func - the function to execute.
+ *     Returns: none.
+ */
+
+void
+Loop(elem, func)
+FVoid func;
+struct qelem * elem;
+{
+    while (elem != NULL) {
+       char ** info = (char **) elem->q_data;
+       (*func) (info);
+       elem = elem->q_forw;
+    }
+}
+
+
+/*     Function Name: QueryLoop
+ *     Description: This functions loops through a queue containing
+ *                   information about some item that we want to perform
+ *                   an operation on, and then calls the correct routine
+ *                   perform that operation.
+ *     Arguments: top - top of the queue of information.
+ *                 print_func - print function.
+ *                 op_function - operation to be performed.
+ *                 query_string - string the prompts the user whether or not
+ *                                to perform this operation.
+ *     Returns: none.
+ *      NOTES:
+ *               print_opt - should expect one arguent, the info array
+ *                           of char *'s.
+ *                           is expected to return the name of the item.
+ *               op_func   - should expect two arguments.
+ *                           1) the info array of char *'s.
+ *                           2) a boolean the is true if there only
+ *                              one item in this queue, used for delete
+ *                              confirmation.
+ *               query_string - this should be of such a form that when the
+ *                              name of the object and '(y/n/q) ?' are appended
+ *                              then it should still make sense, an example is
+ *                              "Delete the list"
+ */
+
+void
+QueryLoop(elem, print_func, op_func, query_string)
+struct qelem *elem;
+FVoid op_func;
+FCharStar print_func;
+char * query_string;
+{
+    Bool one_item;
+    char temp_buf[BUFSIZ], *name;
+
+    elem = QueueTop(elem);
+    one_item = (QueueCount(elem) == 1);
+    while (elem != NULL) {
+       char **info = (char **) elem->q_data;
+       
+       if (one_item)
+           (*op_func) (info, one_item);
+       else {
+           name = (*print_func) (info); /* call print function. */
+           sprintf(temp_buf,"%s %s (y/n/q)", query_string, name);
+           switch(YesNoQuitQuestion(temp_buf, FALSE)) {
+           case TRUE:
+               (*op_func) (info, one_item);
+               break;
+           case FALSE:
+               break;
+           default:            /* Quit. */
+               Put_message("Aborting...");
+               return;
+           }
+       }
+       elem = elem->q_forw;
+    }
+}
+
+/*     Function Name: NullPrint
+ *     Description: print function that returns nothing.
+ *     Arguments: info - a pointer to the info array - Not used.
+ *     Returns: none.
+ */
+
+char *
+NullPrint(info)
+char ** info;
+{
+    return(info[NAME]);
+}
+
+
+/*     Function Name: GetTypeValues
+ *     Description: gets legal values for a typed object, keeping a cache
+ *     Arguments: type name
+ *     Returns: argv of values
+ */
+
+struct qelem *
+GetTypeValues(tname)
+char *tname;
+{
+    int stat;
+    char *argv[3], *p, **pp, *strsave();
+    struct qelem *elem, *oelem;
+    static struct qelem *cache = NULL;
+    struct cache_elem { char *cache_name; struct qelem *cache_data; } *ce;
+
+    for (elem = cache; elem; elem = elem->q_forw) {
+       ce = (struct cache_elem *)elem->q_data;
+       if (!strcmp(ce->cache_name, tname))
+           return(ce->cache_data);
+    }
+
+    argv[0] = tname;
+    argv[1] = "TYPE";
+    argv[2] = "*";
+    elem = NULL;
+    if (stat = do_sms_query("get_alias", 3, argv, StoreInfo, (char *)&elem)) {
+       com_err(program_name, stat, " in GetTypeValues");
+       return(NULL);
+    }
+    oelem = elem;
+    for (elem = QueueTop(elem); elem; elem = elem->q_forw) {
+       pp = (char **) elem->q_data;
+       p = strsave(pp[2]);
+       FreeInfo(pp);
+       elem->q_data = p;
+    }
+    elem = (struct qelem *) malloc(sizeof(struct qelem));
+    ce = (struct cache_elem *) malloc(sizeof(struct cache_elem));
+    ce->cache_name = tname;
+    ce->cache_data = QueueTop(oelem);
+    elem->q_data = (char  *)ce;
+    AddQueue(elem, cache);
+    cache = QueueTop(elem);
+    return(ce->cache_data);
+}
+
+
+/*     Function Name: GetTypeFromUser
+ *     Description: gets a typed value from the user
+ *     Arguments: prompt string, type name, buffer pointer
+ *     Returns: 
  */
+
+GetTypeFromUser(prompt, tname, pointer)
+char *prompt;
+char *tname;
+char  **pointer;
+{
+    char def[BUFSIZ], buffer[BUFSIZ], *p, *argv[3];
+    struct qelem *elem;
+    int stat;
+
+    strcpy(def, *pointer);
+    strcpy(buffer, prompt);
+    strcat(buffer, " (");
+    for (elem = GetTypeValues(tname); elem; elem = elem->q_forw) {
+       strcat(buffer, elem->q_data);
+       if (elem->q_forw)
+           strcat(buffer, ", ");
+    }
+    strcat(buffer, ")");
+    if (strlen(buffer) > 64)
+       sprintf(buffer, "%s (? for help)", prompt);
+    GetValueFromUser(buffer, pointer);
+    if (**pointer == '?') {
+       sprintf(buffer, "Type %s is one of:", tname);
+       Put_message(buffer);
+       for (elem = GetTypeValues(tname); elem; elem = elem->q_forw) {
+           Put_message(elem->q_data);
+       }
+       *pointer = strsave(def);
+       return(GetTypeFromUser(prompt, tname, pointer));
+    }
+    for (elem = GetTypeValues(tname); elem; elem = elem->q_forw) {
+       if (!cistrcmp(elem->q_data, *pointer))
+           return(SUB_NORMAL);
+    }
+    sprintf(buffer, "\"%s\" is not a legal value for %s.  Use one of:",
+           *pointer, tname);
+    Put_message(buffer);
+    for (elem = GetTypeValues(tname); elem; elem = elem->q_forw) {
+       Put_message(elem->q_data);
+    }
+    sprintf(buffer, "Are you sure you want \"%s\" to be a legal %s",
+           *pointer, tname);
+    if (YesNoQuestion("Do you want this to be a new legal value", 0) &&
+       YesNoQuestion(buffer, 0)) {
+       argv[0] = tname;
+       argv[1] = "TYPE";
+       argv[2] = *pointer;
+       for (p = argv[2]; *p; p++)
+           if (islower(*p))
+               *p = toupper(*p);
+       if (stat = do_sms_query("add_alias", 3, argv, Scream, NULL)) {
+           com_err(program_name, stat, " in add_alias");
+       } else {
+           elem = (struct qelem *) malloc(sizeof(struct qelem));
+           elem->q_data = strsave(*pointer);
+           AddQueue(elem, GetTypeValues(tname));
+           Put_message("Done.");
+       }
+    }
+    *pointer = strsave(def);
+    return(GetTypeFromUser(prompt, tname, pointer));
+}
+
+
+do_sms_query(name, argc, argv, proc, hint)
+char *name;
+int argc;
+char **argv;
+int (*proc)();
+char *hint;
+{
+    int status;
+    extern char *whoami;
+
+    status = sms_query(name, argc, argv, proc, hint);
+    if (status != SMS_ABORTED && status != SMS_NOT_CONNECTED)
+      return(status);
+    status = sms_connect(SMS_SERVER);
+    if (status) {
+       com_err(whoami, status, " while re-connecting to server");
+       return(SMS_ABORTED);
+    }
+    status = sms_auth(whoami);
+    if (status) {
+       com_err(whoami, status, " while re-authenticating to server");
+       sms_disconnect();
+       return(SMS_ABORTED);
+    }
+    status = sms_query(name, argc, argv, proc, hint);
+    return(status);
+}
+
This page took 0.089984 seconds and 4 git commands to generate.