1/* 2 * $FreeBSD$ 3 * 4 * Copyright (c) 1995 5 * Jordan Hubbard. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer, 12 * verbatim and that no modifications are made prior to this 13 * point in the file. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 */ 31 32#include "sade.h" 33 34#define MAX_NUM_COMMANDS 10 35 36typedef struct { 37 char key[FILENAME_MAX]; 38 struct { 39 enum { CMD_SHELL, CMD_FUNCTION } type; 40 void *ptr, *data; 41 } cmds[MAX_NUM_COMMANDS]; 42 int ncmds; 43} Command; 44 45#define MAX_CMDS 200 46static Command *commandStack[MAX_CMDS]; 47int numCommands; 48 49/* Nuke the command stack */ 50void 51command_clear(void) 52{ 53 int i, j; 54 55 for (i = 0; i < numCommands; i++) 56 for (j = 0; j < commandStack[i]->ncmds; j++) 57 if (commandStack[i]->cmds[j].type == CMD_SHELL) 58 free(commandStack[i]->cmds[j].ptr); 59 free(commandStack[i]); 60 numCommands = 0; 61} 62 63static void 64addit(char *key, int type, void *cmd, void *data) 65{ 66 int i; 67 68 /* First, look for the key already present and add a command to it if found */ 69 for (i = 0; i < numCommands; i++) { 70 if (!strcmp(commandStack[i]->key, key)) { 71 if (commandStack[i]->ncmds == MAX_NUM_COMMANDS) 72 msgFatal("More than %d commands stacked up behind %s??", MAX_NUM_COMMANDS, key); 73 commandStack[i]->cmds[commandStack[i]->ncmds].type = type; 74 commandStack[i]->cmds[commandStack[i]->ncmds].ptr = cmd; 75 commandStack[i]->cmds[commandStack[i]->ncmds].data = data; 76 ++(commandStack[i]->ncmds); 77 return; 78 } 79 } 80 if (numCommands == MAX_CMDS) 81 msgFatal("More than %d commands accumulated??", MAX_CMDS); 82 83 /* If we fell to here, it's a new key */ 84 commandStack[numCommands] = safe_malloc(sizeof(Command)); 85 strcpy(commandStack[numCommands]->key, key); 86 commandStack[numCommands]->ncmds = 1; 87 commandStack[numCommands]->cmds[0].type = type; 88 commandStack[numCommands]->cmds[0].ptr = cmd; 89 commandStack[numCommands]->cmds[0].data = data; 90 ++numCommands; 91} 92 93/* Add a shell command under a given key */ 94void 95command_shell_add(char *key, const char *fmt, ...) 96{ 97 va_list args; 98 char *cmd; 99 100 cmd = (char *)safe_malloc(256); 101 va_start(args, fmt); 102 vsnprintf(cmd, 256, fmt, args); 103 va_end(args); 104 105 addit(key, CMD_SHELL, cmd, NULL); 106} 107 108/* Add a shell command under a given key */ 109void 110command_func_add(char *key, commandFunc func, void *data) 111{ 112 addit(key, CMD_FUNCTION, func, data); 113} 114 115static int 116sort_compare(Command *p1, Command *p2) 117{ 118 if (!p1 && !p2) 119 return 0; 120 else if (!p1 && p2) /* NULL has a "greater" value for commands */ 121 return 1; 122 else if (p1 && !p2) 123 return -1; 124 else 125 return strcmp(p1->key, p2->key); 126} 127 128void 129command_sort(void) 130{ 131 int i, j; 132 133 commandStack[numCommands] = NULL; 134 /* Just do a crude bubble sort since the list is small */ 135 for (i = 0; i < numCommands; i++) { 136 for (j = 0; j < numCommands; j++) { 137 if (sort_compare(commandStack[j], commandStack[j + 1]) > 0) { 138 Command *tmp = commandStack[j]; 139 140 commandStack[j] = commandStack[j + 1]; 141 commandStack[j + 1] = tmp; 142 } 143 } 144 } 145} 146 147/* Run all accumulated commands in sorted order */ 148void 149command_execute(void) 150{ 151 int i, j, ret; 152 commandFunc func; 153 154 for (i = 0; i < numCommands; i++) { 155 for (j = 0; j < commandStack[i]->ncmds; j++) { 156 /* If it's a shell command, run system on it */ 157 if (commandStack[i]->cmds[j].type == CMD_SHELL) { 158 msgNotify("Doing %s", (char *)commandStack[i]->cmds[j].ptr); 159 ret = vsystem("%s", (char *)commandStack[i]->cmds[j].ptr); 160 if (isDebug()) 161 msgDebug("Command `%s' returns status %d\n", 162 (char *)commandStack[i]->cmds[j].ptr, ret); 163 } 164 else { 165 /* It's a function pointer - call it with the key and 166 the data */ 167 func = (commandFunc)commandStack[i]->cmds[j].ptr; 168 if (isDebug()) 169 msgDebug("%p: Execute(%s, %s)\n", 170 func, commandStack[i]->key, 171 (char *)commandStack[i]->cmds[j].data); 172 ret = (*func)(commandStack[i]->key, commandStack[i]->cmds[j].data); 173 if (isDebug()) 174 msgDebug("Function @ %p returns status %d\n", 175 commandStack[i]->cmds[j].ptr, ret); 176 } 177 } 178 } 179} 180