/********************************************************************* v.1 historee.c functions for creating, maintaining and cleaning dynamic history buffers... an excersise in pointer play Requirments: ewtoo talker (altho with minor mods it can go into any C app) Installing: place this file into your src dir, have it compile as an object of your talker add the following struct to player.h somewhere ... typedef struct history { char **hist; int max; } history; add the following externs to proto.h or player.h ... extern history *init_hist ( int ); extern void add_to_hist ( history *, char * ); extern int stack_hist ( history *, int, char * ); extern void clean_hist ( history * ); extern void free_hist ( history * ); extern void init_global_histories ( void ); extern void to_suhist ( char * ); extern history *SuHistory; put two commands for the functions view_su_history (should be avaible to anyone with su channel) zap_suhist (written to be admin only) in su_wall, su_wall_but, put this at the top, after decls add_to_hist (SuHistory, str); as well as in any other functions you have that talk directly to the sus ... Notes: included is an example of a history buffer in action that being for the suchannel... to add a history to anything else, just give it a history * pointer, either in the struct for it or as a global var (depending on how you will need it), init_history to give it some memory, add items to it with the add_to_hist, use stack_hist as a possible method to retrieve the history, and free_hist when you are finished. included is a lil strcasestr i wrote for speed not beauty... it works..its fast....its not as pretty as it could be... but its better than strstr Bug Reports: send to phypor@benland.muc.edu Licences: freely distributable and modifiable, as long as credit given in appropritate places for any distrubitions (be it this alone or within another package) Warranty: non, the author is in no way responsible for use, misuse, abuse, or any other actions misactions, reactions of this code, its provided as is. Author: phypor "if it breaks you get to keep both pieces" ~old linux proverb *********************************************************************/ #include #include #include #include #include "config.h" #include "proto.h" #define HIST_SU 50 history *SuHistory; char *strcasestr ( char * haystack, char * needle ) { char s[5], *nptr, *hptr; if (!needle || !*needle) return (char *) NULL; memset (s, 0, 5); strncpy (s, needle, 4); lower_case (s); while (*haystack) { if (tolower (*haystack) == s[0]) { if (!s[1]) return haystack; if (*(haystack + 1) && tolower (*(haystack + 1)) == s[1]) { if (!s[2]) return haystack; if (*(haystack + 2) && tolower (*(haystack + 2)) == s[2]) { if (!s[3]) return haystack; if (*(haystack + 3) && tolower (*(haystack + 3)) == s[3]) { hptr = haystack + 4; nptr = needle + 4; for (; *nptr && *hptr; nptr++, hptr++) if (tolower (*nptr) != tolower (*hptr)) break; if (!*nptr) return haystack; } } } } haystack++; } /* strstr returns NULL, not an actual char that is NULL... so we will follow its way */ return (char *) NULL; } history *init_hist ( int max ) { history *nh; nh = (history *) malloc (sizeof (history)); if (!nh) { log ("error", "Failed to malloc history."); return (history *) NULL; } memset (nh, 0, sizeof (history)); nh->hist = (char **) malloc ((max + 1) * sizeof (char *)); if (!nh->hist) { FREE (nh); log ("error", "Failed to malloc history."); return (history *) NULL; } memset (nh->hist, 0, max * sizeof (char *)); nh->max = max; return nh; } void add_to_hist ( history * h, char * str ) { int i; if (!h) /* malloc failed at some point... */ return; for (i = 0; i < h->max; i++) /* find the first free one */ if (!h->hist[i]) break; if (i == h->max) /* if the handles are full */ { free (h->hist[i - 1]); /* get rid of the last one */ h->hist[i - 1] = (char *) NULL; } for (i = h->max; i > 0; i--) /* shift the handles down */ h->hist[i] = h->hist[i - 1]; /* malloc something to point to */ h->hist[0] = (char *) malloc (strlen (str) + 1); if (!h->hist[0]) /* make sure we got it */ { log ("error", "Failed to malloc history"); return; } /* clean it and put it in */ memset (h->hist[0], 0, strlen (str) + 1); strcpy (h->hist[0], str); } int stack_hist ( history * h, int lines, char * needle ) { int i; if (!h || !h->hist[0]) return -1; for (i = 0; h->hist[i + 1]; i++); /* get to the end to put the oldest top */ if (lines > 0) i = i < lines ? i : lines - 1; /* use the smallest */ if (!needle || !*needle) for (; i >= 0; i--) stack += sprintf (stack, "%s", h->hist[i]); else for (; i >= 0; i--) if (strcasestr (h->hist[i], needle)) stack += sprintf (stack, "%s", h->hist[i]); return 0; } void clean_hist ( history * h ) { int i; if (!h || !h->hist) /* make sure its got memory */ return; for (i = 0; i < h->max; i++) if (h->hist[i]) { free (h->hist[i]); h->hist[i] = (char *) NULL; } } void free_hist ( history * h ) { clean_hist (h); free (h->hist); free (h); } void init_global_histories ( void ) { SuHistory = init_hist (HIST_SU); } /* su history */ void zap_suhist ( player * p, char * str ) { clean_hist (SuHistory); tell_player (p, " SuperUsers History zapped!\n"); } void view_su_history ( player * p, char * str ) { char *oldstack = stack, *needle = ""; int lines = -1; if (*str && !strcmp (str, "?")) /* use strcmp so ? can be first char of pattern to be matched */ { tell_player (p, " Format : suhist to view the entire suhist, unabriged\n" " suhist # to view the mot recent # of lines\n" " suhist to view all lines strcasestr'ing \n" " suhist ? to view the format\n"); return; } if (*str && isdigit (*str)) { lines = atoi (str); if (lines < 2) lines = 2; stack += sprintf (stack, "--- SuperUsers History (last %d lines) ---\n", lines); } else if (*str) { stack += sprintf (stack, "--- SuperUsers History (searching %s) ---\n", str); needle = str; } else stack += sprintf (stack, "--- SuperUsers History --------------------\n"); if (stack_hist (SuHistory, lines, needle) < 0) { tell_player (p, " SuperUsers History is empty.\n"); stack = oldstack; return; } stack += sprintf (stack, "-------------------------------------------\n"); stack = end_string (stack); tell_player (p, oldstack); stack = oldstack; }