/***************************************************************************/
/***************************************************************************/
/* */
/* (c) 1995-1999. The Regents of the University of California. All */
/* rights reserved. */
/* */
/* This work was produced at the University of California, Lawrence */
/* Livermore National Laboratory (UC LLNL) under contract no. */
/* W-7405-ENG-48 (Contract 48) between the U.S. Department of Energy */
/* (DOE) and The Regents of the University of California (University) */
/* for the operation of UC LLNL. Copyright is reserved to the */
/* University for purposes of controlled dissemination, */
/* commercialization through formal licensing, or other disposition */
/* under terms of Contract 48; DOE policies, regulations and orders; */
/* and U.S. statutes. The rights of the Federal Government are */
/* reserved under Contract 48 subject to the restrictions agreed upon */
/* by the DOE and University. */
/* */
/* */
/* DISCLAIMER */
/* */
/* This software was prepared as an account of work sponsored by an */
/* agency of the United States Government. Neither the United States */
/* Government nor the University of California nor any of their */
/* employees, makes any warranty, express or implied, or assumes any */
/* liability or responsibility for the accuracy, completeness, or */
/* usefulness of any information, apparatus, product, or process */
/* disclosed, or represents that its specific commercial products, */
/* process, or service by trade name, trademark, manufacturer, or */
/* otherwise, does not necessarily constitute or imply its */
/* endorsement, recommendation, or favoring by the United States */
/* Government or the University of California. The views and opinions */
/* of the authors expressed herein do not necessarily state or reflect */
/* those of the United States Government or the University of */
/* California, and shall not be used for advertising or product */
/* endorsement purposes. */
/* */
/* Permission to use, copy, modify and distribute this software and its */
/* documentation for any non-commercial purpose, without fee, is */
/* hereby granted, provided that the above copyright notice and this */
/* permission notice appear in all copies of the software and */
/* supporting documentation, and that all UC LLNL identification in */
/* the user interface remain unchanged. The title to copyright LLNL */
/* XDIR shall at all times remain with The Regents of the University */
/* of California and users agree to preserve same. Users seeking the */
/* right to make derivative works with LLNL XDIR for commercial */
/* purposes may obtain a license from the Lawrence Livermore National */
/* Laboratory's Technology Transfer Office, P.O. Box 808, L-795, */
/* Livermore, CA 94550. */
/* */
/***************************************************************************/
/***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <Xm/Xm.h>
#include "xdir.h"
#include "list.h"
#include "history.h"
#include "str.h"
#define CURRENT_HISTORY_VERSION 3
#define FIRST_HISTORY_FILE ".xdircache"
#define CURRENT_HISTORY_FILE ".xdirhistory"
#define SAVED_HISTORY_FILE ".xdirhistory-old"
#define MAXHLINE 200
struct history_st *history = NULL;
static char *reformat_msg = "Your LLNL XDIR history file, $HOME/%s,\nhas been reformatted. If you wish to run your\nold version of LLNL XDIR, first change the name\nof $HOME/%s to $HOME/%s.";
static int history_version = CURRENT_HISTORY_VERSION;
static char *current_history_file;
static char *first_history_file;
static char *saved_history_file;
static char *history_file;
static char *history_label[] = {
"Dir:",
"Wildcard:",
"User:",
"Quote:"
};
extern int max_history_hosts;
extern int max_history[];
void add_to_history();
/*
* construct_history_filename - Form all possible history file names.
*/
void
construct_history_filename()
{
char *homedir = getenv("HOME");
/* Construct current file name */
current_history_file = XtMalloc(strlen(homedir)+strlen(CURRENT_HISTORY_FILE)
+2);
strcpy(current_history_file, homedir);
strcat(current_history_file, "/");
strcat(current_history_file, CURRENT_HISTORY_FILE);
/* Construct obsolete file name */
first_history_file = XtMalloc(strlen(homedir)+strlen(FIRST_HISTORY_FILE)+2);
strcpy(first_history_file, homedir);
strcat(first_history_file, "/");
strcat(first_history_file, FIRST_HISTORY_FILE);
/* Construct saved file name */
saved_history_file = XtMalloc(strlen(homedir)+strlen(SAVED_HISTORY_FILE)+2);
strcpy(saved_history_file, homedir);
strcat(saved_history_file, "/");
strcat(saved_history_file, SAVED_HISTORY_FILE);
}
/*
* save_history - Write current history entries to history file. Returns 0
* if successful, else -1. w_parent is the widget to center
* error dialogs over.
*/
save_history(w_parent)
Widget w_parent;
{
static FILE *fp;
struct host_link *hptr;
struct item_link *cptr;
int i;
int saved_obsolete_file = False;
char *msg;
/* If obsolete history file is in use, save a copy of it */
if (history_version < CURRENT_HISTORY_VERSION) {
if (!history_file) /* Sanity check */
fatal_error("Bug in save_history()");
if (rename(history_file, saved_history_file) == 0)
saved_obsolete_file = True;
}
/* Create the new history file */
if ((fp = fopen(current_history_file, "w")) == NULL)
return -1;
/* First line of history file contains version number */
fprintf(fp, "History_Version: %d\n", CURRENT_HISTORY_VERSION);
/* Save history */
hptr = history->host_tail;
while (hptr) {
fprintf(fp, "Host: %s\n", hptr->host_name);
for (i=0; i<NUMKINDS; i++) {
cptr = hptr->kind[i].tail;
while (cptr) {
fprintf(fp, " %s %s\n", history_label[i], cptr->value);
cptr = cptr->prev;
}
}
hptr = hptr->prev;
}
fclose(fp);
/* If an obsolete history file is in use, tell user it was saved */
if (saved_obsolete_file) {
msg = XtMalloc(strlen(reformat_msg)+60);
if (history_version < 3)
sprintf(msg, reformat_msg, FIRST_HISTORY_FILE, SAVED_HISTORY_FILE,
FIRST_HISTORY_FILE);
else
sprintf(msg, reformat_msg, CURRENT_HISTORY_FILE,
SAVED_HISTORY_FILE, CURRENT_HISTORY_FILE);
info_dialog(msg, w_parent);
XtFree(msg);
}
return 0;
}
/*
* read_history_from_file - Initialize history entries with info from
* history file.
*/
void
read_history_from_file()
{
FILE *fp;
char history_line[MAXHLINE+1];
int len;
char *id;
char *value;
char *host_name = NULL;
int i;
/* Verify that history is empty (Sanity check) */
if (history)
fatal_error("Bug in read_history_from_file()");
/* Initialize history */
history = XtNew(struct history_st);
history->host_head = NULL;
history->host_tail = NULL;
history->host_count = 0;
/* Try to open history file */
if ((fp = fopen(current_history_file, "r")))
history_file = current_history_file;
else if ((fp = fopen(first_history_file, "r")))
history_file = first_history_file;
else {
history_file = NULL;
return;
}
/* Process history info */
history_version = 1;
while (fgets(history_line, MAXHLINE+1, fp) != NULL) {
len = strlen(history_line);
if (history_line[len-1] != '\n')
continue;
if ((id = strtok(history_line, "\t\n ")) == NULL)
continue;
if ((value = strtok(NULL, "\n")) == NULL)
continue;
if (strcmp(id, "Cache_Version:") == 0)
sscanf(value, "%d", &history_version);
if (strcmp(id, "History_Version:") == 0)
sscanf(value, "%d", &history_version);
if (strcmp(id, "Host:") == 0) {
XtFree(host_name);
host_name = XtNewString(value);
} else
for (i=0; i<NUMKINDS; i++)
if (strcmp(id, history_label[i]) == 0) {
/* Fix switched "Quote:"/"User:" in early history files */
if (history_version == 1) {
if (i == USER)
i = QUOTE;
else if (i == QUOTE)
i = USER;
}
if (host_name)
add_to_history(i, host_name, value);
break;
}
}
fclose(fp);
XtFree(host_name);
}
/*
* add_to_history - Add the specified host and value to the history
* specified with "kind_id" (DIRECTORY, WILDCARD,
* QUOTE or USER).
*/
void
add_to_history(kind_id, host_name, value)
int kind_id;
char *host_name;
char *value;
{
struct host_link *hptr;
struct item_link *cptr;
struct item_link *next;
int i;
int found;
/* Search for host name */
found = False;
if (history->host_head) {
hptr = history->host_head;
while (hptr) {
if (strcmp(hptr->host_name, host_name) == 0) {
found = True;
break;
}
hptr = hptr->next;
}
}
/* If host name found, move to head of list, else create entry for host */
if (found) {
if (hptr != history->host_head) {
hptr->prev->next = hptr->next;
if (hptr == history->host_tail)
history->host_tail = hptr->prev;
else
hptr->next->prev = hptr->prev;
hptr->prev = NULL;
hptr->next = history->host_head;
history->host_head->prev = hptr;
history->host_head = hptr;
}
} else {
hptr = XtNew(struct host_link);
for (i=0; i<NUMKINDS; i++) {
hptr->kind[i].head = NULL;
hptr->kind[i].tail = NULL;
hptr->kind[i].count = 0;
}
hptr->host_name = XtNewString(host_name);
hptr->next = history->host_head;
hptr->prev = NULL;
if (history->host_head)
history->host_head->prev = hptr;
history->host_head = hptr;
if (history->host_tail == NULL)
history->host_tail = hptr;
history->host_count++;
}
/* If necessary, reduce number of host entries to maximum allowable */
while (history->host_count > max_history_hosts) {
hptr = history->host_tail;
history->host_tail = hptr->prev;
XtFree(hptr->host_name);
for (i=0; i<NUMKINDS; i++) {
cptr = hptr->kind[i].head;
while (cptr) {
XtFree(cptr->value);
next = cptr->next;
XtFree((char *)cptr);
cptr = next;
}
}
XtFree((char *)hptr);
history->host_tail->next = NULL;
history->host_count--;
}
/* Search the history for the value */
found = False;
if (history->host_head->kind[kind_id].head) {
cptr = history->host_head->kind[kind_id].head;
while (cptr) {
if (strcmp(cptr->value, value) == 0) {
found = True;
break;
}
cptr = cptr->next;
}
}
/* If value found, move to head of list, else create entry for value */
if (found) {
if (cptr != history->host_head->kind[kind_id].head) {
cptr->prev->next = cptr->next;
if (cptr == history->host_head->kind[kind_id].tail)
history->host_head->kind[kind_id].tail = cptr->prev;
else
cptr->next->prev = cptr->prev;
cptr->prev = NULL;
cptr->next = history->host_head->kind[kind_id].head;
history->host_head->kind[kind_id].head->prev = cptr;
history->host_head->kind[kind_id].head = cptr;
}
} else {
cptr = XtNew(struct item_link);
cptr->value = XtNewString(value);
cptr->next = history->host_head->kind[kind_id].head;
cptr->prev = NULL;
if (history->host_head->kind[kind_id].head)
history->host_head->kind[kind_id].head->prev = cptr;
history->host_head->kind[kind_id].head = cptr;
if (history->host_head->kind[kind_id].tail == NULL)
history->host_head->kind[kind_id].tail = cptr;
history->host_head->kind[kind_id].count++;
}
/* If necessary, reduce number of values in history to maximum allowable */
while (history->host_head->kind[kind_id].count > max_history[kind_id]) {
cptr = history->host_head->kind[kind_id].tail;
history->host_head->kind[kind_id].tail = cptr->prev;
XtFree(cptr->value);
XtFree((char *)cptr);
history->host_head->kind[kind_id].tail->next = NULL;
history->host_head->kind[kind_id].count--;
}
}
/*
* retrieve_history - Sets "list" to point to a struct containing the
* history values for "hostname" ("kind_id" can
* have the values DIRECTORY, WILDCARD, QUOTE or USER).
* Memory pointed to by "list" should be released by
* calling release_array_list(). If the "sort"
* flag is set, then the list is returned sorted,
* otherwise it is returned in order of last use.
*/
void
retrieve_history(kind_id, hostname, list, sort)
int kind_id;
char *hostname;
struct sl_struct **list;
int sort;
{
char **values;
int indx;
struct host_link *hptr;
struct item_link *cptr;
/* Search for host name */
hptr = history->host_head;
while (hptr) {
if (strcmp(hptr->host_name, hostname) == 0)
break;
hptr = hptr->next;
}
/* If host name not found, return empty list */
if (hptr == NULL) {
*list = XtNew(struct sl_struct);
(*list)->nentries = 0;
(*list)->entries = (char **)XtMalloc(0);
return;
}
/* Host name found. Convert linked list of values into array */
values = (char **)XtMalloc(sizeof(char *)*hptr->kind[kind_id].count);
cptr = hptr->kind[kind_id].head;
indx = 0;
while (cptr) {
values[indx] = XtNewString(cptr->value);
indx++;
cptr = cptr->next;
}
/* Sanity check */
if (indx != hptr->kind[kind_id].count)
fatal_error("Bug in retrieve_history()");
/* Sort entries */
if (sort)
quicksort(values, hptr->kind[kind_id].count, strcmp);
/* Return struct */
*list = XtNew(struct sl_struct);
(*list)->nentries = hptr->kind[kind_id].count;
(*list)->entries = values;
}
/*
* retrieve_hostuser_history - Sets "list" to point to a struct containing the
* expressions in the hostname/username history.
* Memory pointed to by "list" should be released
* by calling release_array_list(). If the "sort"
* flag is set, then the list is returned sorted,
* otherwise it is returned in order of last use.
*/
void
retrieve_hostuser_history(list, sort)
struct sl_struct **list;
int sort;
{
char **hostusers;
int hostuser_count;
struct host_link *hptr;
struct item_link *cptr;
int indx;
/* Count number of host user pairs */
hostuser_count = 0;
hptr = history->host_head;
while (hptr) {
cptr = hptr->kind[USER].head;
while (cptr) {
hostuser_count++;
cptr = cptr->next;
}
hptr = hptr->next;
}
/* Convert linked list of hostname/username pairs into array */
hostusers = (char **)XtMalloc(sizeof(char *)*hostuser_count);
indx = 0;
hptr = history->host_head;
while (hptr) {
cptr = hptr->kind[USER].head;
while (cptr) {
hostusers[indx] = XtMalloc(strlen(hptr->host_name)+
strlen(cptr->value)+6);
sprintf(hostusers[indx], "%s (%s)", hptr->host_name,cptr->value);
indx++;
cptr = cptr->next;
}
hptr = hptr->next;
}
/* Sanity check */
if (indx != hostuser_count)
fatal_error("Bug in retrieve_hostuser_history()");
/* Sort entries */
if (sort)
quicksort(hostusers, hostuser_count, strcmp);
/* Return struct */
*list = XtNew(struct sl_struct);
(*list)->nentries = hostuser_count;
(*list)->entries = hostusers;
}
syntax highlighted by Code2HTML, v. 0.9.1