Initial revision
[TestXSLT.git] / libsablot / src / engine / sablot.cpp
1 /* 
2  * The contents of this file are subject to the Mozilla Public
3  * License Version 1.1 (the "License"); you may not use this file
4  * except in compliance with the License. You may obtain a copy of
5  * the License at http://www.mozilla.org/MPL/
6  * 
7  * Software distributed under the License is distributed on an "AS
8  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
9  * implied. See the License for the specific language governing
10  * rights and limitations under the License.
11  * 
12  * The Original Code is the Sablotron XSLT Processor.
13  * 
14  * The Initial Developer of the Original Code is Ginger Alliance Ltd.
15  * Portions created by Ginger Alliance are Copyright (C) 2000-2002
16  * Ginger Alliance Ltd. All Rights Reserved.
17  * 
18  * Contributor(s):
19  * 
20  * Alternatively, the contents of this file may be used under the
21  * terms of the GNU General Public License Version 2 or later (the
22  * "GPL"), in which case the provisions of the GPL are applicable 
23  * instead of those above.  If you wish to allow use of your 
24  * version of this file only under the terms of the GPL and not to
25  * allow others to use your version of this file under the MPL,
26  * indicate your decision by deleting the provisions above and
27  * replace them with the notice and other provisions required by
28  * the GPL.  If you do not delete the provisions above, a recipient
29  * may use your version of this file under either the MPL or the
30  * GPL.
31  */
32
33 /****************************************
34 *                                       *
35 i n c l u d e s
36 *                                       *
37 ****************************************/
38
39 // #include<iostream.h>
40
41 // GP: clean
42
43 #include <stdarg.h>
44
45 #define SablotAsExport
46 #include "sablot.h"
47
48 #include "base.h"
49 #include "verts.h"
50 #include "tree.h"
51 #include "expr.h"
52 #include "proc.h"
53 #include "situa.h"
54 #include "uri.h"
55 #include "parser.h"
56 #include "guard.h"
57 #include "sxpath.h"
58 #include "domprovider.h"
59
60 //
61 //  defines
62 //
63
64 #define P( PTR ) ((Processor *)(PTR))
65 #define EE(statement) {int code___=(statement); if (code___) return code___;}
66 #define ES(statement) {if (statement) return SIT(S).getError();}
67 // same as EE() but destroys the given processor
68 #define EE_D(CODE,PROC) {int code___=(CODE); if (code___) {SablotDestroyProcessor(PROC); return code___;}}
69 // error-checking chain
70 #define EC( VAR, STMT ) {if (!VAR) VAR = STMT;}
71 #define SIT( S ) (*(Situation*)S)
72
73
74 /****************************************
75 g l o b a l s
76 ****************************************/
77 #define checkErr(situation) {if (situation->isError()) \
78     {Warn(situation, W_PENDING_ERROR); return NOT_OK;}}
79
80
81 /****************************************
82 d e f i n i t i o n s
83 ****************************************/
84
85 void doStart(Sit S)
86 {
87     S.message(MT_LOG, L_START, S.timeStr(), (char*) NULL);
88 //    Log1(S, L_START, S.timeStr());
89 };
90
91 void doEnd(Sit S)
92 {
93     S.message(MT_LOG, L_STOP, S.timeStr(), (char*) NULL);
94 //    Log1(S, L_STOP, S.timeStr());
95 }
96
97 #define ErrQ(S, e) {\
98     S.message(MT_ERROR, e,(char*) NULL, (char*)NULL); \
99     doEnd(S); \
100     return e; \
101         }
102
103 // report function to enable the Sablot... globals to use Err and Log           
104 void report(Sit S, MsgType type, MsgCode code, const Str& arg1, const Str& arg2) 
105 {
106     S.message(type, code, arg1, arg2);
107 }
108
109
110 //
111 //
112 //      situation functions
113 //
114 //
115
116 int SablotCreateSituation(SablotSituation *sPtr)
117 {
118     *sPtr = new Situation;
119     if (!*sPtr)
120         return E_MEMORY;
121     return OK;
122 }
123
124 int SablotDestroySituation(SablotSituation S)
125 {
126     if (S) delete (Situation*)S;
127     S = NULL;
128     return OK;
129 }
130
131 int SablotSetOptions(SablotSituation S, int flags)
132 {
133     ((Situation*)S) -> setFlags(flags);
134     return OK;
135 }
136
137 int SablotGetOptions(SablotSituation S)
138 {
139   return ((Situation*)S) -> getFlags();
140 }
141
142 int SablotClearSituation(SablotSituation S)
143 {
144     ((Situation*)S) -> clear();
145     return OK;
146 }
147
148 //
149 //    document functions
150 //
151
152 int SablotCreateDocument(SablotSituation S, SDOM_Document *D)
153 {
154     // non-XSL tree with empty name
155     Tree *t = new Tree((char*)"", FALSE);
156     SabArena &ar = t -> getArena();
157     NmSpace *nm = new (&ar) NmSpace(*t, t -> unexpand("xml"), 
158                                     t -> unexpand(theXMLNamespace),
159                                     TRUE, NSKIND_DECLARED);
160     RootNode &root = t -> getRoot();
161     root.namespaces.append(nm);
162     *D = &root;
163     return OK;
164 }
165
166 int SablotParse_(
167     SablotSituation S, 
168     const char *uri, 
169     const char *buffer,
170     SDOM_Document *D,
171     Bool asStylesheet)
172 {
173     Str absolute;
174     StrStrList argList;
175     DStr base;
176     *D = NULL;
177     double time_was = getMillisecs();
178     int code = 0;
179
180     SIT(S).clear();
181     // make absolute address
182     char *parserBase = NULL;
183     if (!buffer)
184     {
185         my_getcwd(base);
186         base = Str("file://") + base;
187         // should call Processor::findBaseURI() here (but have no Processor)
188         makeAbsoluteURI(SIT(S), uri, base, absolute);
189         parserBase = (char*)absolute;
190     }
191     else
192       absolute = "arg:/_parsed_";
193     
194     // create the tree and dataline
195     DataLine line;
196     GP( Tree ) newTree = new Tree(absolute, /* isXSL = */ asStylesheet);
197     TreeConstructer tc(SIT(S));
198     
199     // add buffer if there is one
200     if (buffer)
201         argList.appendConstruct("/_parsed_", buffer);
202                     
203     // open the line
204     EC( code, line.open(SIT(S), absolute, DLMODE_READ, &argList) );
205     
206     Log1(SIT(S), L1_PARSING, absolute);
207     EC( code, tc.parseDataLineUsingExpat(SIT(S), newTree, &line, parserBase) );        
208     EC( code, line.close(SIT(S)) );
209     *D = &(newTree.keep() -> getRoot());    
210     Log1(SIT(S), L1_PARSE_DONE, getMillisecsDiff(time_was));
211
212     argList.freeall(FALSE);
213     return SIT(S).getError();
214 }
215
216
217 int SablotParse(
218     SablotSituation S, 
219     const char *uri, 
220     SDOM_Document *D)
221 {
222     return SablotParse_(S, uri, NULL, D, FALSE);
223 }
224
225 int SablotParseBuffer(
226     SablotSituation S, 
227     const char *buffer, 
228     SDOM_Document *D)
229 {
230     return SablotParse_(S, NULL, buffer, D, FALSE);
231 }
232
233 int SablotParseStylesheet(
234     SablotSituation S, 
235     const char *uri, 
236     SDOM_Document *D)
237 {
238     return SablotParse_(S, uri, NULL, D, TRUE);
239 }
240
241 int SablotParseStylesheetBuffer(
242     SablotSituation S, 
243     const char *buffer, 
244     SDOM_Document *D)
245 {
246     return SablotParse_(S, NULL, buffer, D, TRUE);
247 }
248
249 int SablotLockDocument(SablotSituation S, SDOM_Document D)
250 {
251     ((RootNode*)D) -> getOwner().makeStamps();
252     return OK;
253 }
254
255 int SablotDestroyDocument(SablotSituation S, SDOM_Document D)
256 {
257     delete &((toRoot(toV(D))) -> getOwner());
258     return OK;
259 }
260
261
262 //
263 //
264 //      SablotCreateProcessor
265 //
266 //
267
268 int SablotCreateProcessor(void **processorPtr)
269 {
270     // to debug memory leaks in MSVC, uncomment the call to checkLeak()
271     // and set _crtBreakAlloc to the # of block (proc=51)
272
273     // create a new situation for this processor
274     void *newSit = NULL;
275     SablotCreateSituation(&newSit);
276
277 #if defined(HAVE_MTRACE) && defined(CHECK_LEAKS)
278     mtrace();
279 #endif
280     *processorPtr = new Processor;
281     if (!*processorPtr)
282     {
283         ((Situation*)newSit) -> message(MT_ERROR, E_MEMORY, (char*) NULL, (char*) NULL);
284         return E_MEMORY;
285         // Err( *newSit, E_MEMORY );
286     }
287     // the processor must remember its situation (this is just to
288     // avoid compatibility breakdown)
289     P( *processorPtr ) -> rememberSituation((Situation*)newSit);
290     SIT( newSit).setProcessor( P(*processorPtr) );
291
292     // the following seems superfluous - the processor is new
293     // checkErr( P(*processorPtr)->situation );
294     doStart ( SIT( newSit ) );
295     return OK;
296 }
297
298 int SablotCreateProcessorForSituation(SablotSituation S, void **processorPtr)
299 {
300 #if defined(HAVE_MTRACE) && defined(CHECK_LEAKS)
301     mtrace();
302 #endif
303     *processorPtr = new Processor;
304     if (!*processorPtr)
305     {
306         SIT(S).message(MT_ERROR, E_MEMORY, (char*) NULL, (char*) NULL);
307         return E_MEMORY;
308     }
309     P( *processorPtr ) -> rememberMasterSituation((Situation*)S);
310     SIT(S).setProcessor( P(*processorPtr) ); // this will go asap
311     doStart ( SIT(S) );
312     return OK;
313 }
314
315 int SablotAddParam(
316     SablotSituation S,
317     void *processor_,
318     const char *paramName,
319     const char *paramValue)
320 {
321     SIT(S).clear();
322     ES( P(processor_) -> addGlobalParam(SIT(S), 
323         (char*)paramName, (char*)paramValue) );
324     return OK;
325 }
326
327 int SablotAddArgBuffer(
328     SablotSituation S,
329     void *processor_,
330     const char *argName,
331     const char *bufferValue)
332 {
333     SIT(S).clear();
334     if (!(P(processor_) -> getAddedFlag()))
335         SablotFreeResultArgs (processor_);
336     ES( P(processor_) -> useArg(SIT(S), (char*)argName, (char*)bufferValue) );
337     return OK;
338 }
339
340 int SablotAddArgTree(
341     SablotSituation S,
342     void *processor_,
343     const char *argName,
344     SDOM_Document tree)
345 {
346     SIT(S).clear();
347     if (!(P(processor_) -> getAddedFlag()))
348         SablotFreeResultArgs (processor_);
349     ES( P(processor_) -> useTree(SIT(S), (char*) argName, 
350                                  &(toRoot(tree) -> getOwner())) );
351     return OK;
352 }
353
354 int SablotRunProcessorGen(
355     SablotSituation S,
356     void *processor_,
357     const char *sheetURI, 
358     const char *inputURI, 
359     const char *resultURI)
360 {
361     int code = 0;
362
363     void *saveproc = processor_;
364     SIT(S).swapProcessor(saveproc);
365
366     SIT(S).clear();
367     // remove the existing 'arg' buffers
368     if (!(P(processor_) -> getAddedFlag()))
369         EC( code, SablotFreeResultArgs (processor_) );
370     if (!code)
371         P(processor_) -> prepareForRun();
372     // must first open the files, then use global params
373     // because VarsList needs stylesheet's dictionary
374     EC( code, P(processor_) -> open(SIT(S), sheetURI,inputURI) );
375     EC( code, P(processor_) -> useGlobalParams(SIT(S)) );
376     EC( code, P(processor_) -> run(SIT(S), resultURI) );
377     code = SIT(S).getError();
378     P(processor_) -> cleanupAfterRun((Situation*)S);
379     if (code)
380     {
381         // GP: if not all files could be opened, those that could are
382         // closed in cleanupAfterRun
383         // code = SIT(S).getError();
384         P(processor_) -> freeResultArgs(SIT(S));
385     };
386     
387     SIT(S).swapProcessor(saveproc);
388     return code;
389 }
390
391 int SablotRunProcessorExt(
392     SablotSituation S,
393     void *processor_,
394     const char *sheetURI, 
395     const char *resultURI, 
396     NodeHandle doc)
397 {
398     int code = 0;
399     //mask external node
400     doc = SXP_MASK_LEVEL(doc, SIT(S).getSXPMaskBit());
401
402     void *saveproc = processor_;
403     SIT(S).swapProcessor(saveproc);
404
405     SIT(S).clear();
406     // remove the existing 'arg' buffers
407     if (!(P(processor_) -> getAddedFlag()))
408         EC( code, SablotFreeResultArgs (processor_) );
409     if (!code)
410         P(processor_) -> prepareForRun();
411     // must first open the files, then use global params
412     // because VarsList needs stylesheet's dictionary
413     EC( code, P(processor_) -> open(SIT(S), sheetURI, NULL) );
414     EC( code, P(processor_) -> useGlobalParams(SIT(S)) );
415     EC( code, P(processor_) -> run(SIT(S), resultURI, doc) );
416     code = SIT(S).getError();
417     P(processor_) -> cleanupAfterRun((Situation*)S);
418     if (code)
419     {
420         // GP: if not all files could be opened, those that could are
421         // closed in cleanupAfterRun
422         // code = SIT(S).getError();
423         P(processor_) -> freeResultArgs(SIT(S));
424     };
425     
426     SIT(S).swapProcessor(saveproc);
427     return code;
428 }
429
430
431 //
432 //
433 //      SablotRunProcessor
434 //
435 //
436 int SablotRunProcessor(void *processor_,
437                        const char *sheetURI, 
438                        const char *inputURI, 
439                        const char *resultURI,
440                        const char **params, 
441                        const char **arguments)
442 {    
443     Bool problem = FALSE;
444     Sit S = *(NZ(P( processor_ )) -> recallSituation());
445
446     {
447         // remove the existing 'arg' buffers
448             S.clearError();
449         E( SablotFreeResultArgs (processor_));
450         P(processor_) -> prepareForRun();
451         const char **p;
452         if (arguments)
453         {
454             for (p = arguments; *p && !problem; p += 2)
455                 problem = P(processor_) -> useArg(S, p[0], p[1]);
456         }
457             if (!problem)
458             {
459                 // must first open the files, then use global params
460                     // because VarsList needs stylesheet's dictionary
461                 problem = P(processor_) -> open(S, sheetURI,inputURI);
462             if (params)
463             {
464                 for (p = params; *p && !problem; p += 2)
465                     problem = P(processor_) -> useGlobalParam(S, p[0], p[1]);
466             }
467             }
468         if (problem || P(processor_) -> run(S, resultURI))
469         {
470             // GP: if not all files could be opened, those that could are
471             // closed in cleanupAfterRun
472             int code = S.getError();
473             P(processor_) -> cleanupAfterRun(&S);
474             P(processor_) -> freeResultArgs(S);
475 //            cdelete(proc);
476             // S.clear(); (why forget the message?)
477             return code;
478         }
479     }
480     P(processor_) -> cleanupAfterRun(&S);
481     return OK;
482 }
483
484
485
486 //
487 //
488 //      SablotDestroyProcessor
489 //
490 //
491
492
493 int SablotDestroyProcessor(void *processor_)
494 {
495     int code;
496     Bool killSit = !(P( processor_ ) -> situationIsMaster());
497     Situation *SP = P(processor_) -> recallSituation();
498     code = SablotFreeResultArgs(processor_);
499     doEnd(*SP);
500     if(processor_) delete P( processor_);
501     processor_ = NULL;    
502     if (killSit)
503         cdelete(SP);
504 #if defined(WIN32) && defined(CHECK_LEAKS)
505     memStats();
506     checkLeak();
507 #endif
508     return code;
509 };
510
511
512
513 //
514 //
515 //      SablotSetBase
516 //
517 //
518
519 int SablotSetBase(void* processor_, 
520                   const char *theBase)
521 {
522     P(processor_) -> setHardBaseURI(theBase);
523     return OK;
524 }
525
526
527 //
528 //
529 //      SablotSetBaseForScheme
530 //
531 //
532
533 int SablotSetBaseForScheme(void* processor_, 
534                   const char *scheme, const char *base)
535 {
536     P(processor_) -> addBaseURIMapping(scheme, base);
537     return OK;
538 }
539
540
541
542
543 //
544 //
545 //      SablotGetResultArg
546 //
547 //
548
549 int SablotGetResultArg(void *processor_,
550                        const char *argURI,
551                        char **argValue)
552 {
553     char *newCopy; // GP: OK
554     // we even obtain the index of the output buffer but won't use it
555     int resultNdx_;
556     if (argValue)
557     {
558       Situation *s = P(processor_) -> recallSituation();
559       assert(s); //we always should have some situation, master or internal
560       P(processor_) -> copyArg(SIT(s), argURI, &resultNdx_, newCopy);
561       // if output does not go to a buffer, newCopy is NULL
562       *argValue = newCopy;
563     }
564     return OK;
565 }
566
567
568 //
569 //
570 //      SablotSetLog
571 //
572 //
573
574 int SablotSetLog(void *processor_,
575     const char *logFilename, int logLevel)
576 {
577     P(processor_) -> recallSituation()->msgOutputFile((char *)"stderr",(char*) logFilename);
578     // logLevel ignored so far
579     return OK;
580 }
581
582
583 /*****************************************************************
584 SablotProcess
585
586   the main function published by Sablotron. Feeds given XML
587   input to a stylesheet. Both of these as well as the location for
588   output are identified by a URI. One can also pass top-level
589   stylesheet parameters and named buffers ('args').
590 ARGS
591   sheetURI      URI of the XSLT stylesheet
592   inputURI      URI of the XML document
593   resultURI     URI of the output document
594   params        a NULL-terminated array of char*'s defining the top-level
595                 parameters to be passed, interpreted as a
596                 sequence of (name, value) pairs. 
597   arguments     a NULL-terminated array of char*'s defining the named
598                 buffers to be passed, interpreted as a
599                 sequence of (name, value) pairs. Both params and arguments
600                 may be NULL. 
601 RETURNS
602   .             nonzero iff error
603   resultArg     in case output goes to a named buffer, *resultArg is set to                     
604                 point to it (otherwise to NULL). Free it using SablotFree().
605 *****************************************************************/
606
607 int SablotProcess(const char *sheetURI, const char *inputURI, 
608                   const char *resultURI,
609                   const char **params, const char **arguments, 
610                   char **resultArg)
611 {
612     void *theproc;
613     EE( SablotCreateProcessor (&theproc) );
614     EE_D( SablotRunProcessor(theproc,
615         sheetURI, inputURI, resultURI,
616         params, arguments), theproc );
617     EE_D( SablotGetResultArg(theproc, resultURI, resultArg), theproc );
618     EE( SablotDestroyProcessor(theproc) );
619     return OK;
620 };
621
622
623 /*****************************************************************
624 SablotProcessFiles
625
626   calls SablotProcess to process files identified by their
627   file names. No named buffers or params are passed. Included
628   for backward compatibility.
629 ARGUMENTS
630   styleSheetName, inputName, resultName
631             file names of the stylesheet, XML input and output,
632             respectively.
633 RETURNS
634   .         error flag
635 *****************************************************************/
636
637
638 int SablotProcessFiles(const char *styleSheetName,
639                        const char *inputName,
640                        const char *resultName)
641 {
642     return SablotProcess(
643         styleSheetName, inputName, resultName, 
644         NULL, NULL, NULL);
645 };
646
647
648 /*****************************************************************
649 SablotProcessStrings
650
651   calls SablotProcess to process documents in memory, passing
652   pointers to the documents. No named buffers or params are passed.
653   Included for backward compatibility.
654 ARGUMENTS
655   styleSheetStr, inputStr
656                 text of the stylesheet and the XML input
657 RETURNS
658   .             error flag
659   *resultStr    pointer to the newly allocated block containing
660                 the result 
661 *****************************************************************/
662 int SablotProcessStrings(const char *styleSheetStr,
663                          const char *inputStr,
664                          char **resultStr)
665 {
666   const char *argums[] =
667   {
668     "/_stylesheet", styleSheetStr,
669     "/_xmlinput", inputStr,
670     "/_output", NULL, //was: *resultStr,
671     NULL
672   };
673   return SablotProcess("arg:/_stylesheet",
674                        "arg:/_xmlinput",
675                        "arg:/_output",
676                        NULL, argums, resultStr);
677 };
678
679
680 /*****************************************************************
681 SablotProcessStringsWithBase
682
683     Like SablotProcessStrings but lets you pass an URI that replaces
684     the stylesheet's URI in relative address resolution.
685
686 ARGUMENTS
687   styleSheetStr, inputStr
688                 text of the stylesheet and the XML input
689   theHardBase   the "hard base URI" replacing the stylesheet's URI
690                 in all relevant situations
691 RETURNS
692   .             error flag
693   *resultStr    pointer to the newly allocated block containing
694                 the result 
695 *****************************************************************/
696
697 int SablotProcessStringsWithBase(const char *styleSheetStr,
698                          const char *inputStr,
699                          char **resultStr,
700                          const char *theHardBase)
701 {
702     const char *argums[] =
703     {
704         "/_stylesheet", styleSheetStr,
705         "/_xmlinput", inputStr,
706         "/_output", NULL, //was: *resultStr,
707         NULL
708     };
709     void *theproc;
710     EE( SablotCreateProcessor(&theproc));
711     EE_D( SablotSetBase(theproc, theHardBase), theproc );
712     EE_D( SablotRunProcessor(theproc,
713         "arg:/_stylesheet",
714         "arg:/_xmlinput",
715         "arg:/_output",
716         NULL, argums), theproc);
717     EE_D( SablotGetResultArg(theproc,
718         "arg:/_output", resultStr), theproc);
719     EE( SablotDestroyProcessor(theproc));
720     return OK;
721 };
722
723
724 /*****************************************************************
725 SablotFree
726
727   Frees the Sablotron-allocated buffer.
728 *****************************************************************/
729
730 int SablotFree(char *resultStr)
731 {
732     if (resultStr)
733         delete[] resultStr;
734     return OK;
735 }
736
737
738 //
739 //
740 //      SablotFreeResultArgs
741 //      frees the result arg buffers after the have been obtained
742 //      via SablotGetResultArg()
743 //
744 //
745
746 int SablotFreeResultArgs(void *processor_)
747 {
748     EE( P(processor_) -> freeResultArgs(*(P(processor_) -> recallSituation())) );
749     return OK;
750 }
751
752
753 //
754 //
755 //      SablotRegHandler
756 //
757 //
758
759 int SablotRegHandler(void *processor_, 
760                      /* HLR_MESSAGE, HLR_SCHEME, HLR_SAX, HLR_MISC */
761                      HandlerType type,   
762                      void *handler, 
763                      void *userData)
764 {
765     Sit S = *(P(processor_) -> recallSituation());
766     EE( P(processor_) -> setHandler(S, type, handler, userData) );
767     if (type == HLR_MESSAGE)
768         EE( S.closeFiles() );
769     return OK;
770 }
771
772
773
774 //
775 //
776 //      SablotUnregHandler
777 //
778 //
779
780 int SablotUnregHandler(void *processor_, 
781                        HandlerType type,   /* HLR_MESSAGE, HLR_SCHEME, HLR_SAX */
782                        void *handler,
783                        void *userData)
784 {
785     Sit S = *(P(processor_) -> recallSituation());
786     EE( P(processor_) -> setHandler(S, type, NULL, NULL) );
787     if (type == HLR_MESSAGE)
788         EE( S.openDefaultFiles() );
789     return OK;
790 }
791
792
793 //
794 //
795 //      SablotGetMsgText
796 //
797 //
798
799 const char* SablotGetMsgText(int code)
800 {
801     return GetMessage((MsgCode) code) -> text;
802 }
803
804 //
805 //
806 //      SablotClearError
807 //
808 //
809
810 int SablotClearError(void *processor_)
811 {
812     P(processor_) -> recallSituation() -> clear();
813     return OK;
814 }
815
816 //
817 //
818 //      SablotSetInstanceData
819 //
820 //
821
822 void SablotSetInstanceData(void *processor_, void *idata)
823 {
824     P(processor_) -> setInstanceData(idata);
825 }
826
827 //
828 //
829 //      SablotGetInstanceData
830 //
831 //
832
833 void* SablotGetInstanceData(void *processor_)
834 {
835     return P(processor_) -> getInstanceData();
836 }
837
838 //
839 //
840 //      SablotSetEncoding
841 //      sets the output encoding to be used regardless of the encoding
842 //      specified by the stylesheet
843 //      To unset, call with encoding_ NULL.
844 //
845 //
846
847 void SablotSetEncoding(void *processor_, char *encoding_)
848 {
849     P(processor_) -> setHardEncoding(
850         encoding_ ? encoding_ : (const char*) "");
851 }