1 /****************************************************************************
2  *               processrenderoptions.cpp
3  *
4  * This module contains the C++ interface for render option processing.
5  *
6  * from Persistence of Vision(tm) Ray Tracer version 3.6.
7  * Copyright 1991-2003 Persistence of Vision Team
8  * Copyright 2003-2004 Persistence of Vision Raytracer Pty. Ltd.
9  *---------------------------------------------------------------------------
10  * NOTICE: This source code file is provided so that users may experiment
11  * with enhancements to POV-Ray and to port the software to platforms other
12  * than those supported by the POV-Ray developers. There are strict rules
13  * regarding how you are permitted to use this file. These rules are contained
14  * in the distribution and derivative versions licenses which should have been
15  * provided with this file.
16  *
17  * These licences may be found online, linked from the end-user license
18  * agreement that is located at http://www.povray.org/povlegal.html
19  *---------------------------------------------------------------------------
20  * This program is based on the popular DKB raytracer version 2.12.
21  * DKBTrace was originally written by David K. Buck.
22  * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
23  *---------------------------------------------------------------------------
24  *
25  *===========================================================================
26  * This file is part of MegaPOV, a modified and unofficial version of POV-Ray
27  * For more information on MegaPOV visit our website:
28  * http://megapov.inetart.net/
29  *===========================================================================
30  *
31  * $RCSfile: processrenderoptions.cpp,v $
32  * $Revision: 1.11 $
33  * $Author: chris $
34  *
35  *****************************************************************************/
36 
37 #include "configfrontend.h"
38 
39 #include "processrenderoptions.h"
40 #include "fileinputoutput.h"
41 #include "stringutilities.h"
42 #include "textstream.h"
43 #include "povms.h"
44 #include "povmsgid.h"
45 #include "pov_err.h"
46 
47 BEGIN_POV_FRONTEND_NAMESPACE
48 
49 USING_POV_BASE_NAMESPACE
50 
51 /*****************************************************************************
52 * Local preprocessor defines
53 ******************************************************************************/
54 
55 #define kUseSpecialHandler	 kPOVMSType_WildCard
56 #define kNoParameter		 kPOVMSType_Null
57 
58 /*****************************************************************************
59 * Local variables
60 ******************************************************************************/
61 
62 /* Supported output file types */
63 #ifdef HDR_PATCH /* Christoph Hormann March 2003 */
64 const char *Output_File_Types = "sStTcCpPnNdDrRhH";
65 #else
66 const char *Output_File_Types = "sStTcCpPnNdDrR";
67 #endif
68 
69 /*
70    Keyword table for the INI-file parser.
71    The parser converts the INI-file options into a POVMS object using
72    the specifications provided in this table. The first element is the
73    INI-file keyword, the second element is the POVMS object attribute
74    key, the third is the attribute type.
75 */
76 struct ProcessOptions::INI_Parser_Table RenderOptions_INI_Table[] =
77 {
78 	{ "All_Console",		 kPOVAttrib_AllConsole,			kPOVMSType_Bool },
79 	{ "All_File",			 kPOVAttrib_AllFile,			kPOVObjectClass_File },
80 	{ "Antialias_Depth",	 kPOVAttrib_AntialiasDepth,		kPOVMSType_Int },
81 	{ "Antialias",			 kPOVAttrib_Antialias,			kPOVMSType_Bool },
82 	{ "Antialias_Threshold", kPOVAttrib_AntialiasThreshold,	kPOVMSType_Float },
83 
84 	{ "Bits_Per_Color",		 kPOVAttrib_BitsPerColor,		kPOVMSType_Int },
85 	{ "Bits_Per_Colour",	 kPOVAttrib_BitsPerColor,		kPOVMSType_Int },
86 	{ "Bounding",			 kPOVAttrib_Bounding,			kPOVMSType_Bool },
87 	{ "Bounding_Threshold",	 kPOVAttrib_BoundingThreshold,	kPOVMSType_Int },
88 	{ "Buffer_Output",		 '****',						kPOVMSType_Bool },
89 	{ "Buffer_Size",		 '****',						kPOVMSType_Int },
90 
91 	{ "Clock",				 kPOVAttrib_Clock,				kPOVMSType_Float },
92 //	{ "Compression",		 kPOVAttrib_Compression,		kPOVMSType_Int },
93 	{ "Continue_Trace",		 kPOVAttrib_ContinueTrace,		kPOVMSType_Bool },
94 	{ "Create_Histogram",	 kPOVAttrib_CreateHistogram,	kPOVMSType_Bool },
95 	{ "Create_Ini",			 kPOVAttrib_CreateIni,			kPOVObjectClass_File },
96 	{ "Cyclic_Animation",	 kPOVAttrib_CyclicAnimation,	kPOVMSType_Bool },
97 
98 	{ "Debug_Console",		 kPOVAttrib_DebugConsole,		kPOVMSType_Bool },
99 	{ "Debug_File",			 kPOVAttrib_DebugFile,			kPOVObjectClass_File },
100 	{ "Declare",			 kPOVAttrib_Declare,			kUseSpecialHandler },
101 	{ "Display",			 kPOVAttrib_Display,			kPOVMSType_Bool },
102 	{ "Display_Gamma",		 kPOVAttrib_DisplayGamma,		kPOVMSType_Float },
103 	{ "Draw_Vistas",		 kPOVAttrib_DrawVistas,			kPOVMSType_Bool },
104 
105 	{ "End_Column",			 kPOVAttrib_Right,				kPOVMSType_Float },
106 	{ "End_Row",			 kPOVAttrib_Bottom,				kPOVMSType_Float },
107 
108 	{ "Fatal_Console",		 kPOVAttrib_FatalConsole,		kPOVMSType_Bool },
109 	{ "Fatal_Error_Command", kPOVAttrib_FatalErrorCommand,	kUseSpecialHandler },
110 	{ "Fatal_Error_Return",	 kPOVAttrib_FatalErrorCommand,	kUseSpecialHandler },
111 	{ "Fatal_File",			 kPOVAttrib_FatalFile,			kPOVObjectClass_File },
112 	{ "Field_Render",		 kPOVAttrib_FieldRender,		kPOVMSType_Bool },
113 	{ "Final_Clock",		 kPOVAttrib_FinalClock,			kPOVMSType_Float },
114 	{ "Final_Frame",		 kPOVAttrib_FinalFrame,			kPOVMSType_Int },
115   #ifdef FRAME_STEP_PATCH
116 	{ "Frame_Step",			 kPOVAttrib_FrameStep,			kPOVMSType_Int },
117   #endif
118 	{ "Height",				 kPOVAttrib_Height,				kPOVMSType_Int },
119 	{ "Histogram_Name",		 kPOVAttrib_HistogramFile,		kPOVObjectClass_File },
120 	{ "Histogram_Grid_Size", kPOVAttrib_HistogramGridSizeX,	kUseSpecialHandler },
121 	{ "Histogram_Type",		 kPOVAttrib_HistogramFileType,	kUseSpecialHandler },
122 
123 	{ "Initial_Clock",		 kPOVAttrib_InitialClock,		kPOVMSType_Float },
124 	{ "Initial_Frame",		 kPOVAttrib_InitialFrame,		kPOVMSType_Int },
125 	{ "Input_File_Name",	 kPOVAttrib_InputFile,			kPOVObjectClass_File },
126 	{ "Include_Header",		 kPOVAttrib_IncludeHeader,		kPOVObjectClass_File },
127 	{ "Include_Ini",		 kPOVAttrib_IncludeIni,			kUseSpecialHandler },
128 
129 	{ "Jitter_Amount",		 kPOVAttrib_JitterAmount,		kPOVMSType_Float },
130 	{ "Jitter",				 kPOVAttrib_Jitter,				kPOVMSType_Bool },
131 
132 	{ "Library_Path",		 kPOVAttrib_LibraryPath,		kUseSpecialHandler },
133 	{ "Light_Buffer",		 kPOVAttrib_LightBuffer,		kPOVMSType_Bool },
134 
135 	{ "Odd_Field",			 kPOVAttrib_OddField,			kPOVMSType_Bool },
136 	{ "Output_Alpha",		 kPOVAttrib_OutputAlpha,		kPOVMSType_Bool },
137 	{ "Output_File_Name",	 kPOVAttrib_OutputFile,			kPOVObjectClass_File },
138 	{ "Output_File_Type",	 kPOVAttrib_OutputFileType,		kUseSpecialHandler },
139 	{ "Output_To_File",		 kPOVAttrib_OutputToFile,		kPOVMSType_Bool },
140 
141 	{ "Palette",			 kPOVAttrib_Palette,			kUseSpecialHandler },
142 	{ "Pause_When_Done",	 kPOVAttrib_PauseWhenDone,		kPOVMSType_Bool },
143 	{ "Post_Frame_Command",	 kPOVAttrib_PostFrameCommand,	kUseSpecialHandler },
144 	{ "Post_Frame_Return",	 kPOVAttrib_PostFrameCommand,	kUseSpecialHandler },
145 	{ "Post_Scene_Command",	 kPOVAttrib_PostSceneCommand,	kUseSpecialHandler },
146 	{ "Post_Scene_Return",	 kPOVAttrib_PostSceneCommand,	kUseSpecialHandler },
147 	{ "Preview_End_Size",	 kPOVAttrib_PreviewEndSize,		kPOVMSType_Int },
148 	{ "Preview_Start_Size",	 kPOVAttrib_PreviewStartSize,	kPOVMSType_Int },
149 	{ "Pre_Frame_Command",	 kPOVAttrib_PreFrameCommand,	kUseSpecialHandler },
150 	{ "Pre_Frame_Return",	 kPOVAttrib_PreFrameCommand,	kUseSpecialHandler },
151 	{ "Pre_Scene_command",	 kPOVAttrib_PreSceneCommand,	kUseSpecialHandler },
152 	{ "Pre_Scene_Return",	 kPOVAttrib_PreSceneCommand,	kUseSpecialHandler },
153 
154 	{ "Quality",			 kPOVAttrib_Quality,			kPOVMSType_Int },
155 
156 	{ "Radiosity",			 kPOVAttrib_Radiosity,			kPOVMSType_Bool },
157 	{ "Remove_Bounds",		 kPOVAttrib_RemoveBounds,		kPOVMSType_Bool },
158 	{ "Render_Console",		 kPOVAttrib_RenderConsole,		kPOVMSType_Bool },
159 	{ "Render_File",		 kPOVAttrib_RenderFile,			kPOVObjectClass_File },
160 
161 	{ "Sampling_Method",	 kPOVAttrib_SamplingMethod,		kPOVMSType_Int },
162 	{ "Split_Unions",		 kPOVAttrib_SplitUnions,		kPOVMSType_Bool },
163 	{ "Start_Column",		 kPOVAttrib_Left,				kPOVMSType_Float },
164 	{ "Start_Row",			 kPOVAttrib_Top,				kPOVMSType_Float },
165 	{ "Statistic_Console",	 kPOVAttrib_StatisticsConsole,	kPOVMSType_Bool },
166 	{ "Statistic_File",		 kPOVAttrib_StatisticsFile,		kPOVObjectClass_File },
167 	{ "Subset_End_Frame",	 kPOVAttrib_SubsetEndFrame,		kPOVMSType_Int },
168 	{ "Subset_Start_Frame",	 kPOVAttrib_SubsetStartFrame,	kPOVMSType_Int },
169 
170 	{ "Test_Abort_Count",	 kPOVAttrib_TestAbortCount,		kPOVMSType_Int },
171 	{ "Test_Abort",			 kPOVAttrib_TestAbort,			kPOVMSType_Bool },
172 
173 	{ "User_Abort_Command",	 kPOVAttrib_UserAbortCommand,	kUseSpecialHandler },
174 	{ "User_Abort_Return",	 kPOVAttrib_UserAbortCommand,	kUseSpecialHandler },
175 
176 	{ "Verbose",			 kPOVAttrib_Verbose,			kPOVMSType_Bool },
177 	{ "Version",			 kPOVAttrib_Version,			kPOVMSType_Float },
178 	{ "Video_Mode",			 kPOVAttrib_VideoMode,			kUseSpecialHandler },
179 	{ "Vista_Buffer",		 kPOVAttrib_VistaBuffer,		kPOVMSType_Bool },
180 
181 	{ "Warning_Console",	 kPOVAttrib_WarningConsole,		kPOVMSType_Bool },
182 	{ "Warning_File",		 kPOVAttrib_WarningFile,		kPOVObjectClass_File },
183 	{ "Warning_Level",		 kPOVAttrib_WarningLevel,		kPOVMSType_Int },
184 	{ "Width",				 kPOVAttrib_Width,				kPOVMSType_Int },
185 
186 	{ NULL, 0, 0 }
187 };
188 
189 /*
190    Keyword table for the command line parser.
191    The parser converts the command line options into a POVMS object using
192    the specifications provided in this table. The first element is the
193    command keyword, the second element is the POVMS object attribute key
194    of the parameter, the third is the attribute type and the last specifies
195    is the +/- switch is used as boolean parameter if an attribute key is
196    provided.
197 */
198 struct ProcessOptions::Cmd_Parser_Table RenderOptions_Cmd_Table[] =
199 {
200 	{ "A0",	 kPOVAttrib_AntialiasThreshold,	kPOVMSType_Float,		kPOVAttrib_Antialias },
201 	{ "AM",	 kPOVAttrib_SamplingMethod,		kPOVMSType_Int,			kNoParameter },
202 	{ "A",	 kNoParameter,					kNoParameter,			kPOVAttrib_Antialias },
203 
204 	{ "B",	 '****',						kPOVMSType_Int,			'****' },
205 	{ "B",	 kNoParameter,					kNoParameter,			'****' },
206 
207 	{ "C",	 kNoParameter,					kNoParameter,			kPOVAttrib_ContinueTrace },
208 
209 	{ "D",	 kPOVAttrib_Display,			kUseSpecialHandler,		kPOVAttrib_Display },
210 	{ "D",	 kNoParameter,					kNoParameter,			kPOVAttrib_Display },
211 
212 	{ "EC",	 kPOVAttrib_Right,				kPOVMSType_Float,		kNoParameter },
213 	{ "EF0", kPOVAttrib_SubsetEndFrame,		kPOVMSType_Float,		kNoParameter },
214 	{ "EF",	 kPOVAttrib_SubsetEndFrame,		kPOVMSType_Int,			kNoParameter },
215 	{ "EP",	 kPOVAttrib_PreviewEndSize,		kPOVMSType_Int,			kNoParameter },
216 	{ "ER",	 kPOVAttrib_Bottom,				kPOVMSType_Float,		kNoParameter },
217 
218 	{ "F",	 kPOVAttrib_OutputFileType,		kUseSpecialHandler,		kPOVAttrib_OutputToFile },
219 	{ "F",	 kNoParameter,					kNoParameter,			kPOVAttrib_OutputToFile },
220 
221 	{ "GA",	 kPOVAttrib_AllFile,			kPOVObjectClass_File,	kPOVAttrib_AllConsole },
222 	{ "GA",	 kNoParameter,					kNoParameter,			kPOVAttrib_AllConsole },
223 	{ "GD",	 kPOVAttrib_DebugFile,			kPOVObjectClass_File,	kPOVAttrib_DebugConsole },
224 	{ "GD",	 kNoParameter,					kNoParameter,			kPOVAttrib_DebugConsole },
225 	{ "GF",	 kPOVAttrib_FatalFile,			kPOVObjectClass_File,	kPOVAttrib_FatalConsole },
226 	{ "GF",	 kNoParameter,					kNoParameter,			kPOVAttrib_FatalConsole },
227 	{ "GI",	 kPOVAttrib_CreateIni,			kPOVObjectClass_File,	kNoParameter },
228 	{ "GR",	 kPOVAttrib_RenderFile,			kPOVObjectClass_File,	kPOVAttrib_RenderConsole },
229 	{ "GR",	 kNoParameter,					kNoParameter,			kPOVAttrib_RenderConsole },
230 	{ "GS",	 kPOVAttrib_StatisticsFile,		kPOVObjectClass_File,	kPOVAttrib_StatisticsConsole },
231 	{ "GS",	 kNoParameter,					kNoParameter,			kPOVAttrib_StatisticsConsole },
232 	{ "GW",	 kPOVAttrib_WarningFile,		kPOVObjectClass_File,	kPOVAttrib_WarningConsole },
233 	{ "GW",	 kNoParameter,					kNoParameter,			kPOVAttrib_WarningConsole },
234 
235 	{ "HI",	 kPOVAttrib_IncludeHeader,		kPOVObjectClass_File,	kNoParameter },
236 	{ "HN",	 kPOVAttrib_HistogramFile,		kPOVObjectClass_File,	kNoParameter },
237 	{ "HS",	 kPOVAttrib_HistogramGridSizeX,	kUseSpecialHandler,		kNoParameter },
238 	{ "HT",	 kPOVAttrib_HistogramFileType,	kUseSpecialHandler,		kPOVAttrib_CreateHistogram },
239 	{ "H",	 kPOVAttrib_Height,				kPOVMSType_Int,			kNoParameter },
240 
241 	{ "I",	 kPOVAttrib_InputFile,			kPOVObjectClass_File,	kNoParameter },
242 
243 	{ "J",	 kPOVAttrib_JitterAmount,		kPOVMSType_Float,		kPOVAttrib_Jitter },
244 	{ "J",	 kNoParameter,					kNoParameter,			kPOVAttrib_Jitter },
245 
246 	{ "KC",	 kNoParameter,					kNoParameter,			kPOVAttrib_CyclicAnimation },
247 	{ "KI",	 kPOVAttrib_InitialClock,		kPOVMSType_Float,		kNoParameter },
248 	{ "KFF", kPOVAttrib_FinalFrame,			kPOVMSType_Int,			kNoParameter },
249 	{ "KFI", kPOVAttrib_InitialFrame,		kPOVMSType_Int,			kNoParameter },
250 	{ "KF",	 kPOVAttrib_FinalClock,			kPOVMSType_Float,		kNoParameter },
251 	{ "K",	 kPOVAttrib_Clock,				kPOVMSType_Float,		kNoParameter },
252 
253 	{ "L",	 kPOVAttrib_LibraryPath,		kUseSpecialHandler,		kNoParameter },
254 
255 	{ "MB",	 kPOVAttrib_BoundingThreshold,	kPOVMSType_Int,			kPOVAttrib_Bounding },
256 	{ "MB",	 kNoParameter,					kNoParameter,			kPOVAttrib_Bounding },
257 	{ "MV",	 kPOVAttrib_Version,			kPOVMSType_Float,		kNoParameter },
258 
259 	{ "O",	 kPOVAttrib_OutputFile,			kPOVObjectClass_File,	kNoParameter },
260 
261 	{ "P",	 kNoParameter,					kNoParameter,			kPOVAttrib_PauseWhenDone },
262 
263 	{ "QR",	 kNoParameter,					kNoParameter,			kPOVAttrib_Radiosity },
264 	{ "Q",	 kPOVAttrib_Quality,			kPOVMSType_Int,			kNoParameter },
265 
266 	{ "R",	 kPOVAttrib_AntialiasDepth,		kPOVMSType_Int,			kNoParameter },
267 
268 	{ "SC",	 kPOVAttrib_Left,				kPOVMSType_Float,		kNoParameter },
269 	{ "SF0", kPOVAttrib_SubsetStartFrame,	kPOVMSType_Float,		kNoParameter },
270 	{ "SF",	 kPOVAttrib_SubsetStartFrame,	kPOVMSType_Int,			kNoParameter },
271 	{ "SP",	 kPOVAttrib_PreviewStartSize,	kPOVMSType_Int,			kNoParameter },
272 	{ "SR",	 kPOVAttrib_Top,				kPOVMSType_Float,		kNoParameter },
273 	{ "SU",	 kNoParameter,					kNoParameter,			kPOVAttrib_SplitUnions },
274   #ifdef FRAME_STEP_PATCH
275 	{ "STP", kPOVAttrib_FrameStep,			kPOVMSType_Int,			kNoParameter },
276   #endif
277 	{ "UA",	 kNoParameter,					kNoParameter,			kPOVAttrib_OutputAlpha },
278 	{ "UD",	 kNoParameter,					kNoParameter,			kPOVAttrib_DrawVistas },
279 	{ "UF",	 kNoParameter,					kNoParameter,			kPOVAttrib_FieldRender },
280 	{ "UL",	 kNoParameter,					kNoParameter,			kPOVAttrib_LightBuffer },
281 	{ "UO",	 kNoParameter,					kNoParameter,			kPOVAttrib_OddField },
282 	{ "UR",	 kNoParameter,					kNoParameter,			kPOVAttrib_RemoveBounds },
283 	{ "UV",	 kNoParameter,					kNoParameter,			kPOVAttrib_VistaBuffer },
284 
285 	{ "V",	 kNoParameter,					kNoParameter,			kPOVAttrib_Verbose },
286 
287 	{ "WL",	 kPOVAttrib_WarningLevel,		kPOVMSType_Int,			kNoParameter },
288 	{ "W",	 kPOVAttrib_Width,				kPOVMSType_Int,			kNoParameter },
289 
290 	{ "X",	 kPOVAttrib_TestAbortCount,		kUseSpecialHandler,		kPOVAttrib_TestAbort },
291 	{ "X",	 kNoParameter,					kNoParameter,			kPOVAttrib_TestAbort },
292 
293 	{ NULL, 0, 0, 0 }
294 };
295 
ProcessRenderOptions()296 ProcessRenderOptions::ProcessRenderOptions() : ProcessOptions(RenderOptions_INI_Table, RenderOptions_Cmd_Table)
297 {
298 }
299 
~ProcessRenderOptions()300 ProcessRenderOptions::~ProcessRenderOptions()
301 {
302 }
303 
ReadSpecialOptionHandler(INI_Parser_Table * option,char * param,POVMSObjectPtr obj)304 int ProcessRenderOptions::ReadSpecialOptionHandler(INI_Parser_Table *option, char *param, POVMSObjectPtr obj)
305 {
306 	POVMSAttributeList list;
307 	double floatval = 0.0;
308 	int intval = 0;
309 	int intval2 = 0;
310 	int err = kNoErr;
311 
312 	switch(option->key)
313 	{
314 		case kPOVAttrib_HistogramGridSizeX:
315 			if(sscanf(param, "%d.%d", &intval, &intval2) == 2)
316 			{
317 				err = POVMSUtil_SetInt(obj, kPOVAttrib_HistogramGridSizeX, intval);
318 				if(err == kNoErr)
319 					err = POVMSUtil_SetInt(obj, kPOVAttrib_HistogramGridSizeY, intval2);
320 			}
321 			else
322 			{
323 				ParseError("Invalid histogram grid size '%s'.", param);
324 				err = kParseErr;
325 			}
326 			break;
327 		case kPOVAttrib_Palette:
328 		case kPOVAttrib_VideoMode:
329 			while(isspace(*param))
330 				param++;
331 			err = POVMSUtil_SetInt(obj, option->key, tolower(*param));
332 			break;
333 		case kPOVAttrib_HistogramFileType:
334 		case kPOVAttrib_OutputFileType:
335 			while(isspace(*param))
336 				param++;
337 			if(strchr(Output_File_Types, *param) == NULL)
338 				ParseError("Unrecognized output file format %c.", *param);
339 			err = POVMSUtil_SetInt(obj, option->key, tolower(*param));
340 			break;
341 		case kPOVAttrib_IncludeIni:
342 		case kPOVAttrib_LibraryPath:
343 			POVMSAttribute attr;
344 
345 			if(err == kNoErr)
346 			{
347 				// parse INI file (recursive)
348 				if(option->key == kPOVAttrib_IncludeIni)
349 					err = ParseFile(param, obj);
350 
351 				// create list if it isn't there
352 				if(err == kNoErr)
353 				{
354 					if(POVMSObject_Exist(obj, option->key) == kFalseErr)
355 						err = POVMSAttrList_New(&list);
356 					else if(POVMSObject_Exist(obj, option->key) != kNoErr)
357 						err = kObjectAccessErr;
358 					else
359 						err = POVMSObject_Get(obj, &list, option->key);
360 				}
361 			}
362 			else
363 			{
364 				ParseError("File name or path parameter expected for option '%s', found '%s'.", option->keyword, param);
365 				err = kParseErr;
366 			}
367 
368 			// add path or file to list
369 			if(err == kNoErr)
370 				err = POVMSAttr_New(&attr);
371 			if(err == kNoErr)
372 			{
373 				err = POVMSAttr_Set(&attr, kPOVMSType_CString, (void *)param, strlen(param) + 1);
374 				if(err == kNoErr)
375 					err = POVMSAttrList_Append(&list, &attr);
376 				else
377 					err = POVMSAttr_Delete(&attr);
378 			}
379 			if(err == kNoErr)
380 				err = POVMSObject_Set(obj, &list, option->key);
381 			break;
382 		case kPOVAttrib_Declare:
383 			POVMSObject decobj;
384 
385 			// create list if it isn't there
386 			if(POVMSObject_Exist(obj, option->key) == kFalseErr)
387 				err = POVMSAttrList_New(&list);
388 			else if(POVMSObject_Exist(obj, option->key) != kNoErr)
389 				err = kObjectAccessErr;
390 			else
391 				err = POVMSObject_Get(obj, &list, option->key);
392 
393 			// add value to list
394 			if(err == kNoErr)
395 				err = POVMSObject_New(&decobj, kPOVMSType_WildCard);
396 			if(err == kNoErr)
397 			{
398 				char *ptr = NULL;
399 
400 				err = POVMSUtil_SetString(&decobj, kPOVAttrib_Identifier, strtok(param, "="));
401 				if(err == kNoErr)
402 				{
403 					ptr = strtok(NULL, "");
404 					if(ptr == NULL)
405 						err = kParseErr;
406 				}
407 				if(err == kNoErr)
408 				{
409 					if(strchr(ptr, '"') != NULL)
410 					{
411 						ptr = strchr(ptr, '"') + 1;
412 						strtok(ptr, "\"");
413 						err = POVMSUtil_SetString(&decobj, kPOVAttrib_Value, ptr);
414 					}
415 					else
416 						err = POVMSUtil_SetFloat(&decobj, kPOVAttrib_Value, atof(ptr));
417 				}
418 				if(err == kNoErr)
419 					err = POVMSAttrList_Append(&list, &decobj);
420 				else
421 					err = POVMSObject_Delete(&decobj);
422 			}
423 			if(err == kNoErr)
424 				err = POVMSObject_Set(obj, &list, option->key);
425 			break;
426 		case kPOVAttrib_FatalErrorCommand:
427 		case kPOVAttrib_PostFrameCommand:
428 		case kPOVAttrib_PostSceneCommand:
429 		case kPOVAttrib_PreFrameCommand:
430 		case kPOVAttrib_PreSceneCommand:
431 		case kPOVAttrib_UserAbortCommand:
432 			POVMSObject cmdobj;
433 
434 			if(POVMSObject_Exist(obj, option->key) == kNoErr)
435 				err = POVMSObject_Get(obj, &cmdobj, option->key);
436 			else
437 				err = POVMSObject_New(&cmdobj, kPOVMSType_WildCard);
438 			if(toupper(*(option->keyword + strlen(option->keyword) - 1)) == 'D')
439 			{
440 				if(err == kNoErr)
441 					err = POVMSUtil_SetString(&cmdobj, kPOVAttrib_CommandString, param);
442 			}
443 			else
444 			{
445 				if(err == kNoErr)
446 				{
447 					int i = 0;
448 
449 					if((*param == '-') || (*param == '!'))
450 						i = tolower(*(param + 1));
451 					else
452 						i = tolower(*param);
453 					err = POVMSUtil_SetInt(&cmdobj, kPOVAttrib_ReturnAction, i);
454 				}
455 			}
456 			if(err == kNoErr)
457 				err = POVMSObject_Set(obj, &cmdobj, option->key);
458 			break;
459 	}
460 
461 	return err;
462 }
463 
ReadSpecialSwitchHandler(Cmd_Parser_Table * option,char * param,POVMSObjectPtr obj,bool)464 int ProcessRenderOptions::ReadSpecialSwitchHandler(Cmd_Parser_Table *option, char *param, POVMSObjectPtr obj, bool)
465 {
466 	int intval = 0;
467 	int intval2 = 0;
468 	int err = 0;
469 	char chr = 0;
470 
471 	switch(option->key)
472 	{
473 		case kPOVAttrib_Display:
474 			if(param[0] != '\0')
475 			{
476 				err = POVMSUtil_SetInt(obj, kPOVAttrib_VideoMode, (int)toupper(param[0]));
477 				if((param[1] != '\0') && (err == 0))
478 					err = POVMSUtil_SetInt(obj, kPOVAttrib_Palette, (int)toupper(param[1]));
479 			}
480 			break;
481 		case kPOVAttrib_HistogramGridSizeX:
482 			if(sscanf(param, "%d.%d", &intval, &intval2) == 2)
483 			{
484 				err = POVMSUtil_SetInt(obj, kPOVAttrib_HistogramGridSizeX, intval);
485 				if(err == kNoErr)
486 					err = POVMSUtil_SetInt(obj, kPOVAttrib_HistogramGridSizeY, intval2);
487 			}
488 			else
489 			{
490 				ParseError("Invalid histogram grid size '%s'.", param);
491 				err = kParseErr;
492 			}
493 			break;
494 		case kPOVAttrib_OutputFileType:
495 			if(strchr(Output_File_Types, *param) == NULL)
496 				ParseError("Unrecognized output file format %c.", *param);
497 			err = POVMSUtil_SetInt(obj, option->key, tolower(*param));
498 			param++;
499 			if((err == kNoErr) && (*param > ' '))
500 			{
501 				if(isdigit(*param) != 0)
502 				{
503 					if(sscanf(param, "%d", &intval) == 1)
504 						err = POVMSUtil_SetInt(obj, kPOVAttrib_BitsPerColor, intval);
505 					else
506 					{
507 						ParseError("Invalid bits per color '%s'.", param);
508 						err = kParseErr;
509 					}
510 				}
511 				else
512 				{
513 					ParseError("Missing bits per color, '%s' found instead.", param);
514 					err = kParseErr;
515 				}
516 			}
517 			break;
518 		case kPOVAttrib_HistogramFileType:
519 			if(strchr(Output_File_Types, *param) == NULL)
520 			{
521 				ParseError("Unrecognized output file format %c.", *param);
522 				err = kParseErr;
523 			}
524 			else
525 			{
526 				chr = tolower(*param);
527 				err = POVMSUtil_SetInt(obj, option->key, chr);
528 			}
529 			break;
530 		case kPOVAttrib_LibraryPath:
531 			POVMSAttributeList list;
532 			POVMSAttribute attr;
533 
534 			if(err == kNoErr)
535 			{
536 				// create list if it isn't there
537 				if(POVMSObject_Exist(obj, option->key) == kFalseErr)
538 					err = POVMSAttrList_New(&list);
539 				else if(POVMSObject_Exist(obj, option->key) != kNoErr)
540 					err = kObjectAccessErr;
541 				else
542 					err = POVMSObject_Get(obj, &list, option->key);
543 			}
544 			else
545 			{
546 				ParseError("File name or path parameter expected for switch '%s', found '%s'.", option->command, param);
547 				err = kParseErr;
548 			}
549 
550 			// add path or file to list
551 			if(err == kNoErr)
552 				err = POVMSAttr_New(&attr);
553 			if(err == kNoErr)
554 			{
555 				err = POVMSAttr_Set(&attr, kPOVMSType_CString, (void *)param, strlen(param) + 1);
556 				if(err == kNoErr)
557 					err = POVMSAttrList_Append(&list, &attr);
558 				else
559 					err = POVMSAttr_Delete(&attr);
560 			}
561 			if(err == kNoErr)
562 				err = POVMSObject_Set(obj, &list, option->key);
563 			break;
564 		case kPOVAttrib_TestAbortCount:
565 			if((*param) == 0)
566 				break;
567 			if(sscanf(param, "%d", &intval) == 1)
568 				err = POVMSUtil_SetInt(obj, option->key, intval);
569 			else
570 			{
571 				ParseError("No or integer parameter expected for switch '%s', found '%s'.", option->command, param);
572 				err = kParseErr;
573 			}
574 			break;
575 	}
576 
577 	return err;
578 }
579 
WriteSpecialOptionHandler(INI_Parser_Table * option,POVMSObjectPtr obj,OTextStream * file)580 int ProcessRenderOptions::WriteSpecialOptionHandler(INI_Parser_Table *option, POVMSObjectPtr obj, OTextStream *file)
581 {
582 	POVMSAttributeList list;
583 	POVMSFloat floatval;
584 	POVMSInt intval,intval2;
585 	int err = 0;
586 	int l;
587 	int i,imax;
588 	POVMSAttribute item;
589 	char *bufptr;
590 	char chr;
591 
592 	switch(option->key)
593 	{
594 		case kPOVAttrib_HistogramGridSizeX:
595 			if(POVMSUtil_GetInt(obj, kPOVAttrib_HistogramGridSizeX, &intval) == 0)
596 			{
597 				if(POVMSUtil_GetInt(obj, kPOVAttrib_HistogramGridSizeY, &intval2) == 0)
598 					file->printf("%s=%d.%d\n", option->keyword, intval, intval2);
599 			}
600 			break;
601 		case kPOVAttrib_Palette:
602 		case kPOVAttrib_VideoMode:
603 		case kPOVAttrib_OutputFileType:
604 		case kPOVAttrib_HistogramFileType:
605 			if(POVMSUtil_GetInt(obj, option->key, &intval) == 0)
606 			{
607 				chr = intval;
608 				if(chr > 32)
609 					file->printf("%s=%c\n", option->keyword, chr);
610 			}
611 			break;
612 		case kPOVAttrib_IncludeIni:
613 			break;
614 		case kPOVAttrib_Declare:
615 			POVMSObject decobj;
616 
617 			err = POVMSObject_Get(obj, &list, option->key);
618 			if(err != 0)
619 				break;
620 
621 			l = 0;
622 			err = POVMSAttrList_Count(&list, &l);
623 			if(err != 0)
624 				break;
625 			if(l == 0)
626 				break;
627 
628 			imax = l;
629 			for(i = 1; i <= imax; i++)
630 			{
631 				err = POVMSAttrList_GetNth(&list, i, &decobj);
632 				if(err == 0)
633 					err = POVMSObject_Get(&decobj, &item, kPOVAttrib_Identifier);
634 				if(err == 0)
635 				{
636 					l = 0;
637 					err = POVMSAttr_Size(&item, &l);
638 					if(l > 0)
639 					{
640 						bufptr = new char[l];
641 						bufptr[0] = 0;
642 						if((POVMSUtil_GetFloat(&decobj, kPOVAttrib_Value, &floatval) == 0) &&
643 						   (POVMSAttr_Get(&item, kPOVMSType_CString, bufptr, &l) == 0))
644 							file->printf("%s=%s=%g\n", option->keyword, bufptr, (float)floatval);
645 						delete[] bufptr;
646 					}
647 					(void)POVMSAttr_Delete(&item);
648 				}
649 			}
650 			break;
651 		case kPOVAttrib_LibraryPath:
652 			err = POVMSObject_Get(obj, &list, option->key);
653 			if(err != 0)
654 				break;
655 
656 			l = 0;
657 			err = POVMSAttrList_Count(&list, &l);
658 			if(err != 0)
659 				break;
660 			if(l == 0)
661 				break;
662 
663 			imax = l;
664 			for(i = 1; i <= imax; i++)
665 			{
666 				err = POVMSAttrList_GetNth(&list, i, &item);
667 				if(err == 0)
668 				{
669 					l = 0;
670 					err = POVMSAttr_Size(&item, &l);
671 					if(l > 0)
672 					{
673 						bufptr = new char[l];
674 						bufptr[0] = 0;
675 						if(POVMSAttr_Get(&item, kPOVMSType_CString, bufptr, &l) == 0)
676 							file->printf("%s=\"%s\"\n", option->keyword, bufptr);
677 						delete[] bufptr;
678 					}
679 					(void)POVMSAttr_Delete(&item);
680 				}
681 			}
682 			break;
683 		case kPOVAttrib_FatalErrorCommand:
684 		case kPOVAttrib_PostFrameCommand:
685 		case kPOVAttrib_PostSceneCommand:
686 		case kPOVAttrib_PreFrameCommand:
687 		case kPOVAttrib_PreSceneCommand:
688 		case kPOVAttrib_UserAbortCommand:
689 			POVMSObject cmdobj;
690 
691 			err = POVMSObject_Get(obj, &cmdobj, option->key);
692 			if(err != 0)
693 				break;
694 
695 			err = POVMSObject_Get(&cmdobj, &item, kPOVAttrib_CommandString);
696 			if(err == 0)
697 			{
698 				if(toupper(*(option->keyword + strlen(option->keyword) - 1)) == 'D')
699 				{
700 					l = 0;
701 					err = POVMSAttr_Size(&item, &l);
702 					if(l > 0)
703 					{
704 						bufptr = new char[l];
705 						bufptr[0] = 0;
706 						if(POVMSAttr_Get(&item, kPOVMSType_CString, bufptr, &l) == 0)
707 							file->printf("%s=%s\n", option->keyword, bufptr);
708 						delete[] bufptr;
709 					}
710 				}
711 				else
712 				{
713 					if(POVMSUtil_GetInt(&cmdobj, kPOVAttrib_ReturnAction, &intval) == 0)
714 					{
715 						if(intval < 0)
716 						{
717 							chr = -intval;
718 							file->printf("%s=!%c\n", option->keyword, chr);
719 						}
720 						else
721 						{
722 							chr = intval;
723 							file->printf("%s=%c\n", option->keyword, chr);
724 						}
725 					}
726 				}
727 			}
728 			if(err == 0)
729 				err = POVMSObject_Delete(&cmdobj);
730 			break;
731 	}
732 
733 	return err;
734 }
735 
WriteOptionFilter(INI_Parser_Table * table)736 bool ProcessRenderOptions::WriteOptionFilter(INI_Parser_Table *table)
737 {
738 	// So that we don't get both Bits_Per_Color and Bits_Per_Colour in the INI file.
739 	return (strcmp(table->keyword, "Bits_Per_Colour") != 0);
740 }
741 
ProcessUnknownString(char * str,POVMSObjectPtr obj)742 int ProcessRenderOptions::ProcessUnknownString(char *str, POVMSObjectPtr obj)
743 {
744 	POVMSAttributeList list;
745 	POVMSAttribute attr;
746 	int state = 0; // INI file
747 	int err = kNoErr;
748 
749 	if(str == NULL)
750 	{
751 		ParseError("Expected filename, nothing was found.");
752 		return kParseErr;
753 	}
754 
755 	// add filename or path
756 
757 	// see if it is a POV file
758 	if(state == 0)
759 	{
760 		char *ptr = strrchr(str, '.');
761 		if(ptr != NULL)
762 		{
763 			if(pov_stricmp(ptr, ".pov") == 0)
764 				state = 1; // POV file
765 		}
766 	}
767 
768 	// see if it is a path
769 	if(state == 0)
770 	{
771 		if(strlen(str) > 0)
772 		{
773 			if(str[strlen(str) - 1] == FILENAME_SEPARATOR)
774 				state = 2; // library path
775 		}
776 	}
777 
778 	switch(state)
779 	{
780 		// INI file
781 		case 0:
782 			// parse INI file (recursive)
783 			err = ParseFile(str, obj);
784 			if(err == kNoErr)
785 			{
786 				// create list if it isn't there
787 				if(POVMSObject_Exist(obj, kPOVAttrib_IncludeIni) == kFalseErr)
788 					err = POVMSAttrList_New(&list);
789 				else if(POVMSObject_Exist(obj, kPOVAttrib_IncludeIni) != kNoErr)
790 					err = kObjectAccessErr;
791 				else
792 					err = POVMSObject_Get(obj, &list, kPOVAttrib_IncludeIni);
793 			}
794 
795 			// add INI file to list
796 			if(err == kNoErr)
797 				err = POVMSAttr_New(&attr);
798 			if(err == kNoErr)
799 			{
800 				err = POVMSAttr_Set(&attr, kPOVMSType_CString, str, strlen(str) + 1);
801 				if(err == kNoErr)
802 					err = POVMSAttrList_Append(&list, &attr);
803 				else
804 					err = POVMSAttr_Delete(&attr);
805 			}
806 			if(err == kNoErr)
807 				err = POVMSObject_Set(obj, &list, kPOVAttrib_IncludeIni);
808 			break;
809 		// POV file
810 		case 1:
811 			// set POV file
812 			err = POVMSUtil_SetString(obj, kPOVAttrib_InputFile, str);
813 			break;
814 		// library path
815 		case 2:
816 			// create list if it isn't there
817 			if(POVMSObject_Exist(obj, kPOVAttrib_LibraryPath) == kFalseErr)
818 				err = POVMSAttrList_New(&list);
819 			else if(POVMSObject_Exist(obj, kPOVAttrib_LibraryPath) != kNoErr)
820 				err = kObjectAccessErr;
821 			else
822 				err = POVMSObject_Get(obj, &list, kPOVAttrib_LibraryPath);
823 
824 			// add librarypath to list
825 			if(err == kNoErr)
826 				err = POVMSAttr_New(&attr);
827 			if(err == kNoErr)
828 			{
829 				err = POVMSAttr_Set(&attr, kPOVMSType_CString, str, strlen(str) + 1);
830 				if(err == kNoErr)
831 					err = POVMSAttrList_Append(&list, &attr);
832 				else
833 					err = POVMSAttr_Delete(&attr);
834 			}
835 			if(err == kNoErr)
836 				err = POVMSObject_Set(obj, &list, kPOVAttrib_LibraryPath);
837 			break;
838 	}
839 
840 	return err;
841 }
842 
OpenFileForRead(const char * filename,POVMSObjectPtr obj)843 ITextStream *ProcessRenderOptions::OpenFileForRead(const char *filename, POVMSObjectPtr obj)
844 {
845 	char buffer[FILE_NAME_LENGTH];
846 
847 	return OpenINIFileStream(filename, POV_BASE_NAMESPACE::POV_File_Text_INI, buffer, obj);
848 }
849 
OpenFileForWrite(const char * filename,POVMSObjectPtr)850 OTextStream *ProcessRenderOptions::OpenFileForWrite(const char *filename, POVMSObjectPtr)
851 {
852 	return new OTextStream(filename, POV_BASE_NAMESPACE::POV_File_Text_INI);
853 }
854 
OpenINIFileStream(const char * filename,unsigned int stype,char * buffer,POVMSObjectPtr obj)855 ITextStream *ProcessRenderOptions::OpenINIFileStream(const char *filename, unsigned int stype, char *buffer, POVMSObjectPtr obj)
856 {
857 	int i,ii,l[4];
858 	char pathname[FILE_NAME_LENGTH];
859 	char file[FILE_NAME_LENGTH];
860 	char file_x[4][FILE_NAME_LENGTH];
861 	int cnt = 0;
862 	int ll;
863 	POVMSAttribute attr, item;
864 
865 	if(Has_Extension(filename))
866 	{
867 		for(i = 0; i < 4; i++)
868 			l[i]=0;
869 	}
870 	else
871 	{
872 		for(i = 0; i < 4; i++)
873 		{
874 			if((l[i] = strlen(gPOV_File_Extensions[stype].ext[i])) > 0)
875 			{
876 				strcpy(file_x[i], filename);
877 				strcat(file_x[i], gPOV_File_Extensions[stype].ext[i]);
878 			}
879 		}
880 	}
881 
882 	// Check the current directory first
883 	for(i = 0; i < 4; i++)
884 	{
885 		if(l[i])
886 		{
887 			if(EXIST_FILE(file_x[i]) == true)
888 			{
889 				strcpy(buffer,file_x[i]);
890 				return new ITextStream(file_x[i], stype);
891 			}
892 		}
893 	}
894 	if(EXIST_FILE(filename) == true)
895 	{
896 		strcpy(buffer,filename);
897 		return new ITextStream(filename, stype);
898 	}
899 
900 	if(POVMSObject_Get(obj, &attr, kPOVAttrib_LibraryPath) != 0)
901 		return NULL;
902 
903 	if(POVMSAttrList_Count(&attr, &cnt) != 0)
904 	{
905 		(void)POVMSAttrList_Delete(&attr);
906 		return NULL;
907 	}
908 
909 	for (i = 1; i <= cnt; i++)
910 	{
911 		(void)POVMSAttr_New(&item);
912 		if(POVMSAttrList_GetNth(&attr, i, &item) != 0)
913 			continue;
914 		ll = 0;
915 		if(POVMSAttr_Size(&item, &ll) != 0)
916 		{
917 			(void)POVMSAttr_Delete(&item);
918 			continue;
919 		}
920 		if(ll <= 0)
921 		{
922 			(void)POVMSAttr_Delete(&item);
923 			continue;
924 		}
925 		if(POVMSAttr_Get(&item, kPOVMSType_CString, file, &ll) != 0)
926 		{
927 			(void)POVMSAttr_Delete(&item);
928 			continue;
929 		}
930 		(void)POVMSAttr_Delete(&item);
931 
932 		file[strlen(file)+1] = '\0';
933 		if(file[strlen(file) - 1] != DRIVE_SEPARATOR)
934 			file[strlen(file)] = FILENAME_SEPARATOR;
935 
936 		for(ii = 0; ii < 4; ii++)
937 		{
938 			if(l[ii])
939 			{
940 				strcpy(pathname, file);
941 				strcat(pathname, file_x[ii]);
942 				if(EXIST_FILE(pathname) == true)
943 				{
944 					strcpy(buffer,pathname);
945 					(void)POVMSAttrList_Delete(&attr);
946 					return new ITextStream(pathname, stype);
947 				}
948 			}
949 		}
950 		strcpy(pathname, file);
951 		strcat(pathname, filename);
952 		if(EXIST_FILE(pathname) == true)
953 		{
954 			strcpy(buffer,pathname);
955 			(void)POVMSAttrList_Delete(&attr);
956 			return new ITextStream(pathname, stype);
957 		}
958 	}
959 
960 	(void)POVMSAttrList_Delete(&attr);
961 
962 	if(l[0])
963 		ParseError("Could not find file '%s%s'", filename, gPOV_File_Extensions[stype].ext[0]);
964 	else
965 		ParseError("Could not find file '%s'", filename);
966 
967 	return NULL;
968 }
969 
970 END_POV_FRONTEND_NAMESPACE
971