1/*
2 * convert.c --
3 *
4 *	Implements the C level procedures handling option processing
5 *	of transformation reflecting the work to the tcl level.
6 *
7 *
8 * Copyright (c) 1997 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: ref_opt.c,v 1.9 2009/05/07 04:57:27 andreas_kupries Exp $
29 */
30
31#include "reflect.h"
32
33/*
34 * forward declarations of all internally used procedures.
35 */
36
37static Trf_Options
38CreateOptions _ANSI_ARGS_ ((ClientData clientData));
39
40static void
41DeleteOptions _ANSI_ARGS_ ((Trf_Options options,
42			    ClientData  clientData));
43static int
44CheckOptions  _ANSI_ARGS_ ((Trf_Options            options,
45			    Tcl_Interp*            interp,
46			    CONST Trf_BaseOptions* baseOptions,
47			    ClientData             clientData));
48
49static int
50SetOption     _ANSI_ARGS_ ((Trf_Options    options,
51			    Tcl_Interp*    interp,
52			    CONST char*    optname,
53			    CONST Tcl_Obj* optvalue,
54			    ClientData     clientData));
55
56static int
57QueryOptions  _ANSI_ARGS_ ((Trf_Options options,
58			    ClientData  clientData));
59
60static void
61SeekQueryOptions  _ANSI_ARGS_ ((Tcl_Interp*          interp,
62				Trf_Options          options,
63				Trf_SeekInformation* seekInfo,
64				ClientData           clientData));
65
66/*
67 *------------------------------------------------------*
68 *
69 *	TrfTransformOptions --
70 *
71 *	------------------------------------------------*
72 *	Accessor to the set of vectors realizing option
73 *	processing for reflecting transformation.
74 *	------------------------------------------------*
75 *
76 *	Sideeffects:
77 *		None.
78 *
79 *	Result:
80 *		See above.
81 *
82 *------------------------------------------------------*
83 */
84
85Trf_OptionVectors*
86TrfTransformOptions ()
87{
88  static Trf_OptionVectors optVec = /* THREADING: const, read-only => safe */
89    {
90      CreateOptions,
91      DeleteOptions,
92      CheckOptions,
93      NULL,      /* no string procedure for 'SetOption' */
94      SetOption,
95      QueryOptions,
96      SeekQueryOptions /* Tcl level can change/define the ratio */
97    };
98
99  return &optVec;
100}
101
102/*
103 *------------------------------------------------------*
104 *
105 *	CreateOptions --
106 *
107 *	------------------------------------------------*
108 *	Create option structure for reflecting transformation.
109 *	------------------------------------------------*
110 *
111 *	Sideeffects:
112 *		Allocates memory and initializes it as
113 *		option structure for reflecting
114 *		transformations.
115 *
116 *	Result:
117 *		A reference to the allocated block of
118 *		memory.
119 *
120 *------------------------------------------------------*
121 */
122
123static Trf_Options
124CreateOptions (clientData)
125ClientData clientData;
126{
127  TrfTransformOptionBlock* o;
128
129  o = (TrfTransformOptionBlock*) ckalloc (sizeof (TrfTransformOptionBlock));
130  o->mode    = TRF_UNKNOWN_MODE;
131  o->command = (Tcl_Obj*) NULL;
132
133  return (Trf_Options) o;
134}
135
136/*
137 *------------------------------------------------------*
138 *
139 *	DeleteOptions --
140 *
141 *	------------------------------------------------*
142 *	Delete option structure of a reflecting transformation
143 *	------------------------------------------------*
144 *
145 *	Sideeffects:
146 *		A memory block allocated by 'CreateOptions'
147 *		is released.
148 *
149 *	Result:
150 *		None.
151 *
152 *------------------------------------------------------*
153 */
154
155static void
156DeleteOptions (options, clientData)
157Trf_Options options;
158ClientData  clientData;
159{
160  TrfTransformOptionBlock* o = (TrfTransformOptionBlock*) options;
161
162  if (o->command != NULL) {
163    Tcl_DecrRefCount (o->command);
164  }
165
166  ckfree ((VOID*) o);
167}
168
169/*
170 *------------------------------------------------------*
171 *
172 *	CheckOptions --
173 *
174 *	------------------------------------------------*
175 *	Check the given option structure for errors.
176 *	------------------------------------------------*
177 *
178 *	Sideeffects:
179 *		May modify the given structure to set
180 *		default values into uninitialized parts.
181 *
182 *	Result:
183 *		A standard Tcl error code.
184 *
185 *------------------------------------------------------*
186 */
187
188static int
189CheckOptions (options, interp, baseOptions, clientData)
190Trf_Options            options;
191Tcl_Interp*            interp;
192CONST Trf_BaseOptions* baseOptions;
193ClientData             clientData;
194{
195  TrfTransformOptionBlock* o = (TrfTransformOptionBlock*) options;
196
197  if (o->command == NULL) {
198    Tcl_AppendResult (interp, "command not specified", (char*) NULL);
199    return TCL_ERROR;
200  }
201
202  if ((o->command->bytes == 0) && (o->command->typePtr == NULL)) {
203    /* object defined, but empty, reject this too */
204    Tcl_AppendResult (interp, "command specified, but empty", (char*) NULL);
205    return TCL_ERROR;
206  }
207
208  if (baseOptions->attach == (Tcl_Channel) NULL) /* IMMEDIATE? */ {
209    if (o->mode == TRF_UNKNOWN_MODE) {
210      Tcl_AppendResult (interp, "-mode option not set", (char*) NULL);
211      return TCL_ERROR;
212    }
213  } else /* ATTACH */ {
214    if (o->mode != TRF_UNKNOWN_MODE) {
215      /* operation mode irrelevant for attached transformation,
216       * and specification therefore ruled as illegal.
217       */
218      Tcl_AppendResult (interp, "mode illegal for attached transformation",
219			(char*) NULL);
220      return TCL_ERROR;
221    }
222    o->mode = TRF_WRITE_MODE;
223  }
224
225  return TCL_OK;
226}
227
228/*
229 *------------------------------------------------------*
230 *
231 *	SetOption --
232 *
233 *	------------------------------------------------*
234 *	Define value of given option.
235 *	------------------------------------------------*
236 *
237 *	Sideeffects:
238 *		Sets the given value into the option
239 *		structure
240 *
241 *	Result:
242 *		A standard Tcl error code.
243 *
244 *------------------------------------------------------*
245 */
246
247static int
248SetOption (options, interp, optname, optvalue, clientData)
249Trf_Options    options;
250Tcl_Interp*    interp;
251CONST char*    optname;
252CONST Tcl_Obj* optvalue;
253ClientData     clientData;
254{
255  TrfTransformOptionBlock* o = (TrfTransformOptionBlock*) options;
256  int                     len;
257  CONST char*             value;
258
259  len = strlen (optname+1);
260
261  switch (optname [1]) {
262  case 'm':
263    if (0 != strncmp (optname, "-mode", len))
264      goto unknown_option;
265
266    value = Tcl_GetStringFromObj ((Tcl_Obj*) optvalue, NULL);
267    len = strlen (value);
268
269    switch (value [0]) {
270    case 'r':
271      if (0 != strncmp (value, "read", len))
272	goto unknown_mode;
273
274      o->mode = TRF_READ_MODE;
275      break;
276
277    case 'w':
278      if (0 != strncmp (value, "write", len))
279	goto unknown_mode;
280
281      o->mode = TRF_WRITE_MODE;
282      break;
283
284    default:
285    unknown_mode:
286      Tcl_AppendResult (interp, "unknown mode '", (char*) NULL);
287      Tcl_AppendResult (interp, value, (char*) NULL);
288      Tcl_AppendResult (interp, "', should be 'read' or 'write'", (char*) NULL);
289      return TCL_ERROR;
290      break;
291    } /* switch optvalue */
292    break;
293
294  case 'c':
295    if (0 != strncmp (optname, "-command", len))
296      goto unknown_option;
297
298    /* 'optvalue' contains the command to execute for a buffer */
299
300    /*
301     * Store reference, tell the interpreter about it.
302     * We have to unCONST it explicitly to allow modification
303     * of its reference counter
304     */
305    o->command = (Tcl_Obj*) optvalue;
306    Tcl_IncrRefCount (o->command);
307    break;
308
309  default:
310    goto unknown_option;
311    break;
312  }
313
314  return TCL_OK;
315
316 unknown_option:
317  Tcl_AppendResult (interp, "unknown option '", (char*) NULL);
318  Tcl_AppendResult (interp, optname, (char*) NULL);
319  Tcl_AppendResult (interp, "', should be '-mode' or '-command'", (char*) NULL);
320  return TCL_ERROR;
321}
322
323/*
324 *------------------------------------------------------*
325 *
326 *	QueryOptions --
327 *
328 *	------------------------------------------------*
329 *	Returns a value indicating wether the encoder or
330 *	decoder set of vectors is to be used by immediate
331 *	execution.
332 *	------------------------------------------------*
333 *
334 *	Sideeffects:
335 *		None
336 *
337 *	Result:
338 *		1 - use encoder vectors.
339 *		0 - use decoder vectors.
340 *
341 *------------------------------------------------------*
342 */
343
344static int
345QueryOptions (options, clientData)
346Trf_Options options;
347ClientData clientData;
348{
349  TrfTransformOptionBlock* o = (TrfTransformOptionBlock*) options;
350
351  return (o->mode == TRF_WRITE_MODE ? 1 : 0);
352}
353
354/*
355 *------------------------------------------------------*
356 *
357 *	SeekQueryOptions --
358 *
359 *	------------------------------------------------*
360 *	Modifies the natural seek policy according to the
361 *	configuration of the transformation (queries the
362 *	tcl level).
363 *	------------------------------------------------*
364 *
365 *	Sideeffects:
366 *		May modify 'seekInfo'.
367 *
368 *	Result:
369 *		None.
370 *
371 *------------------------------------------------------*
372 */
373
374static void
375SeekQueryOptions (interp, options, seekInfo, clientData)
376     Tcl_Interp*          interp;
377     Trf_Options          options;
378     Trf_SeekInformation* seekInfo;
379     ClientData           clientData;
380{
381  TrfTransformOptionBlock* o = (TrfTransformOptionBlock*) options;
382  ReflectControl           rc;
383
384  START (SeekQueryOptions);
385
386  rc.interp                         = interp;
387  rc.naturalRatio.numBytesTransform = seekInfo->numBytesTransform;
388  rc.naturalRatio.numBytesDown      = seekInfo->numBytesDown;
389  rc.command                        = o->command;
390  Tcl_IncrRefCount (rc.command);
391
392
393  PRINT ("in  = (%d, %d)\n",
394	 seekInfo->numBytesTransform, seekInfo->numBytesDown); FL;
395
396  RefExecuteCallback (&rc, (Tcl_Interp*) interp,
397		      (unsigned char*) "query/ratio",
398		      NULL, 0, TRANSMIT_RATIO /* -> naturalRatio */, 1);
399
400  seekInfo->numBytesTransform = rc.naturalRatio.numBytesTransform;
401  seekInfo->numBytesDown      = rc.naturalRatio.numBytesDown;
402
403  Tcl_DecrRefCount (rc.command);
404
405
406  PRINT ("out = (%d, %d)\n",
407	 seekInfo->numBytesTransform, seekInfo->numBytesDown); FL;
408
409  DONE (SeekQueryOptions);
410}
411