1/* 2 * dig_opt.c -- 3 * 4 * Implements the C level procedures handling option processing 5 * for message digest generators. 6 * 7 * 8 * Copyright (c) 1996 Andreas Kupries (a.kupries@westend.com) 9 * All rights reserved. 10 * 11 * Permission is hereby granted, without written agreement and without 12 * license or royalty fees, to use, copy, modify, and distribute this 13 * software and its documentation for any purpose, provided that the 14 * above copyright notice and the following two paragraphs appear in 15 * all copies of this software. 16 * 17 * IN NO EVENT SHALL I LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, 18 * INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS 19 * SOFTWARE AND ITS DOCUMENTATION, EVEN IF I HAVE BEEN ADVISED OF THE 20 * POSSIBILITY OF SUCH DAMAGE. 21 * 22 * I SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 * PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND 25 * I HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 26 * ENHANCEMENTS, OR MODIFICATIONS. 27 * 28 * CVS: $Id: dig_opt.c,v 1.11 2009/05/07 04:57:27 andreas_kupries Exp $ 29 */ 30 31#include "transformInt.h" 32 33/* 34 * forward declarations of all internally used procedures. 35 */ 36 37static Trf_Options CreateOptions _ANSI_ARGS_ ((ClientData clientData)); 38static void DeleteOptions _ANSI_ARGS_ ((Trf_Options options, 39 ClientData clientData)); 40static int CheckOptions _ANSI_ARGS_ ((Trf_Options options, 41 Tcl_Interp* interp, 42 CONST Trf_BaseOptions* baseOptions, 43 ClientData clientData)); 44static int SetOption _ANSI_ARGS_ ((Trf_Options options, 45 Tcl_Interp* interp, 46 CONST char* optname, 47 CONST Tcl_Obj* optvalue, 48 ClientData clientData)); 49 50static int QueryOptions _ANSI_ARGS_ ((Trf_Options options, 51 ClientData clientData)); 52 53static int TargetType _ANSI_ARGS_ ((Tcl_Interp* interp, 54 CONST char* typeString, 55 int* isChannel)); 56 57static int DigestMode _ANSI_ARGS_ ((Tcl_Interp* interp, 58 CONST char* modeString, 59 int* mode)); 60 61/* 62 *------------------------------------------------------* 63 * 64 * TrfMDOptions -- 65 * 66 * ------------------------------------------------* 67 * Accessor to the set of vectors realizing option 68 * processing for message digest generators. 69 * ------------------------------------------------* 70 * 71 * Sideeffects: 72 * None. 73 * 74 * Result: 75 * See above. 76 * 77 *------------------------------------------------------* 78 */ 79 80Trf_OptionVectors* 81TrfMDOptions () 82{ 83 static Trf_OptionVectors optVec = /* THREADING: constant, read-only => safe */ 84 { 85 CreateOptions, 86 DeleteOptions, 87 CheckOptions, 88 NULL, /* no string procedure for 'SetOption' */ 89 SetOption, 90 QueryOptions, 91 NULL /* unseekable, unchanged by options */ 92 }; 93 94 return &optVec; 95} 96 97/* 98 *------------------------------------------------------* 99 * 100 * CreateOptions -- 101 * 102 * ------------------------------------------------* 103 * Create option structure for message digest generators. 104 * ------------------------------------------------* 105 * 106 * Sideeffects: 107 * Allocates memory and initializes it as 108 * option structure for message digest generators. 109 * 110 * Result: 111 * A reference to the allocated block of 112 * memory. 113 * 114 *------------------------------------------------------* 115 */ 116 117static Trf_Options 118CreateOptions (clientData) 119ClientData clientData; 120{ 121 TrfMDOptionBlock* o; 122 123 o = (TrfMDOptionBlock*) ckalloc (sizeof (TrfMDOptionBlock)); 124 o->behaviour = TRF_IMMEDIATE; /* irrelevant until set by 'CheckOptions' */ 125 o->mode = TRF_UNKNOWN_MODE; 126 o->readDestination = (char*) NULL; 127 o->writeDestination = (char*) NULL; 128 o->rdIsChannel = 0; 129 o->wdIsChannel = 1; 130 o->matchFlag = (char*) NULL; 131 o->vInterp = (Tcl_Interp*) NULL; 132 o->rdChannel = (Tcl_Channel) NULL; 133 o->wdChannel = (Tcl_Channel) NULL; 134 135 return (Trf_Options) o; 136} 137 138/* 139 *------------------------------------------------------* 140 * 141 * DeleteOptions -- 142 * 143 * ------------------------------------------------* 144 * Delete option structure of a message digest generators. 145 * ------------------------------------------------* 146 * 147 * Sideeffects: 148 * A memory block allocated by 'CreateOptions' 149 * is released. 150 * 151 * Result: 152 * None. 153 * 154 *------------------------------------------------------* 155 */ 156 157static void 158DeleteOptions (options, clientData) 159Trf_Options options; 160ClientData clientData; 161{ 162 TrfMDOptionBlock* o = (TrfMDOptionBlock*) options; 163 164 if (o->readDestination) { 165 ckfree ((char*) o->readDestination); 166 } 167 168 if (o->writeDestination) { 169 ckfree ((char*) o->writeDestination); 170 } 171 172 if (o->matchFlag) { 173 ckfree ((char*) o->matchFlag); 174 } 175 176 ckfree ((char*) o); 177} 178 179/* 180 *------------------------------------------------------* 181 * 182 * CheckOptions -- 183 * 184 * ------------------------------------------------* 185 * Check the given option structure for errors. 186 * ------------------------------------------------* 187 * 188 * Sideeffects: 189 * May modify the given structure to set 190 * default values into uninitialized parts. 191 * 192 * Result: 193 * A standard Tcl error code. 194 * 195 *------------------------------------------------------* 196 */ 197 198static int 199CheckOptions (options, interp, baseOptions, clientData) 200Trf_Options options; 201Tcl_Interp* interp; 202CONST Trf_BaseOptions* baseOptions; 203ClientData clientData; 204{ 205 TrfMDOptionBlock* o = (TrfMDOptionBlock*) options; 206 Trf_MessageDigestDescription* md_desc = (Trf_MessageDigestDescription*) clientData; 207 208 /* 209 * Call digest dependent check of environment first. 210 */ 211 212 START (dig_opt:CheckOptions); 213 214 if (md_desc->checkProc != NULL) { 215 if (TCL_OK != (*md_desc->checkProc) (interp)) { 216 DONE (dig_opt:CheckOptions); 217 return TCL_ERROR; 218 } 219 } 220 221 /* TRF_IMMEDIATE: no options allowed 222 * TRF_ATTACH: -mode required 223 * TRF_ABSORB_HASH: -matchflag required (only if channel is read) 224 * TRF_WRITE_HASH: -write/read-destination required according to 225 * access mode of attached channel. If a channel 226 * is used as target, then it has to be writable. 227 * TRF_TRANSPARENT: see TRF_WRITE_HASH. 228 */ 229 230 if (baseOptions->attach == (Tcl_Channel) NULL) { 231 if ((o->mode != TRF_UNKNOWN_MODE) || 232 (o->matchFlag != (char*) NULL) || 233 (o->readDestination != (char*) NULL) || 234 (o->writeDestination != (char*) NULL)) { 235 /* IMMEDIATE MODE */ 236 Tcl_AppendResult (interp, "immediate: no options allowed", (char*) NULL); 237 DONE (dig_opt:CheckOptions); 238 return TCL_ERROR; 239 } 240 } else { 241 /* ATTACH MODE / FILTER */ 242 if (o->mode == TRF_UNKNOWN_MODE) { 243 Tcl_AppendResult (interp, "attach: -mode not defined", (char*) NULL); 244 DONE (dig_opt:CheckOptions); 245 return TCL_ERROR; 246 247 } else if (o->mode == TRF_ABSORB_HASH) { 248 if ((baseOptions->attach_mode & TCL_READABLE) && 249 (o->matchFlag == (char*) NULL)) { 250 Tcl_AppendResult (interp, "attach: -matchflag not defined", (char*) NULL); 251 DONE (dig_opt:CheckOptions); 252 return TCL_ERROR; 253 } 254 255 } else if ((o->mode == TRF_WRITE_HASH) || (o->mode == TRF_TRANSPARENT)) { 256 if (o->matchFlag != (char*) NULL) { 257 Tcl_AppendResult (interp, "attach: -matchflag not allowed", (char*) NULL); 258 DONE (dig_opt:CheckOptions); 259 return TCL_ERROR; 260 } 261 262 if (baseOptions->attach_mode & TCL_READABLE) { 263 if (o->readDestination == (char*) NULL) { 264 Tcl_AppendResult (interp, "attach, external: -read-destination missing", 265 (char*) NULL); 266 DONE (dig_opt:CheckOptions); 267 return TCL_ERROR; 268 } else if (o->rdIsChannel) { 269 int mode; 270 o->rdChannel = Tcl_GetChannel (interp, (char*) o->readDestination, &mode); 271 272 if (o->rdChannel == (Tcl_Channel) NULL) { 273 DONE (dig_opt:CheckOptions); 274 return TCL_ERROR; 275 } else if (! (mode & TCL_WRITABLE)) { 276 Tcl_AppendResult (interp, 277 "read destination channel '", o->readDestination, 278 "' not opened for writing", (char*) NULL); 279 DONE (dig_opt:CheckOptions); 280 return TCL_ERROR; 281 } 282 } 283 } 284 285 if (baseOptions->attach_mode & TCL_WRITABLE) { 286 if (o->writeDestination == (char*) NULL) { 287 Tcl_AppendResult (interp, "attach, external: -write-destination missing", 288 (char*) NULL); 289 DONE (dig_opt:CheckOptions); 290 return TCL_ERROR; 291 } else if (o->wdIsChannel) { 292 int mode; 293 294 o->wdChannel = Tcl_GetChannel (interp, (char*) o->writeDestination, &mode); 295 296 if (o->wdChannel == (Tcl_Channel) NULL) { 297 DONE (dig_opt:CheckOptions); 298 return TCL_ERROR; 299 } else if (! (mode & TCL_WRITABLE)) { 300 Tcl_AppendResult (interp, 301 "write destination channel '", o->writeDestination, 302 "' not opened for writing", (char*) NULL); 303 DONE (dig_opt:CheckOptions); 304 return TCL_ERROR; 305 } 306 } 307 } 308 } else { 309 Tcl_Panic ("unknown mode given to dig_opt.c::CheckOptions"); 310 } 311 } 312 313 o->behaviour = (baseOptions->attach == (Tcl_Channel) NULL ? 314 TRF_IMMEDIATE : 315 TRF_ATTACH); 316 317 PRINT ("Ok\n"); FL; 318 DONE (dig_opt:CheckOptions); 319 return TCL_OK; 320} 321 322/* 323 *------------------------------------------------------* 324 * 325 * SetOption -- 326 * 327 * ------------------------------------------------* 328 * Define value of given option. 329 * ------------------------------------------------* 330 * 331 * Sideeffects: 332 * Sets the given value into the option 333 * structure 334 * 335 * Result: 336 * A standard Tcl error code. 337 * 338 *------------------------------------------------------* 339 */ 340 341static int 342SetOption (options, interp, optname, optvalue, clientData) 343Trf_Options options; 344Tcl_Interp* interp; 345CONST char* optname; 346CONST Tcl_Obj* optvalue; 347ClientData clientData; 348{ 349 /* Possible options: 350 * 351 * -mode absorb|write|transparent 352 * -matchflag <varname> 353 * -write-destination <channel> | <variable> 354 * -read-destination <channel> | <variable> 355 */ 356 357 TrfMDOptionBlock* o = (TrfMDOptionBlock*) options; 358 CONST char* value; 359 360 int len = strlen (optname); 361 362 value = Tcl_GetStringFromObj ((Tcl_Obj*) optvalue, NULL); 363 364 switch (optname [1]) { 365 case 'm': 366 if (len < 3) 367 goto unknown_option; 368 369 if (0 == strncmp (optname, "-mode", len)) { 370 return DigestMode (interp, value, &o->mode); 371 372 } else if (0 == strncmp (optname, "-matchflag", len)) { 373 if (o->matchFlag) { 374 ckfree (o->matchFlag); 375 } 376 377 o->vInterp = interp; 378 o->matchFlag = strcpy (ckalloc (1 + strlen (value)), value); 379 380 } else 381 goto unknown_option; 382 break; 383 384 case 'w': 385 if (len < 8) 386 goto unknown_option; 387 388 if (0 == strncmp (optname, "-write-destination", len)) { 389 if (o->writeDestination) { 390 ckfree (o->writeDestination); 391 } 392 393 o->vInterp = interp; 394 o->writeDestination = strcpy (ckalloc (1+strlen (value)), value); 395 396 } else if (0 == strncmp (optname, "-write-type", len)) { 397 return TargetType (interp, value, &o->wdIsChannel); 398 } else 399 goto unknown_option; 400 break; 401 402 case 'r': 403 if (len < 7) 404 goto unknown_option; 405 406 if (0 == strncmp (optname, "-read-destination", len)) { 407 if (o->readDestination) { 408 ckfree (o->readDestination); 409 } 410 411 o->vInterp = interp; 412 o->readDestination = strcpy (ckalloc (1+strlen (value)), value); 413 414 } else if (0 == strncmp (optname, "-read-type", len)) { 415 return TargetType (interp, value, &o->rdIsChannel); 416 } else 417 goto unknown_option; 418 break; 419 420 default: 421 goto unknown_option; 422 break; 423 } 424 425 return TCL_OK; 426 427 unknown_option: 428 Tcl_AppendResult (interp, "unknown option '", optname, "', should be '-mode', '-matchflag', '-write-destination', '-write-type', '-read-destination' or '-read-type'", (char*) NULL); 429 430 return TCL_ERROR; 431} 432 433/* 434 *------------------------------------------------------* 435 * 436 * QueryOptions -- 437 * 438 * ------------------------------------------------* 439 * Returns a value indicating wether the encoder or 440 * decoder set of vectors is to be used by immediate 441 * execution. 442 * ------------------------------------------------* 443 * 444 * Sideeffects: 445 * None 446 * 447 * Result: 448 * 1 - use encoder vectors. 449 * 0 - use decoder vectors. 450 * 451 *------------------------------------------------------* 452 */ 453 454static int 455QueryOptions (options, clientData) 456Trf_Options options; 457ClientData clientData; 458{ 459 /* Always use encoder for immediate execution */ 460 return 1; 461} 462 463/* 464 *------------------------------------------------------* 465 * 466 * TargetType -- 467 * 468 * ------------------------------------------------* 469 * Determines from a string what destination was 470 * given to the message digest. 471 * ------------------------------------------------* 472 * 473 * Sideeffects: 474 * May leave an error message in the 475 * interpreter result area. 476 * 477 * Result: 478 * A standard Tcl error code, in case of 479 * success 'isChannel' is set too. 480 * 481 *------------------------------------------------------* 482 */ 483 484static int 485TargetType (interp, typeString, isChannel) 486Tcl_Interp* interp; 487CONST char* typeString; 488int* isChannel; 489{ 490 int len = strlen (typeString); 491 492 switch (typeString [0]) { 493 case 'v': 494 if (0 == strncmp ("variable", typeString, len)) { 495 *isChannel = 0; 496 } else 497 goto unknown_type; 498 break; 499 500 case 'c': 501 if (0 == strncmp ("channel", typeString, len)) { 502 *isChannel = 1; 503 } else 504 goto unknown_type; 505 break; 506 507 default: 508 unknown_type: 509 Tcl_AppendResult (interp, "unknown target-type '", 510 typeString, "'", (char*) NULL); 511 return TCL_ERROR; 512 } 513 514 return TCL_OK; 515} 516 517/* 518 *------------------------------------------------------* 519 * 520 * DigestMode -- 521 * 522 * ------------------------------------------------* 523 * Determines the operation mode of the digest. 524 * ------------------------------------------------* 525 * 526 * Sideeffects: 527 * May leave an error message in the 528 * interpreter result area. 529 * 530 * Result: 531 * A standard Tcl error code, in case of 532 * success 'mode' is set too. 533 * 534 *------------------------------------------------------* 535 */ 536 537static int 538DigestMode (interp, modeString, mode) 539Tcl_Interp* interp; 540CONST char* modeString; 541int* mode; 542{ 543 int len = strlen (modeString); 544 545 switch (modeString [0]) { 546 case 'a': 547 if (0 == strncmp (modeString, "absorb", len)) { 548 *mode = TRF_ABSORB_HASH; 549 } else 550 goto unknown_mode; 551 break; 552 553 case 'w': 554 if (0 == strncmp (modeString, "write", len)) { 555 *mode = TRF_WRITE_HASH; 556 } else 557 goto unknown_mode; 558 break; 559 560 case 't': 561 if (0 == strncmp (modeString, "transparent", len)) { 562 *mode = TRF_TRANSPARENT; 563 } else 564 goto unknown_mode; 565 break; 566 567 default: 568 unknown_mode: 569 Tcl_AppendResult (interp, "unknown mode '", modeString, "', should be 'absorb', 'write' or 'transparent'", (char*) NULL); 570 return TCL_ERROR; 571 } 572 573 return TCL_OK; 574} 575