halsh.c
1 // Copyright 2007-2013, various authors 2 // 3 // This program is free software; you can redistribute it and/or modify 4 // it under the terms of the GNU General Public License as published by 5 // the Free Software Foundation; either version 2 of the License, or 6 // (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU General Public License for more details. 12 // 13 // You should have received a copy of the GNU General Public License 14 // along with this program; if not, write to the Free Software 15 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16 17 #include <string.h> 18 #include <stdlib.h> 19 #include <stdio.h> 20 #include <tcl.h> 21 #include "halcmd.h" 22 23 Tcl_Interp *target_interp = NULL; 24 static int pending_cr = 0; 25 26 static void halError(Tcl_Interp *interp, int result) { 27 // Usually, halcmd leaves a good string message via halcmd_error() 28 // but just in case, fall back to using the result of the halcmd api call as 29 // a negative errno value... 30 if(!*Tcl_GetStringResult(interp)) 31 Tcl_SetResult(interp, strerror(-result), TCL_VOLATILE); 32 } 33 34 static int refcount = 0; 35 36 static void shutdown(void) { 37 if(refcount > 0) { 38 refcount --; 39 if(refcount == 0) halcmd_shutdown(); 40 } 41 } 42 43 static int init() { 44 int result = 0; 45 if(refcount == 0) { 46 result = halcmd_startup(0); 47 atexit(shutdown); 48 } 49 if(result == 0) { 50 refcount ++; 51 } 52 return result; 53 } 54 static void halExit(ClientData d) { 55 shutdown(); 56 } 57 58 static int halCmd(ClientData cd, Tcl_Interp *interp, int argc, const char **argv) { 59 int result; 60 Tcl_ResetResult(interp); 61 62 if(argc < 2) { 63 Tcl_AppendResult(interp, 64 "wrong # args: should be \"", argv[0], " command ...\"", NULL); 65 return TCL_ERROR; 66 } 67 68 if(strcmp(argv[1], "--commands") == 0) 69 { 70 int i; 71 Tcl_ResetResult(interp); 72 for(i=0; i<halcmd_ncommands; i++) 73 Tcl_AppendElement(interp, halcmd_commands[i].name); 74 return TCL_OK; 75 } 76 77 target_interp = interp; 78 pending_cr = 0; 79 result = halcmd_parse_cmd((char **)argv+1); 80 target_interp = NULL; 81 82 if(result == 0) return TCL_OK; 83 halError(interp, result); 84 return TCL_ERROR; 85 } 86 87 int Hal_Init(Tcl_Interp *interp) { 88 int result = init(); 89 if(result < 0) { 90 Tcl_ResetResult(interp); 91 halError(interp, result); 92 return TCL_ERROR; 93 } 94 95 if (Tcl_InitStubs(interp, "8.1", 0) == NULL) 96 { 97 return TCL_ERROR; 98 } 99 100 Tcl_CreateCommand(interp, "hal", halCmd, 0, halExit); 101 102 Tcl_PkgProvide(interp, "Hal", "1.0"); 103 return TCL_OK; 104 } 105 106 #ifndef BUFFERLEN 107 #define BUFFERLEN 1024 108 #endif 109 110 void halcmd_output(const char *format, ...) { 111 char buf[BUFFERLEN + 1]; 112 va_list ap; 113 int len; 114 115 va_start(ap, format); 116 vsnprintf(buf, BUFFERLEN, format, ap); 117 va_end(ap); 118 119 if(pending_cr) 120 Tcl_AppendResult(target_interp, "\n", NULL); 121 len = strlen(buf); 122 if(buf[len-1] == '\n') { 123 buf[len-1] = 0; 124 pending_cr = 1; 125 } else { 126 pending_cr = 0; 127 } 128 Tcl_AppendResult(target_interp, buf, NULL); 129 } 130 131 void halcmd_error(const char *format, ...) { 132 char buf[BUFFERLEN + 1]; 133 va_list ap; 134 int len; 135 136 va_start(ap, format); 137 vsnprintf(buf, BUFFERLEN, format, ap); 138 va_end(ap); 139 140 if(pending_cr) 141 Tcl_AppendResult(target_interp, "\n", NULL); 142 len = strlen(buf); 143 if(buf[len-1] == '\n') { 144 buf[len-1] = 0; 145 pending_cr = 1; 146 } else { 147 pending_cr = 0; 148 } 149 Tcl_AppendResult(target_interp, buf, NULL); 150 } 151 152 void halcmd_warning(const char *format, ...) { 153 char buf[BUFFERLEN + 1]; 154 va_list ap; 155 int len; 156 157 va_start(ap, format); 158 vsnprintf(buf, BUFFERLEN, format, ap); 159 va_end(ap); 160 161 if(pending_cr) 162 Tcl_AppendResult(target_interp, "\n", NULL); 163 len = strlen(buf); 164 if(buf[len-1] == '\n') { 165 buf[len-1] = 0; 166 pending_cr = 1; 167 } else { 168 pending_cr = 0; 169 } 170 Tcl_AppendResult(target_interp, buf, NULL); 171 } 172 173 void halcmd_info(const char *format, ...) { 174 char buf[BUFFERLEN + 1]; 175 va_list ap; 176 int len; 177 178 va_start(ap, format); 179 vsnprintf(buf, BUFFERLEN, format, ap); 180 va_end(ap); 181 182 if(pending_cr) 183 Tcl_AppendResult(target_interp, "\n", NULL); 184 len = strlen(buf); 185 if(buf[len-1] == '\n') { 186 buf[len-1] = 0; 187 pending_cr = 1; 188 } else { 189 pending_cr = 0; 190 } 191 Tcl_AppendResult(target_interp, buf, NULL); 192 } 193